javascript - 如何在不收到OVER_QUERY_LIMIT响应的情况下对20个地址进行地理编码?

使用谷歌地理编码器v3,如果我尝试对20个地址进行地理编码,我会得到一个OVER_QUERY_LIMIT,除非我将它们分开约1秒,但是我的标记全部放置需要20秒。

除了预先存储坐标之外,还有其他方法吗?

6个解决方案
83 votes

不,没有其他任何方式:如果您有许多位置并希望在地图上显示它们,最佳解决方案是:

  • 创建位置时,使用地理编码器获取纬度+经度
  • 将数据存储在数据库中,并与地址一起存储
  • 当您想要显示地图时,使用那些存储的纬度+经度。

当然,考虑到您创建/修改位置的次数比您对位置的咨询要少得多。


是的,这意味着在保存位置时你将不得不做更多的工作 - 但它也意味着:

  • 您将能够按地理坐标进行搜索
    • 即“我想要一个靠近我现在所在位置的点列表”
  • 显示地图会快得多
    • 即使有超过20个位置
  • 哦,而且,(最后但并非最不重要):这将工作;-)
    • 您将不太可能在N秒内达到X地理编码器调用的限制。
    • 并且您不太可能达到每天Y地理编码器呼叫的限制。
Pascal MARTIN answered 2019-09-11T06:41:12Z
20 votes

实际上,您不必为每个请求等待一整秒。 我发现如果我在每个请求之间等待200毫秒,我就可以避免OVER_QUERY_LIMIT响应并且用户体验可以通过。 使用此解决方案,您可以在4秒内加载20个项目。

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

  setTimeout(function(){

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

  }, 200 * i);

}
gabeodess answered 2019-09-11T06:41:35Z
6 votes

不幸的是,这是Google地图服务的限制。

我目前正在使用地理编码功能处理应用程序,并且我将基于每个用户保存每个唯一地址。 我根据谷歌地图返回的信息生成地址信息(城市,街道,州等),然后将纬度/经度信息保存在数据库中。 这可以防止您不得不重新编码,并为您提供格式良好的地址。

您想要这样做的另一个原因是因为可以从特定IP地址进行地理编码的地址数量每日限制。 出于这个原因,您不希望您的应用程序因某个人而失败。

Zachary Wright answered 2019-09-11T06:42:12Z
2 votes

我在尝试对140个地址进行地理编码时遇到了同样的问题。

我的解决方法是为下一个地理编码请求的每个循环添加usleep(100000)。 如果请求的状态为OVER_QUERY_LIMIT,则usleep将增加50000并重复请求,依此类推。

并且因为所有接收的数据(lat / long)都存储在XML文件中,以便在每次加载页面时都不运行请求。

gray answered 2019-09-11T06:42:49Z
1 votes

编辑:

忘了说这个解决方案是纯粹的js,你唯一需要的是一个支持promises的浏览器[https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise]


对于那些仍然需要完成此任务的人,我编写了自己的解决方案,将承诺与超时结合起来。

码:

/*
    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);
            }
        });
    }
};

请注意,它只是我写的处理谷歌地图的更大图书馆的一部分,因此评论可能会令人困惑。

用法非常简单,然而,方法略有不同:您不需要一次循环和解析一个地址,而是需要将一个地址数组传递给类,它将自己处理搜索,返回一个promise ,当解析时,返回一个包含所有已解析(和未解析)地址的数组。

例:

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

控制台输出:

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

返回的对象:

enter image description here

整个魔术发生在这里:

(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);

基本上,它在每个项目之间循环延迟750毫秒,因此每750毫秒一个地址被控制。

我做了一些进一步的测试,我发现即使在700毫秒我有时也会收到QUERY_LIMIT错误,而在750时我根本没有任何问题。

在任何情况下,如果您觉得自己安全,可以通过降低延迟来编辑上面的750。

希望这可以在不久的将来帮助某人;)

briosheje answered 2019-09-11T06:44:22Z
0 votes

我刚刚测试了Google Geocoder并遇到了与您相同的问题。我注意到我每12次请求只获得一次OVER_QUERY_LIMIT状态所以我等了1秒(这是等待的最小延迟)它会降低应用程序的速度,但每次请求都会等待1秒钟

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
}

使用基本的holdOn方法:

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

希望能帮助到你

Hugues answered 2019-09-11T06:44:53Z
translate from https://stackoverflow.com:/questions/2419219/how-do-i-geocode-20-addresses-without-receiving-an-over-query-limit-response