Come faccio a geocodificare 20 indirizzi senza ricevere una risposta OVER_QUERY_LIMIT?


87

Utilizzando Google Geocoder v3, se provo a geocodificare 20 indirizzi, ottengo un OVER_QUERY_LIMIT a meno che non cronometri che siano a ~ 1 secondo di distanza, ma poi ci vogliono 20 secondi prima che i miei marcatori siano tutti posizionati.

C'è un altro modo per farlo, oltre a memorizzare le coordinate in anticipo?


è ancora così? L'unica limitazione che vedo nella documentazione è: "un limite di query di 2.500 richieste di geolocalizzazione al giorno". code.google.com/apis/maps/documentation/geocoding/…
russau

6
Non si tratta della quantità totale di query per utente al giorno, ma del numero di query in un breve lasso di tempo, come quando si esegue una query in un ciclo.
Michiel van Oosterhout,

Abbiamo una licenza commerciale presso il nostro negozio e continuiamo a riscontrare il problema dell'impossibilità di gestire più di 10 richieste al secondo. L'unica differenza tra una licenza commerciale e uno sviluppatore regolare è che abbiamo un limite di 100.000 chiamate al giorno.
abhi

@michielvoo Hai risolto questo problema? Se sì, allora gentilmente aiutami. Ricevo OVER_QUERY_LIMIT. La mia domanda in SO. Fiddle
Prabs

Risposte:


85

No, in realtà non c'è altro modo: se hai molte località e vuoi visualizzarle su una mappa, la soluzione migliore è:

  • recuperare la latitudine + longitudine, utilizzando il geocoder, quando viene creata una posizione
  • memorizzali nel tuo database, insieme all'indirizzo
  • e utilizzare quelle memorizzate latitudine + longitudine quando si desidera visualizzare la mappa.

Questo, ovviamente, considerando che hai molta meno creazione / modifica di posizioni rispetto alle consultazioni di posizioni.


Sì, significa che dovrai lavorare un po 'di più quando salvi le posizioni, ma significa anche:

  • Potrai cercare per coordinate geografiche
    • ad es. " Voglio un elenco di punti vicini a dove mi trovo ora "
  • La visualizzazione della mappa sarà molto più veloce
    • Anche con più di 20 posizioni su di esso
  • Oh, e anche (ultimo ma non meno importante) : funzionerà ;-)
    • È meno probabile che raggiungerai il limite di chiamate del geocoder X in N secondi.
    • Ed è meno probabile che raggiungerai il limite di chiamate del geocoder Y al giorno.

Sono curioso di sapere come puoi essere sicuro che i risultati siano corretti dopo un po 'di tempo (diciamo, un mese). Li interroghi nuovamente ogni tanto?
Chris

2
Se l'indirizzo (che hai già nel tuo DB - altrimenti non saresti in grado di geocodificare) non cambia, è molto probabile che la latitudine / longitudine cambi. E, naturalmente, ogni volta che l'indirizzo viene modificato, dovresti interrogare nuovamente il geocoder, per ottenere la latitudine + longitudine che corrispondono al nuovo indirizzo.
Pascal MARTIN

Ho memorizzato lat / long nel DB e recuperandolo dal DB tramite AJAX come array, ma dovrebbe quindi essere passato di nuovo a un ciclo di script java, inoltre ho ricevuto 173 posizioni dal DB. Ora mi mostra lo stesso stato OVER_QUERY_LIMIT. Per favore consiglio ...
Prabhu M

20

In realtà non è necessario attendere un secondo intero per ogni richiesta. Ho scoperto che se aspetto 200 millisecondi tra ogni richiesta sono in grado di evitare la risposta OVER_QUERY_LIMIT e l'esperienza dell'utente è passabile. Con questa soluzione puoi caricare 20 articoli in 4 secondi.

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

  setTimeout(function(){

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

  }, 200 * i);

}

5
ma (200 * i) significa che la pausa tra ogni richiesta è in aumento. Quindi alla terza richiesta sono 600, poi 800 ecc.
Roman

è sufficiente rimuovere la "* i"
Chris

9
setTimeout lo eseguirà una volta. Quindi, se ho ragione, (..., 200 * i) pianificherà ogni chiamata separata da 200 ms (come ha commentato oyatek), che è ciò che gabeodess voleva ottenere. La corrente (..., 200) li eseguirà tutti contemporaneamente dopo 200 ms. O mi sta sfuggendo qualcosa?
lepe

@gabeodess - dovresti fare setIntervalil numero di richieste necessarie, invece di setTimeout, e impostarlo su 100- nel caso in cui l'importo dell'indirizzo in futuro estenderà l' 20importo.
Rob Scott,

3
@gabeodess Ho provato la tua soluzione ma continuo a ottenere OVER_QUERY_LIMIT Fiddle
Prabs

6

Purtroppo questa è una restrizione del servizio di mappe di Google.

Al momento sto lavorando a un'applicazione che utilizza la funzione di geocodifica e sto salvando ogni indirizzo univoco per utente. Genero le informazioni sull'indirizzo (città, via, stato, ecc.) In base alle informazioni restituite da Google Maps, quindi salvo anche le informazioni su latitudine / longitudine nel database. Questo ti impedisce di dover ricodificare le cose e ti dà indirizzi ben formattati.

Un altro motivo per cui vuoi farlo è perché esiste un limite giornaliero al numero di indirizzi che possono essere geocodificati da un particolare indirizzo IP. Non vuoi che la tua richiesta fallisca per una persona per questo motivo.


2

Sto affrontando lo stesso problema cercando di geocodificare 140 indirizzi.

La mia soluzione alternativa era l'aggiunta di usleep (100000) per ogni ciclo della successiva richiesta di geocodifica. Se lo stato della richiesta è OVER_QUERY_LIMIT, l'usleep viene aumentato di 50000 e la richiesta viene ripetuta, e così via.

E di causa tutti i dati ricevuti (lat / long) vengono memorizzati nel file XML per non eseguire la richiesta ogni volta che la pagina viene caricata.


1
La tua risposta è vaga, ti riferisci a lato server o è questo javascript, se è quest'ultimo, usleep non è una funzione e quindi sarebbe errato, se è il primo, allora ti suggerisco di modificare la tua risposta per dichiararlo esplicitamente è lato server per evitare ambiguità.
t0mm13b

1

MODIFICARE:

Ho dimenticato di dire che questa soluzione è in puro js, ​​l'unica cosa di cui hai bisogno è un browser che supporti le promesse https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Per coloro che hanno ancora bisogno di farlo, ho scritto la mia soluzione che combina le promesse con i timeout.

Codice:

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

Tieni presente che è solo una parte di una libreria più grande che ho scritto per gestire le cose di Google Maps, quindi i commenti potrebbero creare confusione.

L'utilizzo è abbastanza semplice, l'approccio, tuttavia, è leggermente diverso: invece di ripetere in loop e risolvere un indirizzo alla volta, dovrai passare un array di indirizzi alla classe che gestirà la ricerca da sola, restituendo una promessa che , una volta risolto, restituisce un array contenente tutti gli indirizzi risolti (e irrisolti).

Esempio:

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

Uscita console:

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

Oggetto restituito:

inserisci qui la descrizione dell'immagine

L'intera magia avviene qui:

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

Fondamentalmente, esegue il loop di ogni elemento con un ritardo di 750 millisecondi tra ciascuno di essi, quindi ogni 750 millisecondi viene controllato un indirizzo.

Ho fatto ulteriori test e ho scoperto che anche a 700 millisecondi a volte ricevevo l'errore QUERY_LIMIT, mentre con 750 non ho avuto alcun problema.

In ogni caso, sentiti libero di modificare il 750 sopra se ritieni di essere al sicuro gestendo un ritardo inferiore.

Spero che questo aiuti qualcuno nel prossimo futuro;)


0

Ho appena testato Google Geocoder e ho riscontrato lo stesso problema che hai tu. Ho notato che ottengo lo stato OVER_QUERY_LIMIT solo una volta ogni 12 richieste Quindi aspetto 1 secondo (questo è il ritardo minimo di attesa) Rallenta l'applicazione ma meno di 1 secondo ogni richiesta

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
}

Con il metodo holdOn di base:

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

Spero che sia d'aiuto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.