Usando Google Geocoder v3, si trato de geocodificar 20 direcciones, obtengo un OVER_QUERY_LIMIT a menos que las programe para que estén separadas por ~ 1 segundo, pero luego pasan 20 segundos antes de que se coloquen todos mis marcadores.
¿Hay alguna otra forma de hacerlo, además de almacenar las coordenadas por adelantado?
javascript
geocoding
google-maps
Michiel van Oosterhout
fuente
fuente
Respuestas:
No, realmente no hay otra manera: si tiene muchas ubicaciones y desea mostrarlas en un mapa, la mejor solución es:
Esto es, por supuesto, considerando que tiene mucha menos creación / modificación de ubicaciones que consultas de ubicaciones.
Sí, significa que tendrá que trabajar un poco más al guardar las ubicaciones, pero también significa:
fuente
En realidad, no tiene que esperar un segundo completo para cada solicitud. Descubrí que si espero 200 milisegundos entre cada solicitud, puedo evitar la respuesta OVER_QUERY_LIMIT y la experiencia del usuario es aceptable. Con esta solución puede cargar 20 artículos en 4 segundos.
$(items).each(function(i, item){ setTimeout(function(){ geoLocate("my address", function(myLatlng){ ... }); }, 200 * i); }
fuente
setInterval
en la cantidad de solicitudes necesarias, en lugar desetTimeout
, y establecerlo en100
, en caso de que la cantidad de la dirección en algún momento en el futuro extienda la20
cantidad.Desafortunadamente, esta es una restricción del servicio de mapas de Google.
Actualmente estoy trabajando en una aplicación que utiliza la función de codificación geográfica y estoy guardando cada dirección única por usuario. Genero la información de la dirección (ciudad, calle, estado, etc.) en función de la información devuelta por los mapas de Google y luego también guardo la información de latitud y longitud en la base de datos. Esto evita que tenga que volver a codificar cosas y le brinda direcciones con un formato agradable.
Otra razón por la que desea hacer esto es porque existe un límite diario en la cantidad de direcciones que se pueden geocodificar desde una dirección IP en particular. No desea que su solicitud falle para una persona por ese motivo.
fuente
Estoy enfrentando el mismo problema al intentar geocodificar 140 direcciones.
Mi solución fue agregar usleep (100000) para cada ciclo de la siguiente solicitud de codificación geográfica . Si el estado de la solicitud es OVER_QUERY_LIMIT, el usleep se incrementa en 50000 y la solicitud se repite, y así sucesivamente.
Y, por lo tanto, todos los datos recibidos (lat / long) se almacenan en un archivo XML para no ejecutar la solicitud cada vez que se carga la página.
fuente
EDITAR:
Olvidé decir que esta solución está en js puro, lo único que necesita es un navegador que admita promesas https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
Para aquellos que todavía necesitan lograrlo, he escrito mi propia solución que combina promesas con tiempos de espera.
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: <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); } }); } };
Tenga en cuenta que es solo una parte de una biblioteca más grande que escribí para manejar cosas de Google Maps, por lo que los comentarios pueden ser confusos.
El uso es bastante simple, sin embargo, el enfoque es ligeramente diferente: en lugar de hacer un bucle y resolver una dirección a la vez, deberá pasar una matriz de direcciones a la clase y esta manejará la búsqueda por sí misma, devolviendo una promesa que , cuando se resuelve, devuelve una matriz que contiene todas las direcciones resueltas (y no resueltas).
Ejemplo:
var myAmazingGeo = new Geolocalizer(); var locations = ["Italy","California","Dragons are thugs...","China","Georgia"]; myAmazingGeo.Localize(locations).then(function(res){ console.log(res); });
Salida de consola:
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 devuelto:
Toda la magia sucede aquí:
(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);
Básicamente, repite cada elemento con un retraso de 750 milisegundos entre cada uno de ellos, por lo que cada 750 milisegundos se controla una dirección.
Hice algunas pruebas adicionales y descubrí que incluso en 700 milisegundos a veces recibía el error QUERY_LIMIT, mientras que con 750 no he tenido ningún problema.
En cualquier caso, siéntase libre de editar el 750 anterior si se siente seguro manejando un retraso menor.
Espero que esto ayude a alguien en un futuro cercano;)
fuente
Acabo de probar Google Geocoder y tengo el mismo problema que tú. Noté que solo obtengo el estado OVER_QUERY_LIMIT una vez cada 12 solicitudes. Así que espero 1 segundo (ese es el retraso mínimo para esperar). Ralentiza la aplicación, pero menos de esperar 1 segundo cada solicitud.
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 el método holdOn básico:
private void holdOn(long delay) { try { Thread.sleep(delay); } catch (InterruptedException ex) { // ignore } }
Espero eso ayude
fuente