OVER_QUERY_LIMIT応答を受信せずに20アドレスをジオコーディングするにはどうすればよいですか?


87

Google Geocoder v3を使用して、20個のアドレスをジオコーディングしようとすると、1秒間隔で配置しない限り、OVER_QUERY_LIMITが発生しますが、マーカーがすべて配置されるまでに20秒かかります。

事前に座標を保存する以外に、他に方法はありますか?


これはまだ当てはまりますか?ドキュメントに表示される唯一の制限は、「1日あたり2,500のジオロケーションリクエストのクエリ制限」です。code.google.com/apis/maps/documentation/geocoding/...
russau

6
これは、ユーザーあたり1日あたりのクエリの総数ではなく、ループでクエリを実行する場合のように、短時間でのクエリの数です。
Michiel van Oosterhout 2010

当店には営業許可がありますが、1秒あたり10件を超えるリクエストを処理できないというこの問題が発生しています。ビジネスライセンスと通常の開発者の唯一の違いは、1日あたりの通話数が100,000に制限されていることです。
abhi 2013

@michielvooこれを解決しましたか?はいの場合は、親切に私を助けてください。OVER_QUERY_LIMITを取得しています。SOでの私の質問フィドル
プラブ2015

回答:


85

いいえ、他に方法はありません。場所がたくさんあり、それらを地図に表示したい場合、最善の解決策は次のとおりです。

  • 場所の作成時に、ジオコーダーを使用して緯度と経度を取得します
  • それらをアドレスと一緒にデータベースに保存します
  • 地図を表示するときは、保存されている緯度と経度を使用します。

もちろん、これは、場所の相談よりも場所の作成/変更がはるかに少ないことを考慮したものです。


はい、それは場所を保存するときにもう少し作業をしなければならないことを意味します-しかしそれはまた意味します:

  • 地理座標で検索できるようになります
    • つまり、「現在の場所の近くにあるポイントのリストが必要です
  • 地図の表示がはるかに速くなります
    • 20か所以上ある場合でも
  • ああ、そしてまた(最後になりましたが):これはうまくいくでしょう;-)
    • N秒でXジオコーダー呼び出しの制限に達する可能性は低くなります。
    • また、1日あたりのYジオコーダー呼び出しの制限に達する可能性は低くなります。

しばらく(たとえば1か月)経過した後、結果が正しいことをどのように確認できるのか興味があります。たまに再クエリしますか?
クリス

2
住所(DBに既にある-そうでなければジオコーディングできないが変更されない場合、緯度/経度が変更される可能性はかなり低くなります。そしてもちろん、住所が変更されるたびに、ジオコーダーを再クエリして、新しい住所に対応する緯度と経度を取得する必要があります。
パスカルマーティン2010年

lat / longをDBに保存し、配列としてAJAXを介してDBから取得しましたが、Javaスクリプトループに再度渡される必要があります。さらに、DBから173の場所を受け取りました。これで、同じOVER_QUERY_LIMITステータスが表示されます。してくださいアドバイス...
プラブーM

20

実際には、リクエストごとに1秒待つ必要はありません。各リクエストの間に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などに
ローマ

'* i'を削除するだけ
Chris

9
setTimeoutはそれを1回実行します。したがって、私が正しければ、(。。。、200 * i)は、(oyatekがコメントしたように)200msで区切られた各呼び出しをスケジュールします。これはgabeodessが達成したかったことです。現在の(。。。、200)は、200ms後にそれらすべてを同時に実行します。それとも私は何かが足りないのですか?
lepe 2014

@ gabeodess-アドレスの量が将来いつか量を拡張する場合に備えてsetInterval、の代わりに必要な数の要求を実行し、setTimeoutそれに設定する100必要があり20ます。
ロブスコット

3
@gabeodess私はあなたの解決策を試しましたが、それでもOVER_QUERY_LIMITフィドルを
Prabs 2015

6

残念ながら、これはGoogleマップサービスの制限です。

私は現在、ジオコーディング機能を使用してアプリケーションに取り組んでおり、ユーザーごとに一意の各アドレスを保存しています。グーグルマップから返された情報に基づいて住所情報(都市、通り、州など)を生成し、緯度/経度の情報もデータベースに保存します。これにより、コードを再コーディングする必要がなくなり、適切にフォーマットされたアドレスが得られます。

これを実行するもう1つの理由は、特定のIPアドレスからジオコーディングできるアドレスの数に1日あたりの制限があるためです。その理由で、ある人のためにアプリケーションが失敗することは望ましくありません。


2

140のアドレスをジオコーディングしようとすると同じ問題が発生します。

私の回避策は、次のジオコーディング要求のループごとにusleep(100000)を追加することでした。リクエストのステータスがOVER_QUERY_LIMITの場合、usleepは50000増加し、リクエストが繰り返されます。

また、受信したすべてのデータ(lat / long)はXMLファイルに保存され、ページが読み込まれるたびにリクエストを実行しないようにします。


1
あなたの答えはあいまいです、あなたはサーバー側で言及していますか、それともこのjavascriptですか、後者の場合、usleepは関数ではないため、正しくありません、前者の場合は、これを明示的に述べるように答えを修正することをお勧めしますあいまいさを避けるためにサーバー側です。
t0mm13b 2014

1

編集:

このソリューションは純粋なjsであると言うのを忘れました。必要なのは、promisehttps ://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);
            }
        });
    }
};

これは、グーグルマップのものを処理するために私が書いたより大きなライブラリの一部にすぎないことに注意してください。したがって、コメントは混乱する可能性があります。

使用法は非常に簡単ですが、アプローチは少し異なります。一度に1つのアドレスをループして解決する代わりに、アドレスの配列をクラスに渡す必要があります。クラスはそれ自体で検索を処理し、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をテストしたところ、あなたと同じ問題が発生しました。OVER_QUERY_LIMITステータスが取得されるのは12リクエストごとに1回だけであることに気付いたので、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
        }
    }

それが役に立てば幸い

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.