[javascript] 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지도를 처리하기 위해 작성한 더 큰 라이브러리의 일부일 뿐이므로 댓글이 혼란 스러울 수 있습니다.

사용법은 매우 간단하지만 접근 방식은 약간 다릅니다. 한 번에 하나의 주소를 반복하고 확인하는 대신 클래스에 주소 배열을 전달해야하며 검색을 자체적으로 처리하여 약속을 반환합니다. , 확인되면 확인 된 (및 확인되지 않은) 주소를 모두 포함하는 배열을 반환합니다.

예:

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을 자유롭게 편집하십시오.

이것이 가까운 장래에 누군가에게 도움이되기를 바랍니다.)


답변

방금 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
        }
    }

도움이되기를 바랍니다.


답변