webentwicklung-frage-antwort-db.com.de

Wie kann ich 20 Adressen geocodieren, ohne eine OVER_QUERY_LIMIT-Antwort zu erhalten?

Wenn ich mit Google Geocoder v3 versuche, 20 Adressen zu geocodieren, erhalte ich ein OVER_QUERY_LIMIT, es sei denn, ich lege einen Zeitabstand von ~ 1 Sekunde fest, aber dann dauert es 20 Sekunden, bis alle meine Markierungen platziert sind.

Gibt es eine andere Möglichkeit, als die Koordinaten im Voraus zu speichern?

Nein, es gibt eigentlich keinen anderen Weg: Wenn Sie viele Standorte haben und diese auf einer Karte anzeigen möchten, ist die beste Lösung:

  • rufen Sie die geografische Breite + Länge mit dem Geocodierer ab, wenn ein Standort erstellt wird
  • speichern Sie diese in Ihrer Datenbank neben der Adresse
  • und verwenden Sie diese gespeicherten Längen- und Breitengrade, wenn Sie die Karte anzeigen möchten.

Dies ist natürlich zu bedenken, dass Sie viel weniger Standorte erstellen/ändern müssen als Sie Standortkonsultationen haben.


Ja, es bedeutet, dass Sie beim Speichern der Standorte etwas mehr Arbeit leisten müssen - aber es bedeutet auch:

  • Sie können nach geografischen Koordinaten suchen
    • d.h. "Ich möchte eine Liste von Punkten, die sich in der Nähe befinden, in der ich mich gerade befinde."
  • Das Anzeigen der Karte erfolgt viel schneller
    • Auch mit mehr als 20 Standorten
  • Oh, und auch (last but not least): das wird funktionieren; -)
    • Es ist weniger wahrscheinlich, dass Sie das Limit von X Geocoder-Aufrufen in N Sekunden erreichen.
    • Und Sie werden weniger wahrscheinlich das Limit von Y Geocoder-Anrufen pro Tag erreichen.
84
Pascal MARTIN

Sie müssen nicht für jede Anforderung eine volle Sekunde warten. Wenn ich zwischen den einzelnen Anforderungen 200 Millisekunden warte, kann ich die Antwort OVER_QUERY_LIMIT vermeiden und die Benutzererfahrung ist passabel. Mit dieser Lösung können Sie 20 Artikel in 4 Sekunden laden.

$(items).each(function(i, item){

  setTimeout(function(){

    geoLocate("my address", function(myLatlng){
      ...
    });

  }, 200 * i);

}
20
gabeodess

Leider ist dies eine Einschränkung des Google Maps-Dienstes.

Ich arbeite derzeit an einer Anwendung, die die Geokodierungsfunktion verwendet, und speichere jede eindeutige Adresse auf Benutzerbasis. Ich generiere die Adressinformationen (Stadt, Straße, Bundesland usw.) auf der Grundlage der von Google Maps zurückgegebenen Informationen und speichere dann auch die Lat/Long-Informationen in der Datenbank. Dies verhindert, dass Sie Dinge neu codieren müssen, und gibt Ihnen gut formatierte Adressen.

Ein weiterer Grund dafür ist, dass die Anzahl der Adressen, die von einer bestimmten IP-Adresse aus geocodiert werden können, täglich begrenzt ist. Sie möchten nicht, dass Ihre Bewerbung für eine Person aus diesem Grund fehlschlägt.

6
Zachary Wright

Ich habe das gleiche Problem beim Geocodieren von 140 Adressen.

Meine Problemumgehung bestand darin, für jede Schleife der nächsten Geokodierungsanforderung sleep (100000) hinzuzufügen. Wenn der Status der Anforderung OVER_QUERY_LIMIT ist, wird der Nutzungszeitraum um 50000 erhöht und die Anforderung wird wiederholt usw.

Und natürlich werden alle empfangenen Daten (lat/long) in einer XML-Datei gespeichert, um die Anforderung nicht jedes Mal auszuführen, wenn die Seite geladen wird.

2
gray

BEARBEITEN:

Ich habe vergessen zu sagen, dass diese Lösung in reinem js vorliegt. Das einzige, was Sie brauchen, ist ein Browser, der Versprechen https: // Entwickler) unterstützt. mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Für diejenigen, die dies noch tun müssen, habe ich eine eigene Lösung geschrieben, die Versprechen mit Timeouts kombiniert.

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);
            }
        });
    }
};

Bitte beachten Sie, dass dies nur ein Teil einer größeren Bibliothek ist, die ich geschrieben habe, um Google Maps-Inhalte zu verwalten. Daher können Kommentare verwirrend sein.

Die Verwendung ist recht einfach, der Ansatz ist jedoch etwas anders: Anstatt eine Adresse nach der anderen zu wiederholen und aufzulösen, müssen Sie der Klasse eine Reihe von Adressen übergeben, die die Suche selbstständig erledigen und ein Versprechen zurückgeben, das diese verspricht Wenn aufgelöst, wird ein Array zurückgegeben, das alle aufgelösten (und nicht aufgelösten) Adressen enthält.

Beispiel:

var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){ 
   console.log(res); 
});

Konsolenausgabe:

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

Objekt zurückgegeben:

enter image description here

Die ganze Magie passiert hier:

(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);

Grundsätzlich durchläuft es jeden Eintrag mit einer Verzögerung von 750 Millisekunden zwischen den einzelnen Einträgen, sodass alle 750 Millisekunden eine Adresse gesteuert wird.

Ich habe einige weitere Tests durchgeführt und festgestellt, dass ich manchmal sogar nach 700 Millisekunden den Fehler QUERY_LIMIT erhalten habe, während ich mit 750 überhaupt kein Problem hatte.

In jedem Fall können Sie die obigen 750 bearbeiten, wenn Sie sich durch eine geringere Verzögerung sicher fühlen.

Hoffe das hilft jemandem in naher Zukunft;)

1
briosheje

Ich habe gerade Google Geocoder getestet und habe das gleiche Problem wie Sie. Mir ist aufgefallen, dass ich nur alle 12 Anfragen den Status OVER_QUERY_LIMIT erhalte. Ich warte also 1 Sekunde (das ist die minimale Wartezeit). Die Anwendung wird langsamer, aber es wird weniger als 1 Sekunde auf jede Anfrage gewartet

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
}

Mit der grundlegenden holdOn-Methode:

private void holdOn(long delay) {
        try {
            Thread.sleep(delay);
        } catch (InterruptedException ex) {
            // ignore
        }
    }

Ich hoffe es hilft

0
Hugues