Como faço para geocodificar 20 endereços sem receber uma resposta de OVER_QUERY_LIMIT?

Usando o Google Geocoder v3, se eu tentar geocodificar 20 endereços, recebo um OVER_QUERY_LIMIT, a menos que eu tenha um intervalo de aproximadamente 1 segundo, mas demora 20 segundos para que meus marcadores sejam colocados.

Existe alguma outra maneira de fazer isso, além de armazenar as coordenadas com antecedência?

Não, realmente não há outra maneira: se você tem muitos locais e deseja exibi-los em um mapa, a melhor solução é:

  • obtém a latitude + longitude usando o geocodificador quando um local é criado
  • armazene aqueles em seu database, ao lado do endereço
  • e use as latitude + longitude armazenadas quando quiser exibir o mapa.

Isto é, naturalmente, considerando que você tem muito menos criação / modificação de locais do que você tem consultas de locais.

Sim, isso significa que você terá que fazer um pouco mais de trabalho ao salvar os locais – mas isso também significa:

  • Você poderá pesquisar por coordenadas geográficas
    • ie ” Eu quero uma lista de pontos que estão perto de onde estou agora
  • Exibindo o mapa será muito mais rápido
    • Mesmo com mais de 20 locais nele
  • Ah, e também (por último mas não menos importante) : isso vai funcionar 😉
    • É menos provável que você atinja o limite de chamadas do geocoder X em N segundos.
    • E é menos provável que você atinja o limite de chamadas do geocoder Y por dia.

Você realmente não precisa esperar um segundo inteiro para cada solicitação. Descobri que, se eu esperar 200 milissegundos entre cada solicitação, poderei evitar a resposta de OVER_QUERY_LIMIT e a experiência do usuário será aceitável. Com esta solução você pode carregar 20 itens em 4 segundos.

$(items).each(function(i, item){ setTimeout(function(){ geoLocate("my address", function(myLatlng){ ... }); }, 200 * i); } 

Infelizmente esta é uma restrição do serviço de mapas do Google.

No momento, estou trabalhando em um aplicativo usando o recurso de geocodificação e estou salvando cada endereço exclusivo por usuário. Eu gero as informações de endereço (cidade, rua, estado, etc) com base nas informações retornadas pelos mapas do Google e, em seguida, salve as informações de lat / long no database também. Isso impede que você precise recodificar as coisas e fornece endereços bem formatados.

Outro motivo pelo qual você deseja fazer isso é porque há um limite diário no número de endereços que podem ser geocodificados a partir de um determinado endereço IP. Você não quer que seu aplicativo falhe por uma pessoa por esse motivo.

Estou enfrentando o mesmo problema tentando geocodificar 140 endereços.

Minha solução alternativa era adicionar usleep (100000) para cada loop da próxima solicitação de geocodificação. Se o status da solicitação for OVER_QUERY_LIMIT, o período de uso será aumentado em 50000 e a solicitação será repetida, e assim por diante.

E de causar todos os dados recebidos (lat / long) são armazenados no arquivo XML para não executar a solicitação toda vez que a página está sendo carregada.

EDITAR:

Esqueci de dizer que esta solução está em js puro, a única coisa que você precisa é de um navegador que suporte promises https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Para aqueles que ainda precisam realizar isso, escrevi minha própria solução que combina promises com tempos limite.

Código:

 /* 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:  needles @returns:  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:  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:  s,  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); } }); } }; 

Por favor, note que é apenas uma parte de uma biblioteca maior que eu escrevi para lidar com coisas do Google Maps, portanto, os comentários podem ser confusos.

O uso é bastante simples, a abordagem, no entanto, é um pouco diferente: em vez de fazer um loop e resolver um endereço de cada vez, você precisará passar uma matriz de endereços para a class e ele irá manipular a pesquisa, retornando uma promise que , quando resolvido, retorna uma matriz contendo todo o endereço resolvido (e não resolvido).

Exemplo:

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

Saída do 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 

Objeto devolvido:

insira a descrição da imagem aqui

Toda a mágica acontece aqui:

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

Basicamente, ele faz um loop em todos os itens com um atraso de 750 milissegundos entre cada um deles, portanto, a cada 750 milissegundos, um endereço é controlado.

Fiz alguns testes adicionais e descobri que, mesmo em 700 milissegundos, às vezes recebia o erro QUERY_LIMIT, enquanto que, com 750, não tive nenhum problema.

De qualquer forma, sinta-se à vontade para editar os 750 acima, se achar que está seguro ao lidar com um atraso menor.

Espero que isso ajude alguém no futuro próximo;)

Acabei de testar o Google Geocoder e recebi o mesmo problema que você. Percebi que só recebo o status OVER_QUERY_LIMIT uma vez a cada 12 solicitações. Então, eu espero por 1 segundo (esse é o mínimo atraso a esperar). Ele retarda o aplicativo, mas diminui a espera de 1 segundo a cada solicitação.

 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 } 

Com o método holdOn básico:

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

Espero que ajude

    Intereting Posts