Javascript 如何在不收到 OVER_QUERY_LIMIT 响应的情况下对 20 个地址进行地理编码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2419219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I Geocode 20 addresses without receiving an OVER_QUERY_LIMIT response?
提问by Michiel van Oosterhout
Using the Google Geocoder v3, if I try to geocode 20 addresses, I get an OVER_QUERY_LIMIT unless I time them to be ~1 second apart, but then it takes 20 seconds before my markers are all placed.
使用谷歌地理编码器 v3,如果我尝试对 20 个地址进行地理编码,我会得到一个 OVER_QUERY_LIMIT,除非我将它们间隔约 1 秒,但在我的标记全部放置之前需要 20 秒。
Is there any other way to do it, other than storing the coordinates in advance?
除了预先存储坐标之外,还有其他方法可以做到吗?
采纳答案by Pascal MARTIN
No, there is not really any other way : if you have many locations and want to display them on a map, the best solution is to :
不,真的没有任何其他方式:如果您有很多位置并想在地图上显示它们,最好的解决方案是:
- fetch the latitude+longitude, using the geocoder, when a location is created
- store those in your database, alongside the address
- and use those stored latitude+longitude when you want to display the map.
- 创建位置时,使用地理编码器获取纬度+经度
- 将它们与地址一起存储在您的数据库中
- 并在要显示地图时使用这些存储的纬度+经度。
This is, of course, considering that you have a lot less creation/modification of locations than you have consultations of locations.
当然,这是考虑到您对位置的创建/修改比对位置进行咨询要少得多。
Yes, it means you'll have to do a bit more work when saving the locations -- but it also means :
是的,这意味着您在保存位置时需要做更多的工作——但这也意味着:
- You'll be able to search by geographical coordinates
- i.e. "I want a list of points that are near where I'm now"
- Displaying the map will be a lot faster
- Even with more than 20 locations on it
- Oh, and, also (last but not least): this will work ;-)
- You will less likely hit the limit of X geocoder calls in N seconds.
- And you will less likely hit the limit of Y geocoder calls per day.
- 您将能够按地理坐标进行搜索
- 即“我想要一个靠近我现在位置的点的列表”
- 显示地图会快很多
- 即使上面有 20 多个位置
- 哦,还有(最后但并非最不重要的):这会起作用;-)
- 您不太可能在 N 秒内达到 X 个地理编码器调用的限制。
- 而且您不太可能达到每天 Y 次地理编码器调用的限制。
回答by gabeodess
You actually do not have to wait a full second for each request. I found that if I wait 200 miliseconds between each request I am able to avoid the OVER_QUERY_LIMIT response and the user experience is passable. With this solution you can load 20 items in 4 seconds.
您实际上不必为每个请求等待一整秒。我发现如果我在每个请求之间等待 200 毫秒,我可以避免 OVER_QUERY_LIMIT 响应并且用户体验是可以通过的。使用此解决方案,您可以在 4 秒内加载 20 个项目。
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
回答by Zachary Wright
Unfortunately this is a restriction of the Google maps service.
不幸的是,这是谷歌地图服务的限制。
I am currently working on an application using the geocoding feature, and I'm saving each unique address on a per-user basis. I generate the address information (city, street, state, etc) based on the information returned by Google maps, and then save the lat/long information in the database as well. This prevents you from having to re-code things, and gives you nicely formatted addresses.
我目前正在使用地理编码功能开发一个应用程序,我正在为每个用户保存每个唯一的地址。我根据谷歌地图返回的信息生成地址信息(城市、街道、州等),然后将纬度/经度信息也保存在数据库中。这可以防止您重新编码,并为您提供格式良好的地址。
Another reason you want to do this is because there is a daily limit on the number of addresses that can be geocoded from a particular IP address. You don't want your application to fail for a person for that reason.
您想要这样做的另一个原因是,可以从特定 IP 地址进行地理编码的地址数量存在每日限制。你不希望你的申请因为这个原因而失败。
回答by gray
I'm facing the same problem trying to geocode 140 addresses.
我在尝试对 140 个地址进行地理编码时遇到了同样的问题。
My workaround was adding usleep(100000)for each loop of next geocoding request. If status of the request is OVER_QUERY_LIMIT, the usleep is increased by 50000 and request is repeated, and so on.
我的解决方法是为下一个地理编码请求的每个循环添加usleep(100000)。如果请求的状态为OVER_QUERY_LIMIT,则usleep 增加50000 并重复请求,以此类推。
And of cause all received data (lat/long) are stored in XML file not to run request every time the page is loading.
由于所有接收到的数据(纬度/经度)都存储在 XML 文件中,因此每次加载页面时都不会运行请求。
回答by briosheje
EDIT:
编辑:
Forgot to say that this solution is in pure js, the only thing you need is a browser that supports promiseshttps://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
忘了说这个方案是纯js的,你唯一需要的是一个支持promise的浏览器https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
For those who still needs to accomplish such, I've written my own solution that combines promises with timeouts.
对于那些仍然需要完成此类任务的人,我编写了自己的解决方案,将 promise 与超时相结合。
Code:
代码:
/*
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);
}
});
}
};
Please note that it's just a part of a bigger library I wrote to handle google maps stuff, hence comments may be confusing.
请注意,它只是我为处理谷歌地图而编写的更大库的一部分,因此评论可能会令人困惑。
Usage is quite simple, the approach, however, is slightly different: instead of looping and resolving one address at a time, you will need to pass an array of addresses to the class and it will handle the search by itself, returning a promise which, when resolved, returns an array containing all the resolved (and unresolved) address.
用法很简单,但是方法略有不同:不是一次循环和解析一个地址,您需要将地址数组传递给类,它会自行处理搜索,返回一个承诺,当解析时,返回一个包含所有解析(和未解析)地址的数组。
Example:
例子:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
Console output:
控制台输出:
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
Object returned:
返回的对象:
The whole magic happens 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);
Basically, it loops every item with a delay of 750 milliseconds between each of them, hence every 750 milliseconds an address is controlled.
基本上,它在每个项目之间以 750 毫秒的延迟循环每个项目,因此每 750 毫秒控制一个地址。
I've made some further testings and I've found out that even at 700 milliseconds I was sometimes getting the QUERY_LIMIT error, while with 750 I haven't had any issue at all.
我做了一些进一步的测试,我发现即使在 700 毫秒时我有时也会收到 QUERY_LIMIT 错误,而在 750 时我根本没有任何问题。
In any case, feel free to edit the 750 above if you feel you are safe by handling a lower delay.
在任何情况下,如果您觉得通过处理较低的延迟是安全的,请随意编辑上面的 750。
Hope this helps someone in the near future ;)
希望这能在不久的将来对某人有所帮助;)
回答by Hugues
I have just tested Google Geocoder and got the same problem as you have. I noticed I only get the OVER_QUERY_LIMIT status once every 12 requests So I wait for 1 second (that's the minimum delay to wait) It slows down the application but less than waiting 1 second every request
我刚刚测试了 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
}
With the basic holdOn method :
使用基本的holdOn 方法:
private void holdOn(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
// ignore
}
}
Hope it helps
希望能帮助到你


