OVER_QUERY_LIMIT 응답을받지 않고 20 개 주소를 지오 코딩하려면 어떻게해야합니까?
Google Geocoder v3를 사용하여 20 개의 주소를 지오 코딩하려고하면 ~ 1 초 간격으로 시간을 설정하지 않으면 OVER_QUERY_LIMIT가 표시되지만 마커가 모두 배치되기까지 20 초가 걸립니다.
좌표를 미리 저장하는 것 외에 다른 방법이 있습니까?
아니요, 다른 방법은 없습니다. 위치가 많고지도에 표시하려는 경우 가장 좋은 방법은 다음과 같습니다.
- 위치가 생성 될 때 지오 코더를 사용하여 위도 + 경도를 가져옵니다.
- 주소와 함께 데이터베이스에 저장
- 지도를 표시하고 싶을 때 저장된 위도 + 경도를 사용합니다.
물론 이것은 위치에 대한 상담보다 위치 생성 / 수정이 훨씬 적다는 것을 고려할 때입니다.
예, 위치를 저장할 때 좀 더 많은 작업을해야하지만 다음을 의미하기도합니다.
- 지리적 좌표로 검색 할 수 있습니다.
- 즉 " 지금있는 위치에 가까운 지점 목록을 원합니다. "
- 지도 표시가 훨씬 빨라집니다.
- 20 개 이상의 위치가있는 경우에도
- 오, 그리고 또한 (마지막으로 중요하지만) : 이것은 작동합니다 ;-)
- N 초 내에 X 지오 코더 호출 제한에 도달 할 가능성이 적습니다.
- 그리고 하루에 Y 지오 코더 호출 한도에 도달 할 가능성이 적습니다.
실제로 각 요청에 대해 1 초를 기다릴 필요가 없습니다. 각 요청 사이에 200 밀리 초를 기다리면 OVER_QUERY_LIMIT 응답을 피할 수 있고 사용자 경험이 통과 할 수 있다는 것을 알았습니다. 이 솔루션을 사용하면 4 초 내에 20 개의 항목을로드 할 수 있습니다.
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
안타깝게도 이것은 Google지도 서비스의 제한 사항입니다.
현재 지오 코딩 기능을 사용하는 응용 프로그램에서 작업 중이며 각 고유 주소를 사용자별로 저장하고 있습니다. Google지도에서 반환 한 정보를 기반으로 주소 정보 (시, 거리, 주 등)를 생성 한 다음 위도 / 경도 정보도 데이터베이스에 저장합니다. 이렇게하면 코드를 다시 코딩 할 필요가 없으며 멋진 형식의 주소를 얻을 수 있습니다.
이 작업을 수행하려는 또 다른 이유는 특정 IP 주소에서 지오 코딩 할 수있는 주소 수에 일일 제한이 있기 때문입니다. 그런 이유로 신청이 실패하는 것을 원하지 않습니다.
140 개의 주소를 지오 코딩하려는 동일한 문제에 직면 해 있습니다.
내 해결 방법은 다음 지오 코딩 요청의 각 루프에 대해 usleep (100000) 을 추가하는 것 입니다. 요청 상태가 OVER_QUERY_LIMIT이면 usleep이 50000 증가하고 요청이 반복됩니다.
그리고 수신 된 모든 데이터 (위도 / 경도)는 페이지가로드 될 때마다 요청을 실행하지 않도록 XML 파일에 저장됩니다.
편집하다:
이 솔루션은 순수 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지도를 처리하기 위해 작성한 더 큰 라이브러리의 일부일 뿐이므로 댓글이 혼란 스러울 수 있습니다.
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.
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.
In any case, feel free to edit the 750 above if you feel you are safe by handling a lower delay.
Hope this helps someone in the near future ;)
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
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 :
private void holdOn(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
// ignore
}
}
Hope it helps
'developer tip' 카테고리의 다른 글
ScrollView 내의 ViewPager가 올바르게 스크롤되지 않습니다. (0) | 2020.09.10 |
---|---|
크기와 개수를 인수로 취하는 fread / fwrite의 근거는 무엇입니까? (0) | 2020.09.10 |
f : viewAction / preRenderView 대 PostConstruct를 언제 사용합니까? (0) | 2020.09.10 |
친구에게 비공개 메시지 보내기 (0) | 2020.09.10 |
Akka 또는 원자로 (0) | 2020.09.10 |