Làm cách nào để Mã hóa địa lý 20 địa chỉ mà không nhận được phản hồi OVER_QUERY_LIMIT?


87

Sử dụng Google Geocoder v3, nếu tôi cố gắng mã hóa địa lý 20 địa chỉ, tôi sẽ nhận được OVER_QUERY_LIMIT trừ khi tôi đặt chúng cách nhau ~ 1 giây, nhưng phải mất 20 giây trước khi các điểm đánh dấu của tôi được đặt hết.

Có cách nào khác để làm điều đó, ngoài việc lưu trữ các tọa độ trước?


đây vẫn là trường hợp? Hạn chế duy nhất mà tôi thấy trong tài liệu là: "giới hạn truy vấn là 2.500 yêu cầu định vị địa lý mỗi ngày". code.google.com/apis/maps/documentation/geocoding/…
russau

6
Nó không phải là về tổng số lượng truy vấn trên mỗi người dùng mỗi ngày, mà là về số lượng truy vấn trong một khoảng thời gian ngắn, giống như khi truy vấn trong một vòng lặp.
Michiel van Oosterhout

Chúng tôi có giấy phép kinh doanh tại cửa hàng của mình và chúng tôi vẫn gặp phải vấn đề không thể xử lý hơn 10 yêu cầu mỗi giây. Sự khác biệt duy nhất giữa giấy phép kinh doanh và nhà phát triển thông thường là chúng tôi có giới hạn 100.000 cuộc gọi mỗi ngày.
abhi

@michielvoo Bạn đã giải quyết được điều này chưa? Nếu có, sau đó vui lòng giúp đỡ tôi. Tôi nhận được OVER_QUERY_LIMIT. Câu hỏi của tôi trong SO. Fiddle
Prabs

Câu trả lời:


85

Không, thực sự không có cách nào khác: nếu bạn có nhiều vị trí và muốn hiển thị chúng trên bản đồ, giải pháp tốt nhất là:

  • tìm nạp vĩ độ + kinh độ, sử dụng bộ mã hóa địa lý, khi một vị trí được tạo
  • lưu trữ chúng trong cơ sở dữ liệu của bạn, cùng với địa chỉ
  • và sử dụng vĩ độ + kinh độ được lưu trữ đó khi bạn muốn hiển thị bản đồ.

Tất nhiên, điều này là do bạn tạo / sửa đổi địa điểm ít hơn nhiều so với việc bạn tham khảo ý kiến ​​về địa điểm.


Có, điều đó có nghĩa là bạn sẽ phải làm nhiều việc hơn một chút khi lưu các vị trí - nhưng nó cũng có nghĩa là:

  • Bạn sẽ có thể tìm kiếm theo tọa độ địa lý
    • tức là " Tôi muốn có một danh sách các điểm gần nơi tôi đang ở "
  • Hiển thị bản đồ sẽ nhanh hơn rất nhiều
    • Ngay cả với hơn 20 địa điểm trên đó
  • Ồ, và, cũng (cuối cùng nhưng không kém phần quan trọng) : điều này sẽ hoạt động ;-)
    • Bạn sẽ ít có khả năng đạt đến giới hạn cuộc gọi bộ mã địa lý X trong N giây.
    • Và bạn sẽ ít có khả năng đạt đến giới hạn số cuộc gọi bộ mã hóa địa lý Y mỗi ngày.

Tôi tò mò làm thế nào bạn có thể chắc chắn rằng kết quả là chính xác sau một thời gian trôi qua (giả sử một tháng). Bạn có thỉnh thoảng truy vấn lại chúng không?
Chris

2
Nếu địa chỉ (mà bạn đã có trong DB của mình - nếu không thì bạn sẽ không thể mã hóa địa lý) không thay đổi, rất có thể vĩ độ / kinh độ sẽ thay đổi. Và tất nhiên, mỗi khi địa chỉ được sửa đổi, bạn nên truy vấn lại bộ mã hóa địa lý, để lấy vĩ độ + kinh độ tương ứng với địa chỉ mới.
Pascal MARTIN

Tôi đã lưu trữ vĩ độ / dài vào DB và truy xuất nó từ DB qua AJAX dưới dạng một mảng, nhưng sau đó nó sẽ được chuyển lại vào vòng lặp tập lệnh java, hơn nữa tôi đã nhận được 173 vị trí từ DB. Bây giờ nó hiển thị cho tôi cùng một trạng thái OVER_QUERY_LIMIT. Xin cho lời khuyên ...
Prabhu M

20

Bạn thực sự không phải đợi một giây đầy đủ cho mỗi yêu cầu. Tôi nhận thấy rằng nếu tôi đợi 200 mili giây giữa mỗi yêu cầu, tôi có thể tránh được phản hồi OVER_QUERY_LIMIT và trải nghiệm người dùng có thể vượt qua. Với giải pháp này, bạn có thể tải 20 mục trong 4 giây.

$(items).each(function(i, item){

  setTimeout(function(){

    geoLocate("my address", function(myLatlng){
      ...
    });

  }, 200 * i);

}

5
nhưng (200 * i) có nghĩa là thời gian tạm dừng giữa mỗi yêu cầu đang tăng lên. Vì vậy, ở yêu cầu thứ 3, đó là 600, sau đó là 800, v.v.
Roman

chỉ cần loại bỏ '* i'
Chris

9
setTimeout sẽ thực thi nó một lần. Vì vậy, nếu tôi đúng, (..., 200 * i) sẽ lên lịch cho mỗi cuộc gọi cách nhau 200ms (như oyatek đã nhận xét), đó là điều mà gabeodess muốn đạt được. Dòng điện (..., 200) sẽ thực hiện tất cả chúng cùng một lúc sau 200ms. Hay tôi đang thiếu cái gì đó?
lepe

@gabeodess - bạn nên thực hiện setIntervaltheo số lượng yêu cầu cần thiết, thay vì setTimeoutvà đặt nó thành 100- đề phòng trường hợp số lượng địa chỉ đôi khi trong tương lai sẽ mở rộng 20số lượng.
Rob Scott

3
@gabeodess Tôi đã thử giải pháp của bạn nhưng vẫn nhận được OVER_QUERY_LIMIT Fiddle
Prabs

6

Rất tiếc, đây là một hạn chế của dịch vụ bản đồ Google.

Tôi hiện đang làm việc trên một ứng dụng sử dụng tính năng mã hóa địa lý và tôi đang lưu từng địa chỉ duy nhất trên cơ sở mỗi người dùng. Tôi tạo thông tin địa chỉ (thành phố, đường phố, tiểu bang, v.v.) dựa trên thông tin do Google maps trả về, và sau đó cũng lưu thông tin vĩ độ / kinh độ trong cơ sở dữ liệu. Điều này ngăn bạn phải viết mã lại mọi thứ và cung cấp cho bạn các địa chỉ được định dạng độc đáo.

Một lý do khác mà bạn muốn làm điều này là vì có giới hạn hàng ngày về số lượng địa chỉ có thể được mã hóa địa lý từ một địa chỉ IP cụ thể. Bạn không muốn ứng dụng của mình thất bại với một người vì lý do đó.


2

Tôi đang gặp phải vấn đề tương tự khi cố gắng mã hóa địa lý 140 địa chỉ.

Cách giải quyết của tôi là thêm usleep (100000) cho mỗi vòng lặp của yêu cầu mã hóa địa lý tiếp theo. Nếu trạng thái của yêu cầu là OVER_QUERY_LIMIT, usleep sẽ tăng lên 50000 và yêu cầu được lặp lại, v.v.

Và nguyên nhân là tất cả dữ liệu nhận được (vĩ độ / độ dài) được lưu trữ trong tệp XML để không chạy yêu cầu mỗi khi tải trang.


1
Câu trả lời của bạn là mơ hồ, bạn đang đề cập đến ở phía máy chủ hay là javascript này, nếu là cái thứ hai, usleep không phải là một hàm và do đó sẽ không chính xác, nếu nó là cái trước, thì tôi khuyên bạn nên sửa đổi câu trả lời của mình để nêu rõ điều này là phía máy chủ để tránh sự mơ hồ.
t0mm13b

1

BIÊN TẬP:

Quên nói rằng giải pháp này là trong js thuần túy, điều duy nhất bạn cần là một trình duyệt hỗ trợ các hứa hẹn https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Đối với những người vẫn cần phải hoàn thành như vậy, tôi đã viết giải pháp của riêng mình kết hợp lời hứa với thời gian chờ.

Mã:

/*
    class: Geolocalizer
        - Handles location triangulation and calculations.
        -- Returns various prototypes to fetch position from strings or coords or dragons or whatever.
*/

var Geolocalizer = function () {
    this.queue          = [];     // queue handler..
    this.resolved       = [];
    this.geolocalizer = new google.maps.Geocoder();  
};

Geolocalizer.prototype = {
    /*
        @fn: Localize
        @scope: resolve single or multiple queued requests.
        @params: <array> needles
        @returns: <deferred> object
    */
    Localize: function ( needles ) {
        var that = this;
        // Enqueue the needles.
        for ( var i = 0; i < needles.length; i++ ) {
            this.queue.push(needles[i]);
        }
        // return a promise and resolve it after every element have been fetched (either with success or failure), then reset the queue.
        return new Promise (
            function (resolve, reject) {
                that.resolveQueueElements().then(function(resolved){
                  resolve(resolved);
                  that.queue    = [];
                  that.resolved = [];
                });
            }
        );
    },

    /*
        @fn: resolveQueueElements
        @scope: resolve queue elements.
        @returns: <deferred> object (promise)
    */

    resolveQueueElements: function (callback) {
        var that = this;
        return new Promise(
            function(resolve, reject) {
                // Loop the queue and resolve each element.
                // Prevent QUERY_LIMIT by delaying actions by one second.
                (function loopWithDelay(such, queue, i){
                    console.log("Attempting the resolution of " +queue[i-1]);
                    setTimeout(function(){
                        such.find(queue[i-1], function(res){
                           such.resolved.push(res); 
                        });
                        if (--i) {
                            loopWithDelay(such,queue,i);
                        }
                    }, 1000);
                })(that, that.queue, that.queue.length);

                // Check every second if the queue has been cleared.
                var it = setInterval(function(){
                    if (that.queue.length == that.resolved.length) {
                        resolve(that.resolved);
                        clearInterval(it);
                    }
                }, 1000);
            }
        );
    },

    /*
        @fn: find
        @scope: resolve an address from string
        @params: <string> s, <fn> Callback
    */
    find: function (s, callback) {
        this.geolocalizer.geocode({
            "address": s
        }, function(res, status){
           if (status == google.maps.GeocoderStatus.OK) {
               var r = {
                   originalString:  s,
                   lat: res[0].geometry.location.lat(),
                   lng: res[0].geometry.location.lng()
               };
               callback(r);
           }
            else {
                callback(undefined);
                console.log(status);
                console.log("could not locate " + s);
            }
        });
    }
};

Xin lưu ý rằng nó chỉ là một phần của thư viện lớn hơn mà tôi đã viết để xử lý nội dung bản đồ google, do đó các nhận xét có thể gây nhầm lẫn.

Cách sử dụng khá đơn giản, tuy nhiên, cách tiếp cận hơi khác: thay vì lặp lại và giải quyết từng địa chỉ một, bạn sẽ cần chuyển một mảng địa chỉ cho lớp và nó sẽ tự xử lý tìm kiếm, trả về một lời hứa. , khi được giải quyết, trả về một mảng chứa tất cả địa chỉ đã được giải quyết (và chưa được giải quyết).

Thí dụ:

var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){ 
   console.log(res); 
});

Đầu ra bảng điều khiển:

Attempting the resolution of Georgia
Attempting the resolution of China
Attempting the resolution of Dragons are thugs...
Attempting the resolution of California
ZERO_RESULTS
could not locate Dragons are thugs...
Attempting the resolution of Italy

Đối tượng được trả lại:

nhập mô tả hình ảnh ở đây

Toàn bộ điều kỳ diệu xảy ra ở đây:

(function loopWithDelay(such, queue, i){
                    console.log("Attempting the resolution of " +queue[i-1]);
                    setTimeout(function(){
                        such.find(queue[i-1], function(res){
                           such.resolved.push(res); 
                        });
                        if (--i) {
                            loopWithDelay(such,queue,i);
                    }
                }, 750);
            })(that, that.queue, that.queue.length);

Về cơ bản, nó lặp lại mọi mục với độ trễ là 750 mili giây giữa mỗi mục, do đó cứ mỗi 750 mili giây thì một địa chỉ được kiểm soát.

Tôi đã thực hiện một số thử nghiệm khác và tôi phát hiện ra rằng ngay cả ở 700 mili giây, đôi khi tôi vẫn gặp lỗi QUERY_LIMIT, trong khi với 750, tôi không gặp bất kỳ sự cố nào.

Trong mọi trường hợp, vui lòng chỉnh sửa 750 ở trên nếu bạn cảm thấy an toàn bằng cách xử lý độ trễ thấp hơn.

Hy vọng điều này sẽ giúp ai đó trong tương lai gần;)


0

Tôi vừa thử nghiệm Google Geocoder và gặp sự cố tương tự như bạn. Tôi nhận thấy rằng tôi chỉ nhận được trạng thái OVER_QUERY_LIMIT một lần sau mỗi 12 yêu cầu Vì vậy, tôi đợi 1 giây (đó là độ trễ tối thiểu để chờ) Nó làm chậm ứng dụng nhưng ít hơn chờ 1 giây cho mỗi yêu cầu

info = getInfos(getLatLng(code)); //In here I call Google API
record(code, info);
generated++; 
if(generated%interval == 0) {
holdOn(delay); // Every x requests, I sleep for 1 second
}

Với phương thức holdOn cơ bản:

private void holdOn(long delay) {
        try {
            Thread.sleep(delay);
        } catch (InterruptedException ex) {
            // ignore
        }
    }

Hy vọng nó giúp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.