Używając Google Geocoder v3, jeśli spróbuję geokodować 20 adresów, otrzymam OVER_QUERY_LIMIT, chyba że ustawię je w odstępie około 1 sekundy, ale wtedy zajmuje to 20 sekund, zanim wszystkie moje znaczniki zostaną umieszczone.
Czy jest na to inny sposób niż wcześniejsze zapisanie współrzędnych?
javascript
geocoding
google-maps
Michiel van Oosterhout
źródło
źródło
Odpowiedzi:
Nie, tak naprawdę nie ma innego wyjścia: jeśli masz wiele lokalizacji i chcesz je wyświetlić na mapie, najlepszym rozwiązaniem jest:
Wynika to oczywiście z faktu, że tworzenie / modyfikowanie lokalizacji jest o wiele mniejsze niż w przypadku konsultacji lokalizacji.
Tak, oznacza to, że będziesz musiał wykonać trochę więcej pracy podczas zapisywania lokalizacji - ale oznacza to również:
źródło
W rzeczywistości nie musisz czekać pełnej sekundy na każde żądanie. Zauważyłem, że jeśli czekam 200 milisekund między każdym żądaniem, jestem w stanie uniknąć odpowiedzi OVER_QUERY_LIMIT, a wrażenia użytkownika są zadowalające. Dzięki takiemu rozwiązaniu załadujesz 20 pozycji w 4 sekundy.
$(items).each(function(i, item){ setTimeout(function(){ geoLocate("my address", function(myLatlng){ ... }); }, 200 * i); }
źródło
setInterval
na liczbie potrzebnych żądań, zamiastsetTimeout
i ustawić to na100
- na wypadek, gdyby kwota adresu w przyszłości zwiększyła tę20
kwotę.Niestety jest to ograniczenie usługi map Google.
Obecnie pracuję nad aplikacją korzystającą z funkcji geokodowania i zapisuję każdy unikalny adres dla każdego użytkownika. Generuję informacje adresowe (miasto, ulica, województwo itp.) Na podstawie informacji zwracanych przez mapy Google, a następnie zapisuję również informacje o długości i szerokości geograficznej w bazie danych. Zapobiega to konieczności ponownego kodowania i zapewnia ładnie sformatowane adresy.
Innym powodem, dla którego chcesz to zrobić, jest dzienny limit liczby adresów, które można geokodować z określonego adresu IP. Nie chcesz, aby Twoja aplikacja została odrzucona przez osobę z tego powodu.
źródło
Mam ten sam problem, próbując geokodować 140 adresów.
Moim rozwiązaniem było dodanie usleep (100000) dla każdej pętli następnego żądania geokodowania. Jeśli status żądania to OVER_QUERY_LIMIT, uśpienie jest zwiększane o 50000 i żądanie jest powtarzane i tak dalej.
I dlatego wszystkie otrzymane dane (szerokość / długość) są przechowywane w pliku XML, aby nie uruchamiać żądania za każdym razem, gdy strona się ładuje.
źródło
EDYTOWAĆ:
Zapomniałem powiedzieć, że to rozwiązanie jest w czystym js, jedyne, czego potrzebujesz, to przeglądarka obsługująca obietnice https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
Dla tych, którzy wciąż muszą to osiągnąć, napisałem własne rozwiązanie, które łączy obietnice z limitami czasu.
Kod:
/* 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); } }); } };
Zwróć uwagę, że to tylko część większej biblioteki, którą napisałem do obsługi map Google, dlatego komentarze mogą być mylące.
Użycie jest dość proste, jednak podejście jest nieco inne: zamiast zapętlać i rozwiązywać jeden adres na raz, będziesz musiał przekazać do klasy tablicę adresów, która sama obsłuży wyszukiwanie, zwracając obietnicę, która , po rozwiązaniu, zwraca tablicę zawierającą cały rozwiązany (i nierozwiązany) adres.
Przykład:
var myAmazingGeo = new Geolocalizer(); var locations = ["Italy","California","Dragons are thugs...","China","Georgia"]; myAmazingGeo.Localize(locations).then(function(res){ console.log(res); });
Wyjście konsoli:
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
Obiekt zwrócony:
Cała magia dzieje się tutaj:
(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);
Zasadniczo zapętla każdy element z opóźnieniem 750 milisekund między każdym z nich, stąd co 750 milisekund adres jest kontrolowany.
Wykonałem kilka dalszych testów i odkryłem, że nawet po 700 milisekundach czasami otrzymywałem błąd QUERY_LIMIT, podczas gdy przy 750 nie miałem żadnego problemu.
W każdym razie możesz edytować powyższe 750, jeśli uważasz, że jesteś bezpieczny, obsługując mniejsze opóźnienie.
Mam nadzieję, że to pomoże komuś w najbliższej przyszłości;)
źródło
Właśnie przetestowałem Google Geocoder i mam ten sam problem, co ty. Zauważyłem, że otrzymuję status OVER_QUERY_LIMIT tylko raz na 12 żądań, więc czekam 1 sekundę (to jest minimalne opóźnienie oczekiwania) Spowalnia aplikację, ale mniej niż 1 sekundę na każde żądanie
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 }
W przypadku podstawowej metody holdOn:
private void holdOn(long delay) { try { Thread.sleep(delay); } catch (InterruptedException ex) { // ignore } }
Mam nadzieję, że to pomoże
źródło