如何在未收到OVER_QUERY_LIMIT响应的情况下对20个地址进行地址解析?


87

使用Google Geocoder v3,如果我尝试对20个地址进行地理编码,除非得到的时间间隔为1秒左右,否则我将获得OVER_QUERY_LIMIT,但是所有标记都需要20秒才能放置完。

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


还是这样吗?我在文档中看到的唯一限制是:“每天查询限制为2500个地理位置请求”。code.google.com/apis/maps/documentation/geocoding/...
russau

6
这与每个用户每天的查询总数无关,它与短时间内的查询数量有关,例如在循环查询中。
Michiel van Oosterhout 2010年

我们在商店拥有营业执照,但仍然遇到无法每秒处理10个以上请求的问题。营业执照和普通开发者之间的唯一区别是,我们每天最多只能通话100,000个电话。
阿比

@michielvoo你解决了这个吗?如果是的话,请帮我。我得到OVER_QUERY_LIMIT。我的问题在SO。小提琴
Prabs 2015年

Answers:


85

不,实际上没有其他方法:如果您有很多位置并希望在地图上显示它们,则最佳解决方案是:

  • 创建位置后,使用地理编码器获取纬度+经度
  • 将它们与地址一起存储在数据库中
  • 并在显示地图时使用存储的纬度和经度。

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


是的,这意味着您在保存位置时必须做更多的工作-但这还意味着:

  • 您将可以按地理坐标进行搜索
    • 即“我想要一个靠近我现在所在位置的点的列表
  • 显示地图会更快
    • 即使上面有20多个位置
  • 哦,还有(最后但并非最不重要):这将起作用;-)
    • 您不太可能在N秒内达到X个地理编码器调用的限制。
    • 而且您不太可能达到每天Y个地理编码器通话的限制。

我很好奇您如何确定经过一段时间(例如一个月)后结果是否正确。您是否每隔一段时间重新查询一次?
克里斯(Chris

2
如果地址(您已经在数据库中拥有的地址-否则您将无法进行地址解析)没有变化,则纬度/经度应发生变化的可能性很小。而且,当然,每次修改地址后,您都应该重新查询地址解析器,以获取与新地址相对应的纬度+经度。
Pascal MARTIN

我已将经纬度存储在数据库中,并通过AJAX作为数组从数据库中检索经纬度,但随后应再次将其传递给Java脚本循环,更多的是,我从数据库收到了173个位置。现在,它向我显示了相同的OVER_QUERY_LIMIT状态。请咨询...
Prabhu M

20

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

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

  setTimeout(function(){

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

  }, 200 * i);

}

5
但是(200 * i)表示每个请求之间的暂停时间在增加。因此,在第三个请求上,它是600,然后是800,等等
Roman

只需删除“ * i”
克里斯

9
setTimeout将执行一次。因此,如果我是对的,(...,200 * i)将安排每个呼叫间隔200毫秒(如oyatek所说),这是gabeodess想要实现的目标。当前(...,200)将在200ms之后同时执行所有操作。还是我错过了什么?
lepe

@gabeodess-您应该setInterval对所需的请求数量进行处理,而不是setTimeout对它进行设置,并将其设置为100-以防万一地址数量将来会扩展20
罗伯·斯科特

3
@gabeodess我已经尝试了您的解决方案,但仍然遇到OVER_QUERY_LIMIT 小提琴
Prabs 2015年

6

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

我目前正在使用地理编码功能开发应用程序,并且正在按用户保存每个唯一地址。我根据Google地图返回的信息生成地址信息(城市,街道,州等),然后将纬度/经度信息也保存在数据库中。这样可以避免您必须重新编码内容,并为您提供格式正确的地址。

您要执行此操作的另一个原因是,每天对可以从特定IP地址进行地址解析的地址数量有限制。您不希望因此而导致应用程序失败。


2

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

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

因此,每次页面加载时,所有接收到的数据(经/纬度)都存储在XML文件中,因此不会运行请求。


1
您的答案含糊不清,是在服务器端引用还是此javascript,如果是后者,则usleep不是函数,因此将是不正确的;如果是前者,那么我建议您修改答案以明确声明此内容是服务器端以避免歧义。
t0mm13b

1

编辑:

忘了说这个解决方案是在纯js中实现的,您唯一需要的就是支持诺言 的浏览器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);
            }
        });
    }
};

请注意,这只是我为处理Google Maps编写的更大的图书馆的一部分,因此评论可能会令人困惑。

用法很简单,但是方法略有不同:您不需要一次循环并解析一个地址,而是需要将一个地址数组传递给该类,并且它将自行处理搜索,并返回一个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

返回的对象:

在此处输入图片说明

整个魔术发生在这里:

(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。

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


0

我刚刚测试了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
        }
    }

希望能帮助到你

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.