Bir OVER_QUERY_LIMIT yanıtı almadan 20 adresi nasıl Coğrafi olarak kodlayabilirim?


87

Google Geocoder v3'ü kullanarak, 20 adresin coğrafi kodlamasını yapmaya çalışırsam, arayla ~ 1 saniye ara vermedikçe bir OVER_QUERY_LIMIT alırım, ancak işaretçilerimin yerleştirilmesi 20 saniye sürer.

Koordinatları önceden kaydetmekten başka bunu yapmanın başka bir yolu var mı?


hala durum bu mu? Belgelerde gördüğüm tek kısıtlama: "günde 2.500 coğrafi konum isteği sorgu sınırı". code.google.com/apis/maps/documentation/geocoding/…
russau

6
Bu, günlük kullanıcı başına toplam sorgu miktarı ile ilgili değil, bir döngüde sorgulama yaparken olduğu gibi, kısa sürede yapılan sorgu sayısı ile ilgilidir.
Michiel van Oosterhout

Mağazamızda bir işletme lisansımız var ve hala saniyede 10'dan fazla isteği karşılayamama sorunuyla karşılaşıyoruz. Bir işletme lisansı ile normal bir geliştirici arasındaki tek fark, günlük 100.000 çağrı sınırına sahip olmamızdır.
abhi

@michielvoo Bunu çözdün mü? Cevabınız evet ise, lütfen bana yardım edin. OVER_QUERY_LIMIT alıyorum. SO'daki sorum . Fiddle
Prabs

Yanıtlar:


85

Hayır, gerçekten başka bir yol yok: Çok sayıda konumunuz varsa ve bunları bir haritada görüntülemek istiyorsanız, en iyi çözüm şudur:

  • bir konum oluşturulduğunda coğrafi kodlayıcıyı kullanarak enlem + boylamı getirin
  • bunları veritabanınızda adresin yanında saklayın
  • ve haritayı görüntülemek istediğinizde kayıtlı enlem + boylamı kullanın.

Bu, elbette, konumlarla ilgili danışmalarınız olduğundan çok daha az yer yaratma / değiştirmeye sahip olduğunuz düşünülür.


Evet, konumları kaydederken biraz daha fazla iş yapmanız gerektiği anlamına gelir - ancak aynı zamanda şu anlama da gelir:

  • Coğrafi koordinatlara göre arama yapabileceksiniz
    • ör. " Şu anda bulunduğum yere yakın noktaların bir listesini istiyorum "
  • Haritayı görüntülemek çok daha hızlı olacak
    • Üzerinde 20'den fazla konum olsa bile
  • Oh, ayrıca (sonuncu ama en az değil) : bu işe yarayacak ;-)
    • N saniye içinde X coğrafi kodlayıcı çağrısı sınırına daha az ulaşacaksınız.
    • Ve günlük Y geocoder çağrısı sınırına daha az ulaşacaksınız.

Bir süre geçtikten sonra sonuçların doğru olduğundan nasıl emin olabileceğinizi merak ediyorum (diyelim ki bir ay). Onları arada bir yeniden sorguluyor musunuz?
Chris

2
Adres (zaten DB'nizde bulunan - aksi takdirde coğrafi kodlama yapamazsınız) değişmezse, enlem / boylamın değişmesi ihtimali oldukça düşüktür. Ve elbette, adres her değiştirildiğinde, yeni adrese karşılık gelen enlem + boylamı elde etmek için coğrafi kodlayıcıyı yeniden sorgulamalısınız.
Pascal MARTIN

Enlem / boylam değerini DB'ye depoladım ve AJAX aracılığıyla DB'den bir dizi olarak geri aldım, ancak daha sonra bir java betiği döngüsüne tekrar geçmesi gerekiyor, daha çok DB'den 173 konum aldım. Şimdi bana aynı OVER_QUERY_LIMIT durumunu gösteriyor. Lütfen tavsiye ...
Prabhu M

20

Aslında her istek için tam bir saniye beklemenize gerek yoktur. Her istek arasında 200 milisaniye beklersem OVER_QUERY_LIMIT yanıtından kaçınabileceğimi ve kullanıcı deneyiminin fena olmadığını anladım. Bu çözümle 20 öğeyi 4 saniyede yükleyebilirsiniz.

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

  setTimeout(function(){

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

  }, 200 * i);

}

5
ancak (200 * i), her istek arasındaki duraklamanın arttığı anlamına gelir. Yani 3. istek üzerine 600, sonra 800 vb.
Roman

sadece "* i"
Chris

9
setTimeout onu bir kez çalıştıracaktır. Yani eğer haklıysam, (..., 200 * i) her aramayı 200 ms ile ayrılmış olarak planlayacaktır (oyatek'in söylediği gibi), gabeodess'in başarmak istediği şey buydu. Akım (..., 200) hepsini 200ms sonra aynı anda çalıştıracaktır. Yoksa bir şey mi kaçırıyorum?
lepe

@gabeodess - adres miktarının ileride miktarı artırması ihtimaline karşı setInterval, gerekli isteklerin sayısı yerine yapmanız setTimeoutve bunu ayarlamanız gerekir . 10020
Rob Scott

3
@gabeodess Çözümünüzü denedim ama hala OVER_QUERY_LIMIT Fiddle
Prabs

6

Maalesef bu, Google haritalar hizmetinin bir kısıtlamasıdır.

Şu anda coğrafi kodlama özelliğini kullanan bir uygulama üzerinde çalışıyorum ve her benzersiz adresi kullanıcı bazında kaydediyorum. Adres bilgilerini (şehir, cadde, eyalet vb.) Google haritalarının döndürdüğü bilgilere göre oluşturuyor ve ardından enlem / boylam bilgilerini veritabanına kaydediyorum. Bu, bir şeyleri yeniden kodlamak zorunda kalmanızı önler ve size güzel biçimlendirilmiş adresler verir.

Bunu yapmak istemenizin diğer bir nedeni, belirli bir IP adresinden coğrafi kodlama yapılabilecek adreslerin sayısında günlük bir sınır olmasıdır. Başvurunuzun bu nedenle bir kişi için başarısız olmasını istemezsiniz.


2

140 adresi coğrafi kodlamaya çalışırken aynı sorunla karşılaşıyorum.

Benim geçici çözüm ekleyerek oldu usleep (100000) sonraki coğrafi kodlama isteğinin her döngü için. İsteğin durumu OVER_QUERY_LIMIT ise, usleep 50000 artırılır ve istek tekrarlanır ve bu böyle devam eder.

Ve bu nedenle, alınan tüm veriler (enlem / boylam) XML dosyasında saklanır ve sayfa her yüklendiğinde isteği çalıştırmaz.


1
Cevabınız belirsiz, sunucu tarafından mı bahsediyorsunuz yoksa bu javascript, ikincisi ise usleep bir işlev değildir ve bu nedenle yanlış olur, eğer eski ise cevabınızı bunu açıkça belirtmek için değiştirmenizi öneririm belirsizliği önlemek için sunucu tarafıdır.
t0mm13b

1

DÜZENLE:

Bu çözümün saf js'de olduğunu söylemeyi unuttum, ihtiyacınız olan tek şey vaatleri destekleyen bir tarayıcıdır https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise


Hala bunu başarması gerekenler için, vaatleri zaman aşımlarıyla birleştiren kendi çözümümü yazdım.

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

Lütfen bunun, google haritalar işlerini halletmek için yazdığım daha büyük bir kitaplığın bir parçası olduğunu unutmayın, bu nedenle yorumlar kafa karıştırıcı olabilir.

Kullanım oldukça basittir, ancak yaklaşım biraz farklıdır: her seferinde bir adresi döngülemek ve çözmek yerine, sınıfa bir dizi adres iletmeniz gerekecek ve aramayı kendi başına halledecek ve bir söz verecektir. , çözümlendiğinde, tüm çözümlenmiş (ve çözümlenmemiş) adresleri içeren bir dizi döndürür.

Misal:

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

Konsol çıkışı:

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

Döndürülen nesne:

görüntü açıklamasını buraya girin

Bütün sihir burada gerçekleşir:

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

Temel olarak, her bir öğeyi aralarında 750 milisaniye gecikmeyle döngüler, dolayısıyla her 750 milisaniyede bir adres kontrol edilir.

Daha fazla test yaptım ve 700 milisaniyede bile bazen QUERY_LIMIT hatası aldığımı, 750 ile ise hiç sorun yaşamadığımı öğrendim.

Her durumda, daha düşük bir gecikmeyle kendinizi güvende hissediyorsanız yukarıdaki 750'yi düzenlemekten çekinmeyin.

Umarım bu yakın gelecekte birine yardımcı olur;)


0

Google Geocoder'ı yeni test ettim ve seninle aynı sorunu yaşadım. OVER_QUERY_LIMIT durumunu yalnızca her 12 istekte bir kez aldığımı fark ettim, bu yüzden 1 saniye bekliyorum (bu, beklemek için minimum gecikme) Uygulamayı yavaşlatıyor, ancak her istekte 1 saniye beklemekten daha az

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
}

Temel holdOn yöntemiyle:

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

Umarım yardımcı olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.