Bagaimana cara Geocode 20 alamat tanpa menerima tanggapan OVER_QUERY_LIMIT?

87

Dengan menggunakan Google Geocoder v3, jika saya mencoba untuk membuat geocode 20 alamat, saya mendapatkan OVER_QUERY_LIMIT kecuali saya mengatur waktunya dengan jarak ~ 1 detik, tetapi kemudian butuh waktu 20 detik sebelum semua penanda saya ditempatkan.

Apakah ada cara lain untuk melakukannya, selain menyimpan koordinat terlebih dahulu?

Michiel van Oosterhout
sumber
apakah ini masih terjadi? Satu-satunya batasan yang saya lihat dalam dokumentasi adalah: "batas kueri 2.500 permintaan geolokasi per hari". code.google.com/apis/maps/documentation/geocoding/…
russau
6
Ini bukan tentang jumlah total kueri per pengguna per hari, ini tentang jumlah kueri dalam waktu singkat, seperti saat membuat kueri dalam satu putaran.
Michiel van Oosterhout
Kami memiliki izin usaha di toko kami dan kami masih mengalami masalah ini karena tidak dapat menangani lebih dari 10 permintaan per detik. Satu-satunya perbedaan antara izin usaha dan pengembang biasa adalah bahwa kami memiliki batas 100.000 panggilan per hari.
abhi
@michielvoo Sudahkah Anda memecahkan masalah ini? Jika ya, tolong bantu saya. Saya mendapatkan OVER_QUERY_LIMIT. Pertanyaan saya di SO. Fiddle
Prabs

Jawaban:

85

Tidak, sebenarnya tidak ada cara lain: jika Anda memiliki banyak lokasi dan ingin menampilkannya di peta, solusi terbaik adalah:

  • ambil garis lintang + bujur, menggunakan geocoder, saat lokasi dibuat
  • simpan itu di database Anda, di samping alamat
  • dan gunakan lintang + bujur yang disimpan saat Anda ingin menampilkan peta.

Ini, tentu saja, mengingat Anda memiliki lebih sedikit pembuatan / modifikasi lokasi daripada Anda memiliki konsultasi lokasi.


Ya, itu berarti Anda harus melakukan lebih banyak pekerjaan saat menyimpan lokasi - tetapi itu juga berarti:

  • Anda dapat mencari berdasarkan koordinat geografis
    • yaitu " Saya ingin daftar titik yang dekat dengan tempat saya sekarang "
  • Menampilkan peta akan jauh lebih cepat
    • Bahkan dengan lebih dari 20 lokasi di atasnya
  • Oh, dan, juga (terakhir tapi tidak kalah pentingnya) : ini akan berhasil ;-)
    • Anda kemungkinan kecil akan mencapai batas panggilan geocoder X dalam N detik.
    • Dan Anda kemungkinan besar tidak akan mencapai batas panggilan geocoder Y per hari.
Pascal MARTIN
sumber
Saya ingin tahu bagaimana Anda bisa yakin bahwa hasilnya benar setelah beberapa waktu berlalu (katakanlah, sebulan). Apakah Anda sesekali menanyakannya kembali?
Chris
2
Jika alamat (yang sudah Anda miliki di DB - jika tidak, Anda tidak akan dapat melakukan geocode) tidak berubah, kemungkinan besar lintang / bujur harus berubah. Dan, tentu saja, setiap kali alamat diubah, Anda harus menanyakan kembali geocoder, untuk mendapatkan garis lintang + bujur yang sesuai dengan alamat baru.
Pascal MARTIN
Saya telah menyimpan lat / long ke dalam DB dan mengambilnya dari DB melalui AJAX sebagai sebuah array, tetapi kemudian harus diteruskan lagi ke loop java script, terlebih lagi saya telah menerima 173 lokasi dari DB. Sekarang ini menunjukkan kepada saya status OVER_QUERY_LIMIT yang sama. Mohon saran ...
Prabhu M
20

Anda sebenarnya tidak perlu menunggu satu detik penuh untuk setiap permintaan. Saya menemukan bahwa jika saya menunggu 200 milidetik di antara setiap permintaan, saya dapat menghindari tanggapan OVER_QUERY_LIMIT dan pengalaman pengguna lumayan. Dengan solusi ini Anda dapat memuat 20 item dalam 4 detik.

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

  setTimeout(function(){

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

  }, 200 * i);

}
kecerdikan
sumber
5
tapi (200 * i) berarti jeda antara setiap permintaan meningkat. Jadi pada permintaan ketiga adalah 600, lalu 800 dll.
Roman
hapus saja '* i'
Chris
9
setTimeout akan menjalankannya sekali. Jadi jika saya benar, (..., 200 * i) akan menjadwalkan setiap panggilan dipisahkan oleh 200ms (seperti komentar oyatek), yang ingin dicapai oleh kecerdikan. Arus (..., 200) akan mengeksekusi semuanya pada waktu yang sama setelah 200ms. Atau apakah saya melewatkan sesuatu?
lepe
@gabeodess - Anda harus melakukan setIntervaljumlah permintaan yang diperlukan, bukan setTimeout, dan menyetelnya ke 100- untuk berjaga-jaga jika jumlah alamat suatu saat nanti akan menambah 20jumlahnya.
Rob Scott
3
@gabeodess Saya sudah mencoba solusi Anda tetapi masih mendapatkan OVER_QUERY_LIMIT Fiddle
Prabs
6

Sayangnya ini adalah batasan dari layanan peta Google.

Saat ini saya sedang mengerjakan aplikasi yang menggunakan fitur geocoding, dan saya menyimpan setiap alamat unik per pengguna. Saya menghasilkan informasi alamat (kota, jalan, negara bagian, dll) berdasarkan informasi yang dikembalikan oleh peta Google, dan kemudian menyimpan informasi lintang / bujur di database juga. Ini mencegah Anda dari keharusan untuk membuat kode ulang, dan memberi Anda alamat yang diformat dengan baik.

Alasan lain Anda ingin melakukan ini adalah karena ada batasan harian pada jumlah alamat yang dapat di-geocode dari alamat IP tertentu. Anda tidak ingin lamaran Anda gagal untuk seseorang karena alasan itu.

Zachary Wright
sumber
2

Saya menghadapi masalah yang sama saat mencoba geocode 140 alamat.

Solusi saya adalah menambahkan usleep (100000) untuk setiap loop permintaan geocoding berikutnya. Jika status permintaan OVER_QUERY_LIMIT, usleep ditingkatkan 50000 dan permintaan diulang, dan seterusnya.

Dan karena itu semua data yang diterima (lat / long) disimpan dalam file XML agar tidak menjalankan request setiap kali halaman di-load.

Abu-abu
sumber
1
Jawaban Anda tidak jelas, apakah yang Anda maksud di sisi server atau javascript ini, jika yang terakhir, usleep bukan fungsi dan karenanya akan salah, jika yang pertama, maka saya sarankan Anda mengubah jawaban Anda untuk menyatakan ini secara eksplisit adalah sisi server untuk menghindari ambiguitas.
t0mm13b
1

EDIT:

Lupa mengatakan bahwa solusi ini murni js, satu-satunya hal yang Anda butuhkan adalah browser yang mendukung promise https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Bagi mereka yang masih perlu melakukannya, saya telah menulis solusi saya sendiri yang menggabungkan janji dengan batas waktu.

Kode:

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

Harap dicatat bahwa ini hanya bagian dari perpustakaan yang lebih besar yang saya tulis untuk menangani hal-hal peta google, maka komentar mungkin membingungkan.

Penggunaannya cukup sederhana, namun pendekatannya sedikit berbeda: alih-alih mengulang dan menyelesaikan satu alamat pada satu waktu, Anda perlu meneruskan array alamat ke kelas dan itu akan menangani pencarian dengan sendirinya, mengembalikan sebuah janji yang , ketika diselesaikan, mengembalikan larik yang berisi semua alamat yang diselesaikan (dan tidak terselesaikan).

Contoh:

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

Keluaran konsol:

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

Objek dikembalikan:

masukkan deskripsi gambar di sini

Seluruh keajaiban terjadi di sini:

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

Pada dasarnya, ini mengulang setiap item dengan penundaan 750 milidetik di antara mereka masing-masing, maka setiap 750 milidetik sebuah alamat dikendalikan.

Saya telah melakukan beberapa pengujian lebih lanjut dan saya menemukan bahwa bahkan pada 700 milidetik saya terkadang mendapatkan kesalahan QUERY_LIMIT, sedangkan dengan 750 saya tidak mengalami masalah sama sekali.

Bagaimanapun, silakan edit 750 di atas jika Anda merasa aman dengan menangani penundaan yang lebih rendah.

Semoga ini membantu seseorang dalam waktu dekat;)

briosheje
sumber
0

Saya baru saja menguji Google Geocoder dan mendapatkan masalah yang sama seperti Anda. Saya perhatikan saya hanya mendapatkan status OVER_QUERY_LIMIT sekali setiap 12 permintaan Jadi saya menunggu selama 1 detik (itu adalah penundaan minimum untuk menunggu) Ini memperlambat aplikasi tetapi kurang dari menunggu 1 detik setiap permintaan

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
}

Dengan metode holdOn dasar:

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

Semoga membantu

Pelukan
sumber