地理编码未成功,原因如下:OVER_QUERY_LIMIT
我很确定这是对标记进行地理编码的方式。
如何避免这些警告,并且有一种更有效的方法对结果进行地理编码?
更新:这是我的尝试在Casey的回答下,此刻我只是得到一个空白页。
<script type="text/javascript">
(function() {
window.onload = function() {
var mc;
// Creating an object literal containing the properties we want to pass to the map
var options = {
zoom: 10,
center: new google.maps.LatLng(52.40, -3.61),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Creating the map
var map = new google.maps.Map(document.getElementById('map'), options);
// Creating a LatLngBounds object
var bounds = new google.maps.LatLngBounds();
// Creating an array that will contain the addresses
var places = [];
// Creating a variable that will hold the InfoWindow object
var infowindow;
mc = new MarkerClusterer(map);
<?php
$pages = get_pages(array('child_of' => $post->ID, 'sort_column' => 'menu_order'));
$popup_content = array();
foreach($pages as $post)
{
setup_postdata($post);
$fields = get_fields();
$popup_content[] = '<p>'.$fields->company_name.'</p><img src="'.$fields->company_logo.'" /><br /><br /><a href="'.get_page_link($post->ID).'">View profile</a>';
$comma = ", ";
$full_address = "{$fields->address_line_1}{$comma}{$fields->address_line_2}{$comma}{$fields->address_line_3}{$comma}{$fields->post_code}";
$address[] = $full_address;
}
wp_reset_query();
echo 'var popup_content = ' . json_encode($popup_content) . ';';
echo 'var address = ' . json_encode($address) . ';';
?>
var geocoder = new google.maps.Geocoder();
var markers = [];
// Adding a LatLng object for each city
for (var i = 0; i < address.length; i++) {
(function(i) {
geocoder.geocode( {'address': address[i]}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
places[i] = results[0].geometry.location;
// Adding the markers
var marker = new google.maps.Marker({position: places[i], map: map});
markers.push(marker);
mc.addMarker(marker);
// Creating the event listener. It now has access to the values of i and marker as they were during its creation
google.maps.event.addListener(marker, 'click', function() {
// Check to see if we already have an InfoWindow
if (!infowindow) {
infowindow = new google.maps.InfoWindow();
}
// Setting the content of the InfoWindow
infowindow.setContent(popup_content[i]);
// Tying the InfoWindow to the marker
infowindow.open(map, marker);
});
// Extending the bounds object with each LatLng
bounds.extend(places[i]);
// Adjusting the map to new bounding box
map.fitBounds(bounds)
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
})(i);
}
var markerCluster = new MarkerClusterer(map, markers);
}
})
();
</script>
只要标记立即加载,解决方案的大小并不重要并没有违反任何条款和条件。
#1 楼
像其他所有人一样,我可以为您提供代码答案,但我认为没有人向您解释您所做的事情根本上是错误的。为什么会遇到此错误?因为您每次有人查看您的页面时都在调用地理编码,而您并未将结果缓存在数据库中的任何地方!
存在此限制的原因是为了防止滥用Google的资源(无论是有意还是无意) )-这正是您在做的事情:)
尽管google的地址解析速度很快,但如果每个人都这样使用它,则会导致服务器停机。存在Google Fusion Tables的原因是为您完成了很多繁重的服务器工作。地理编码和切片缓存是在其服务器上完成的。如果您不想使用它,则应将其缓存在服务器上。
如果仍然如此,则每天2500个请求太少了,那么您必须查看Google Maps Premier(付费)许可证每天可以为您提供100,000个地理编码请求,每年大约需要1万个请求(这很多-使用服务器端缓存,除非您是一个庞大的站点或正在进行繁重的数据处理,否则您不应达到此限制)。如果不使用服务器端缓存并使用当前的方法,则每天只能进行800次网页浏览!
一旦您意识到其他提供商按地理编码收费,您将了解应该缓存结果在数据库中。如果采用这种方法,则每次页面浏览的成本约为10美分!当然。只需从其他IP地址发出请求即可。哎呀,您可以通过亚马逊弹性ips代理呼叫,并且始终会有一个新的2500个新分配的呼叫。但是,当然,除了违法(您正在有效地规避Google Maps服务条款对您的限制)之外,您还将进行黑客攻击来掩盖系统中固有的设计缺陷。
那么该用例的正确方法是什么?在调用google geocode api之前,请将其发送到服务器并查询它是否在缓存中。如果不是,请调用地理编码,将其存储在缓存中并返回结果。
还有其他方法,但这应该使您朝着正确的方向开始。
更新:从下面的评论中可以看出,您正在使用PHP,因此这是一个有关如何正确执行代码的代码示例(来自Google团队本身的建议)https://developers.google.com/maps/articles/phpsqlsearch_v3
评论
您是否有示例可以将其发送到服务器等?
–Rob
2011-10-5 15:38
您的后端CMS是什么? (我假设您可以/知道如何进行更改,只需要一个简单的示例以您选择的语言来演示如何执行此操作。您不需要客户端js的示例,还是您呢?您正在使用任何js吗?像jQuery的框架?
–拉吉·亚瑟(Ragi Yaser Burhum)
2011年10月5日在16:19
此外,您首先需要提供有关标记数据如何进入系统的更多上下文
–拉吉·亚瑟(Ragi Yaser Burhum)
2011年10月5日下午16:21
好。那么Google文档中的这一部分应包括mysql和php部分code.google.com/apis/maps/articles/phpsqlgeocode.html
–拉吉·亚瑟(Ragi Yaser Burhum)
2011年10月5日18:32
有关允许哪种缓存的详细信息,请参见10.1.3(b)。 developers.google.com/maps/terms#section_10_12
– Paul Ramsey
13年1月2日,19:33
#2 楼
我认为Sasa都是正确的。就一次发送所有地址而言,一种选择是间隔发送请求。过去使用JavaScript时,我选择使用
setTimeout( [FUNCTION CALL] , 250 )
方法将请求延迟0.25(似乎可以正常工作!)秒。
在.NET中,我选择了:
System.Threading.Thread.Sleep(250);
似乎可以工作。
编辑:不能真正测试它,但这应该/可能有效!
JavaScript示例。 addressArray保存的字符串是地址...
for (var i = 0; i < addressArray.length; i++0
{
setTimeout('googleGeocodingFunction(' + addressArray[i] + ')' , 250);
}
编辑:
for (var i = 0; i < address.length; i++) {
function(i) {
setTimeout(geocoder.geocode({ 'address': address[i] }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
places[i] = results[0].geometry.location;
var marker = new google.maps.Marker({ position: places[i], map: map });
markers.push(marker);
mc.addMarker(marker);
google.maps.event.addListener(marker, 'click', function() {
if (!infowindow) {
infowindow = new google.maps.InfoWindow();
}
// Setting the content of the InfoWindow
infowindow.setContent(popup_content[i]);
// Tying the InfoWindow to the marker
infowindow.open(map, marker);
});
// Extending the bounds object with all coordinates
bounds.extend(places[i]);
// Adjusting the map to new bounding box
map.fitBounds(bounds)
} else {
alert("Geocode was not successful for the following reason: " + status);
}
}), 250);// End of setTimeOut Function - 250 being a quarter of a second.
}
}
评论
谢谢回复。如何将其纳入我的代码。这有点新,因此需要一些帮助。您应该可以查看我的源代码。
–Rob
2011-09-27 16:16
哪位?您使用什么语言?
– catchingMonkey
2011-09-27 16:16
我正在使用javascript,如何设置时间间隔?
–Rob
2011-09-27 16:16
编辑了我的答案。
– catchingMonkey
2011-09-27 16:16
也意识到我的意思是setTimeout()...谢谢凯西。
– catchingMonkey
2011年9月27日在16:24
#3 楼
听起来您正在达到Google施加的同时请求限制(尽管我找不到关于该限制实际上是什么的参考)。您将需要将请求间隔开,以免一次发送125个请求。请注意,每天还有2500个地理编码的请求限制。请咨询Google地理编码策略文档以获取更多信息。
更新:由于发布了一个启发性的补充解决方案通过Mapperz,您可以考虑创建一个新的Google Fusion Table,将地址和所有相关数据存储在表中,并通过其Web界面对该表进行地理编码。 Fusion Table发出的地址解析数量有一个限制,但是这个限制很大。达到上限后,您需要重新提交地址解析请求,Fusion Tables将从上次停止的地方开始提取。这种方法的好处是可以极大地提高速度,因为您只需要对ONCE进行地理编码,而在您当前的解决方案中,您将需要对每个负载进行地理编码,从而迅速达到每日限制。
评论
我猜想我会达到极限,我对此很陌生,以为我需要一个代码示例来提供帮助。
–Rob
2011-09-27 16:16
我一直在研究Google Fusion Tables,并遇到了一些问题。 1.您必须在表格中手动对地址进行地理编码(通过file-> geocode),这可以自动完成吗? 2.有些标记仅在某些缩放级别出现,而其他标记则显示任何缩放级别。这是示例-mediwales.com/mapping/example。我最终要做的是将我的Wordpress数据(即所有公司地址)导出到融合表中,对这些地址自动进行地理编码,然后获取所有这些经过地理编码的地址并立即绘制地图。
–Rob
2011年11月3日,11:45
#4 楼
这是我在javascript中限制地址解析请求的方式,地址是一个包含每个地址解析地址的数组:for (i=0;i<=addresses.length;i++) {
setTimeout( function () {
geocoder.geocode( { 'address': addresses[i]}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//create and add marker to map based off geocode result
var marker = new google.maps.Marker({
map: map,
title: results[0].formatted_address,
position: results[0].geometry.location
});
} //EDIT, was missing the closing bracket here
});
}, i * 1500);
}
这实际上在每个地址解析请求之间增加了一半。
评论
感谢你的回答。尝试集成到我的代码中时,我一直得到空白页-mediwales / mapping
–Rob
2011-09-27 19:28
您是否正在使用任何可能指出错误的调试工具?如果不是,请尝试使用FireFox插件firebug。在这种情况下可以非常方便。
–卡西
2011-09-27 19:47
我不是我不确定将代码放置在正确的位置,我将尝试进行更新。
–Rob
2011-09-27 19:55
我在代码示例中缺少右括号。我编辑了答案,并添加了评论。但是,看起来这不是示例代码中的问题。您得到的是空白页还是空白的地图?空白页表示javascript代码中存在语法错误。空白地图(无标记)将表明地理编码代码存在问题。
–卡西
2011-09-27 20:26
你好我对你的回答还有一句话。延迟现在可以解决,但无法绘制标记。在我的代码中,这些是绘制标记的重要位-(function(i){and})(i);没有这些,即使不增加延迟也不会绘制。
–Rob
2011年10月5日,10:33
#5 楼
我现在已经尝试过该页面,而且现在似乎可以正常使用。我认为您当前使用的计时器方法是正确的,据我所知,只有这种方法可以使用o需要一些服务器端支持,我应该建议进行以下更改(我自由重写了地理编码功能)以利用localStorage。
LocalStorage是大多数浏览器中内置的一项相对较新的技术,它允许网页以在客户端上存储数据。它有点类似于cookie,但是功能更强大,并且不总是发送到服务器(不同于cookie)。
我的目的是在客户端上保存地理编码的地址,以便用户刷新时该页面无需再次在其上调用Google的地址解析器功能。下面的实现是粗略的(我们应该添加代码来检查过时的记录,并且可能需要比索引更好的缓存键),但应该足以让您入门。
希望它会有所帮助。
(function() {
window.onload = function() {
var mc;
// Creating an object literal containing the properties we want to pass to the map
var options = {
zoom: 0, maxZoom: 0,
center: new google.maps.LatLng(52.40, -3.61),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Creating the map
var map = new google.maps.Map(document.getElementById('map'), options);
// Creating a LatLngBounds object
var bounds = new google.maps.LatLngBounds();
// Creating an array that will contain the addresses
var places = [];
// Creating a variable that will hold the InfoWindow object
var infowindow;
mc = new MarkerClusterer(map);
var popup_content = [..redacted..];
var geocoder = new google.maps.Geocoder();
var markers = [];
// Adding a LatLng object for each city
function geocodeAddress(i) {
// check if localStorage is available (it is now available on most modern browsers)
// http://html5tutorial.net/tutorials/working-with-html5-localstorage.html
// NB: this *must* be improved to handle quota limits, age/freshness, etc
if(localStorage && localStorage['address_'+i]) {
places[i]=JSON.parse(localStorage['address_'+i]);
addPlace(i);
} else {
geocoder.geocode( {'address': address[i]}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
places[i] = results[0].geometry.location;
if(localStorage) {
// cache result locally on the browser, this will help reducing the number of requests
// to the google geocoder in case the user refreshes the page
// remember: the more he will refresh, the more he's likely to hit the limit
// (this is one case where refreshing or closing the browser does not work)
localStorage['address_'+i]=JSON.stringify(results[0].geometry.location);
}
addPlace(i);
} else {
console.log("Geocoding of address "+address[i]+" failed");
}
})
}
function addPlace(i) {
// Adding the markers
var marker = new google.maps.Marker({position: places[i], map: map});
markers.push(marker);
mc.addMarker(marker);
// Creating the event listener. It now has access to the values of i and marker as they were during its creation
google.maps.event.addListener(marker, 'click', function() {
// Check to see if we already have an InfoWindow
if (!infowindow) {
infowindow = new google.maps.InfoWindow();
}
// Setting the content of the InfoWindow
infowindow.setContent(popup_content[i]);
// Tying the InfoWindow to the marker
infowindow.open(map, marker);
});
// Extending the bounds object with each LatLng
bounds.extend(places[i]);
// Adjusting the map to new bounding box
map.fitBounds(bounds);
}
function geocode() {
if (geoIndex < address.length) {
geocodeAddress(geoIndex);
++geoIndex;
}
else {
clearInterval(geoTimer);
}
}
var geoIndex = 0;
var geoTimer = setInterval(geocode, 600); // 200 milliseconds (to try out)
var markerCluster = new MarkerClusterer(map, markers);
}
})
();
评论
非常感谢,只是尝试一下,不过我们将在一分钟内尝试一下。听起来是一个好主意。
–Rob
2011年10月5日13:48
刚刚尝试了一下(现在已经恢复到以前的状态),它第一次起作用,然后在我刷新时它只显示了一个空白页。
–Rob
2011年10月5日13:59
立即尝试,出现错误,也请注意,为简洁起见,已删除popup_content变量。
– Unicoletti
2011年10月5日14:07
#6 楼
使用geopy地理编码器,我可以毫不费力地对大量地址进行地理编码(我不确定海报的设置,或者他是否可以在项目中包含python依赖项)这是我的测试:
from geopy import geocoders
g = geocoders.GoogleV3() #https://geopy.readthedocs.io/en/latest/#geopy.geocoders.GoogleV3
for x in xrange(1,10000):
print x
a = g.geocode("AV JOAO NAVES DE AVILA " + str(x) + " UBERLANDIA MG BRASIL")
print a
结果片段
7595(u'Av。Jo \ xe3o Naves de \ xc1vila,7595- Segismundo Pereira,
Uberl \ xe2ndia-米纳斯吉拉斯州,38408-288,巴西',(-18.9388154,
-48.2220562))
7596(u'Av。Jo \ xe3o Naves de \ xc1vila,7596-Segismundo Pereira,
Uberl \ xe2ndia-Minas Gerais,38408-680,Brazil',(-18.938814,
-48.2217423))
7597( u'Av。Jo \ xe3o Naves de \ xc1vila,7597-Segismundo Pereira,
Uberl \ xe2ndia-Minas Gerais,38408-288,Brazil',(-18.9388128,
-48.2220381))
7598(u'Av。Jo \ xe3o Naves de \ xc1vila,7598-Segismundo Pereira,
Uberl \ xe2ndia-Minas Gerais,38408-680,Brazil',(-18.9388114,
-48.2217242))
7599(u'Av。Jo \ xe3o Naves de \ xc1vila,7599-Segismundo Pereira,
Uberl \ xe2ndia-Minas Gerais,38408-288,Brazil',(-18.9388102,
-48.2220201))
7600(u'Av 。 Jo \ xe3o Naves de \ xc1vila,7600-Segismundo Pereira,
Uberl \ xe2ndia-Minas Gerais,38408-680,Brazil',(-18.9388088,
-48.2217062))
这仍在运行,我得到7k的结果。
编辑:过了一会儿,我走到了尽头,谷歌开始给我同样的要点,但是看起来就像它还在发出请求并给我准确的答案。
评论
Geopy不是魔术,使用约束仍然适用。
– alphabetasoup
17年5月2日在20:35
#7 楼
此php函数(我不知道您使用的是哪种语言,但是可以确定使用它来区分它)使用google geolocator api。给定一个地址,它将返回规范化的地址和latlong。 HTH。// GEOLOCATEBYADDRESS
// @arg (string)address
// @return (array) ((int)flag,(array)address,array(rawresponse))
function geolocatebyaddress($lookupaddress){
$lookupaddress=trim("$lookupaddress New Zealand");
$lookupaddress=urlencode($lookupaddress);
//send off google api lookup request
$apiurl="http://maps.google.com/maps/api/geocode/json";
$apiurl.="?address=$lookupaddress";
$apiurl.="®ion=NZ";
$apiurl.="&sensor=false";
if (function_exists("curl_init")) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$json = curl_exec($ch);
curl_close($ch);
}
else $json= file_get_contents($apiurl);
//process response
$response= json_decode($json,true);
$approxflag=0;
if ($response['status']=='OK' and count($response['results'])) {
$aa= array();
foreach($response['results'] as $cc=>$result) {
//set keys
foreach(array('street_number','road','suburb','city','postcode','region','lat','long') as $t){
$aa[$cc][$t]='';
}
if ($result['geometry']){
$aa[$cc]['lat']= $result['geometry']['location']['lat'];
$aa[$cc]['long']=$result['geometry']['location']['lng'];
}
if (count($result['address_components'])){
foreach ($result['address_components'] as $acs){
if ($acs['types'][0]=='street_number') $aa[$cc]['street_number']= $acs['long_name'];
if ($acs['types'][0]=='route') $aa[$cc]['road']= $acs['long_name'];
if ($acs['types'][0]=='sublocality') $aa[$cc]['suburb']= $acs['long_name'];
if ($acs['types'][0]=='locality') $aa[$cc]['city']= $acs['long_name'];
if ($acs['types'][0]=='postal_code') $aa[$cc]['postcode']= $acs['long_name'];
if ($acs['types'][0]=='administrative_area_level_1') $aa[$cc]['region']= $acs['long_name'];
}
}
//successful?
if ($result['geometry']['location_type']=='APPROXIMATE') $approxflag++;
if (isset($result['partial_match'])) $approxflag++;
if (!$aa[$cc]['street_number']) $approxflag++;
}
if ($approxflag) return (array(1,$aa,$response));
else return (array(2,$aa,$response));
}
else return (array(0,array(),$response));
}
评论
感谢您的答复,我如何将其合并到我的代码中?
–Rob
2011年10月4日上午10:54
对不起,我想您是在对该网站进行编码。该功能用作服务器端脚本的一部分,例如,该脚本获取用户输入地址,并使用google geocoder api获取坐标。然后,您可以将这些坐标放置在数据库中,当需要生成地图时,只需查询坐标并使用标记生成地图即可。这样一来,您就不会对每个页面渲染的目标都滥用地理编码器。 (您是否贬低了我的评论?我试图提供帮助,对我进行惩罚并不会太鼓励我)。我也不得不提及API要求您将其与gmap一起使用。
–彼得
2011年10月8日在1:29
#8 楼
刚才看到了您的查询。您可以尝试以下代码。在地址解析状态检查的其他部分,递归调用相同的函数,但要间隔一段时间以丢失地址。function spotPosition(address) {
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var lat = results[0].geometry.location.lat();
var lang = results[0].geometry.location.lng();
setMarker(lat, lang);
}
else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
setTimeout(function () {
//Recursively calling spotPosition method for lost addresses
spotPosition(address);
}, 1000);
}
});
}
#9 楼
这是我的解决方案:依赖项:Gmaps.js,jQuery
var Maps = function($) {
var lost_addresses = [],
geocode_count = 0;
var addMarker = function() { console.log('Marker Added!') };
return {
getGecodeFor: function(addresses) {
var latlng;
lost_addresses = [];
for(i=0;i<addresses.length;i++) {
GMaps.geocode({
address: addresses[i],
callback: function(response, status) {
if(status == google.maps.GeocoderStatus.OK) {
addMarker();
} else if(status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
lost_addresses.push(addresses[i]);
}
geocode_count++;
// notify listeners when the geocode is done
if(geocode_count == addresses.length) {
$.event.trigger({ type: 'done:geocoder' });
}
}
});
}
},
processLostAddresses: function() {
if(lost_addresses.length > 0) {
this.getGeocodeFor(lost_addresses);
}
}
};
}(jQuery);
Maps.getGeocodeFor(address);
// listen to done:geocode event and process the lost addresses after 1.5s
$(document).on('done:geocode', function() {
setTimeout(function() {
Maps.processLostAddresses();
}, 1500);
});
#10 楼
您无法避免google map地理编码限制:必须获取并存储LatLng信息。如果您有多个城市并且不想手动获取LatLng,则可以使用超时来逐步调用geocoder.geocode并将信息保存在javascript对象中,然后使用
console.log(JSON.stringify(object, null, 4));
在控制台中获取漂亮的打印对象,例如, var locationsPosition = {
"Johannesburg - ZA": {
"lat": -26.2041028,
"lng": 28.047305100000017
},
"Chennai - IN": {
"lat": 13.0826802,
"lng": 80.27071840000008
}
}
,所以现在您可以添加使用
locationsPosition["Johannesburg - ZA"].lat
和.lng
标记#11 楼
听起来您需要执行以下两项操作之一:如果每天没有那么多的唯一性,请更改过程以缓存结果。或
升级到可以让您每天处理更多内容的服务
正如人们多次提到的那样,但是我没有亲身经历,因此Google许可似乎要求每张许可支付10万美元每天大约需要1万美元。
如果您想要同等水平或更高的准确性(而不必为此付出代价),则可以尝试我们的服务。以比Google低得多的价格(几乎是成本的十分之一),您可以得到比2500更高的限制(我们的最低限制为每天25k)。
当然,使用我们的付费地理编码API并非如此我建议您100%诚实地提出解决方案,尽管承认这样做很不好。相反,我建议选择选项1,优化服务以进行缓存。除非您每天需要超过2500个UNIQUE地理编码。
免责声明:我为Geocode Farm(我推荐的服务)工作。
评论
为什么投票失败?我看不到这里的任何地方不正确或不正确?
– Geocode.Farm员工
18年8月22日在12:40
评论
您无需说出为什么或多久进行一次这些查找。您没有尝试对每个页面渲染的相同点进行地理编码吗?如果是这样的话,当位置首次添加到数据库时,您应该只使用api一次执行这些查找服务器端。如果您想尝试@Peter的建议,这里有一个简单的工具,可以对Google电子表格中的点进行地理编码。这样一来,您就可以将城市的纬度/经度写入CMS,因此您无需在运行时使用地理编码器。
@Peter实际上,这听起来是个好主意。我有点被撕裂了,因为它会降低我的cms的可用性。如果客户必须找出每个公司的经/纬度,而不是仅仅输入地址,那它就不是很友好。我理解正确吗?
请从下面查看我的新答案以获取php函数。
@rob FWIW我认为Ragi的方法正确。 Casey的答案仍然要求您在每次绘制地图时对每个点进行地理编码,这对于您的静态数据集来说似乎不是必需的