Используя Google Geocoder v3, если я попытаюсь геокодировать 20 адресов, я получу OVER_QUERY_LIMIT, если я не запрограммирую их так, чтобы они были разделены на ~ 1 секунду, но затем проходит 20 секунд, прежде чем все мои маркеры будут размещены.
Есть ли другой способ сделать это, кроме как заранее сохранить координаты?
javascript
geocoding
google-maps
Михиль ван Остерхаут
источник
источник
Ответы:
Нет, на самом деле другого пути нет: если у вас много мест и вы хотите отобразить их на карте, лучшим решением будет:
Это, конечно, с учетом того, что у вас намного меньше создания / изменения локаций, чем у вас есть консультации по локациям.
Да, это означает, что вам придется немного поработать при сохранении местоположений, но это также означает:
источник
На самом деле вам не нужно ждать целую секунду для каждого запроса. Я обнаружил, что если я жду 200 миллисекунд между каждым запросом, я могу избежать ответа OVER_QUERY_LIMIT, и пользовательский интерфейс будет приемлемым. С помощью этого решения вы можете загрузить 20 элементов за 4 секунды.
$(items).each(function(i, item){ setTimeout(function(){ geoLocate("my address", function(myLatlng){ ... }); }, 200 * i); }
источник
setInterval
по количеству необходимых запросов, а неsetTimeout
и устанавливать его на100
- на всякий случай, если количество адресов в будущем увеличится20
.К сожалению, это ограничение сервиса Google Maps.
В настоящее время я работаю над приложением, использующим функцию геокодирования, и сохраняю каждый уникальный адрес для каждого пользователя. Я генерирую адресную информацию (город, улица, штат и т. Д.) На основе информации, возвращаемой картами Google, а затем сохраняю информацию о широте и долготе в базе данных. Это избавляет вас от необходимости перекодировать вещи и дает хорошо отформатированные адреса.
Еще одна причина, по которой вы хотите это сделать, заключается в том, что существует дневное ограничение на количество адресов, которые можно геокодировать с определенного IP-адреса. Вы не хотите, чтобы ваше приложение провалилось из-за этого человека.
источник
У меня та же проблема, пытаясь геокодировать 140 адресов.
Мое обходное решение - добавление usleep (100000) для каждого цикла следующего запроса геокодирования. Если статус запроса - OVER_QUERY_LIMIT, usleep увеличивается на 50000, и запрос повторяется, и так далее.
И, конечно же, все полученные данные (широта / долгота) хранятся в файле XML, чтобы не запускать запрос каждый раз при загрузке страницы.
источник
РЕДАКТИРОВАТЬ:
Забыл сказать, что это решение на чистом js, единственное, что вам нужно, это браузер, поддерживающий обещания https://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); } }); } };
Обратите внимание, что это просто часть большой библиотеки, которую я написал для работы с картами Google, поэтому комментарии могут сбивать с толку.
Использование довольно простое, однако подход немного отличается: вместо цикла и разрешения одного адреса за раз вам нужно будет передать массив адресов классу, и он будет обрабатывать поиск самостоятельно, возвращая обещание, которое при разрешении возвращает массив, содержащий все разрешенные (и неразрешенные) адреса.
Пример:
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 выше, если вы чувствуете себя в безопасности, используя меньшую задержку.
Надеюсь, это поможет кому-то в ближайшем будущем;)
источник
Я только что протестировал Google Geocoder и столкнулся с той же проблемой, что и вы. Я заметил, что я получаю статус OVER_QUERY_LIMIT только один раз каждые 12 запросов, поэтому я жду 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 }
С помощью основного метода удержания:
private void holdOn(long delay) { try { Thread.sleep(delay); } catch (InterruptedException ex) { // ignore } }
Надеюсь, это поможет
источник