34 votos

¿Evitar el límite de geocodificación de Google Maps?

Estoy creando un mapa de google personalizado que tiene 125 marcadores trazados a través de un cms. Al cargar el mapa me aparece este mensaje:

La geocodificación no ha tenido éxito por el siguiente motivo: OVER_QUERY_LIMIT

Estoy bastante seguro de que es la forma en que he geocodificado los marcadores.

¿Cómo puedo evitar estos avisos y hay una forma más eficaz de geocodificar los resultados?

ACTUALIZACIÓN: Este es mi intento de respuesta de Casey, de momento me sale una página en blanco.

<script type="text/javascript"> 
(function() { 

window.onload = function() { 
 var mc;
// Creating an object literal containing the properties we want to pass to the map 
var options = { 
zoom: 10, 
center: new google.maps.LatLng(52.40, -3.61), 
mapTypeId: google.maps.MapTypeId.ROADMAP 
}; 

// Creating the map 
var map = new google.maps.Map(document.getElementById('map'), options); 

// Creating a LatLngBounds object 
var bounds = new google.maps.LatLngBounds(); 

// Creating an array that will contain the addresses 
var places = []; 

// Creating a variable that will hold the InfoWindow object 
var infowindow; 
mc = new MarkerClusterer(map);
<?php
$pages = get_pages(array('child_of' => $post->ID, 'sort_column' => 'menu_order'));
$popup_content = array();
foreach($pages as $post)
    {
    setup_postdata($post);
    $fields = get_fields(); 
    $popup_content[] = '<p>'.$fields->company_name.'</p><img src="'.$fields->company_logo.'" /><br /><br /><a href="'.get_page_link($post->ID).'">View profile</a>';
    $comma = ", ";
    $full_address = "{$fields->address_line_1}{$comma}{$fields->address_line_2}{$comma}{$fields->address_line_3}{$comma}{$fields->post_code}";
    $address[] = $full_address;
    }
wp_reset_query();
echo 'var popup_content = ' . json_encode($popup_content) . ';';
echo 'var address = ' . json_encode($address) . ';';
?>

var geocoder = new google.maps.Geocoder(); 

var markers = [];

// Adding a LatLng object for each city  
for (var i = 0; i < address.length; i++) { 
    (function(i) { 
        geocoder.geocode( {'address': address[i]}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                places[i] = results[0].geometry.location;

                // Adding the markers 
                var marker = new google.maps.Marker({position: places[i], map: map});
                markers.push(marker);
                mc.addMarker(marker);

                // Creating the event listener. It now has access to the values of i and marker as they were during its creation
                google.maps.event.addListener(marker, 'click', function() {
                    // Check to see if we already have an InfoWindow
                    if (!infowindow) {
                        infowindow = new google.maps.InfoWindow();
                    }

                    // Setting the content of the InfoWindow
                    infowindow.setContent(popup_content[i]);

                    // Tying the InfoWindow to the marker 
                    infowindow.open(map, marker);
                });

                // Extending the bounds object with each LatLng 
                bounds.extend(places[i]); 

                // Adjusting the map to new bounding box 
                map.fitBounds(bounds) 
            } else { 
            alert("Geocode was not successful for the following reason: " + status); 
            }

        });

    })(i);

} 
var markerCluster = new MarkerClusterer(map, markers); 
} 
})
(); 
</script> 

No importa realmente cuál sea la solución, siempre que los marcadores se carguen al instante y no se incumplan los términos y condiciones.

58voto

FlySwat Puntos 61945

Como todo el mundo, podría darte una respuesta con código, pero no creo que nadie te haya explicado que estás haciendo algo que es fundamentalmente erróneo .

¿Por qué se produce este error? Porque estás llamando a geocode cada vez que alguien ve tu página y no estás almacenando los resultados en ninguna parte de la base de datos.

La razón por la que existe ese límite es para evitar el abuso de los recursos de Google (ya sea de forma voluntaria o involuntaria), que es exactamente lo que estás haciendo :)

Aunque el geocódigo de google es rápido, si todo el mundo lo usara así, se les caerían los servidores. La razón por la que existe Google Fusion Tables es para hacer gran parte del trabajo pesado del lado del servidor por ti. La geocodificación y el almacenamiento en caché de los mosaicos se realizan en sus servidores. Si no quieres usar eso, entonces debes cachearlos en tu servidor.

Si aún así, 2500 solicitudes al día es demasiado poco, entonces usted tiene que mirar a Google Maps Premier (de pago) licencia que le da 100.000 solicitudes de geocodificación por día para algo alrededor de 10k un año (que es mucho - con el almacenamiento en caché del lado del servidor no debe ser llegar a este límite a menos que usted es algunos enorme o están haciendo un fuerte procesamiento de datos). Sin el almacenamiento en caché del lado del servidor y utilizando su enfoque actual, ¡sólo podría hacer 800 páginas vistas al día!

Una vez que te das cuenta de que otros proveedores cobran por geocódigo entenderás que debes almacenar en caché los resultados en la db. ¡Con este enfoque le costaría unos 10 céntimos de dólar por página vista!

La pregunta es: ¿se puede trabajar alrededor del límite de aceleración que da Google? Claro, sólo tienes que hacer una solicitud desde diferentes direcciones IP. Heck, usted podría proxy de las llamadas a través de amazon ips elástica y siempre tendría un nuevo fresco 2500 llamadas asignadas. Pero por supuesto, además de ser ilegal (estás eludiendo efectivamente la restricción que te dan los términos de servicio de Google Maps), estarías haciendo un hack para cubrir el defecto de diseño inherente que tienes en tu sistema.

Entonces, ¿cuál es la forma correcta para ese caso de uso? Antes de llamar a la api de geocódigo de google, envíalo a tu servidor y consulta si está en tu caché. Si no lo está, llama al geocódigo, almacénalo en tu caché y devuelve el resultado.

Hay otros enfoques, pero esto debería servir para empezar en la dirección correcta.

Actualización: Por tus comentarios, dice que estás usando PHP, así que aquí tienes un ejemplo de código sobre cómo hacerlo correctamente (recomendación del propio equipo de Google) https://developers.google.com/maps/articles/phpsqlsearch_v3

14voto

Peter Mounce Puntos 506

Creo que Sasa tiene razón, en ambos aspectos.

En cuanto al envío de todas las direcciones a la vez, una opción es enviar las solicitudes a intervalos. En el pasado, al utilizar JavaScript, he optado por retrasar las solicitudes en 0,25 (¡parece que funciona!) segundos utilizando la función

setTimeout( [FUNCTION CALL] , 250 )

método.

En .NET he optado por:

System.Threading.Thread.Sleep(250);

Parece que funciona.

EDIT: No puedo probarlo, pero esto debería/puede funcionar.

Ejemplo de Javascript. El addressArray contiene cadenas que son direcciones...

for (var i = 0; i < addressArray.length; i++0 
{

setTimeout('googleGeocodingFunction(' + addressArray[i] + ')' , 250);

}

EDITAR:

for (var i = 0; i < address.length; i++) {
    function(i) {
        setTimeout(geocoder.geocode({ 'address': address[i] }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                places[i] = results[0].geometry.location;

                var marker = new google.maps.Marker({ position: places[i], map: map });
                markers.push(marker);
                mc.addMarker(marker);
                google.maps.event.addListener(marker, 'click', function() {
                    if (!infowindow) {
                        infowindow = new google.maps.InfoWindow();
                    }

                    // Setting the content of the InfoWindow
                    infowindow.setContent(popup_content[i]);

                    // Tying the InfoWindow to the marker 
                    infowindow.open(map, marker);
                });

                // Extending the bounds object with all coordinates 
                bounds.extend(places[i]);

                // Adjusting the map to new bounding box 
                map.fitBounds(bounds)
            } else {
                alert("Geocode was not successful for the following reason: " + status);
            }
        }), 250);// End of setTimeOut Function - 250 being a quarter of a second. 
    } 
}

9voto

Jason Z Puntos 111

Parece que estás alcanzando el límite de solicitudes simultáneas impuesto por Google (aunque no encuentro una referencia a cuál es el límite realmente). Tendrás que espaciar las solicitudes para no enviar 125 solicitudes de una sola vez. Ten en cuenta que también hay un límite de 2500 solicitudes de geocódigos por día.

Consulte el Estrategias de geocodificación de Google para más información.

Actualización: Como solución añadida, inspirada en un post de Mapperz, podrías pensar en crear un nuevo Tabla de Google Fusion El sistema de gestión de la información de la UE se basa en el principio de la "gestión de la información", que consiste en almacenar la dirección y los datos relacionados con ella en la tabla, y en geocodificar la tabla a través de su interfaz web. Hay un límite en el número de solicitudes de geocodificación que puede hacer una tabla Fusion, pero el límite es bastante grande. Una vez alcanzado el límite, deberá volver a enviar la solicitud de geocodificación, y Fusion Tables la retomará donde la dejó. La bonificación de este enfoque es una enorme mejora de la velocidad, ya que sólo tendrá que geocodificar una vez, mientras que con su solución actual tendrá que geocodificar en cada carga, alcanzando rápidamente los límites diarios.

7voto

buti-oxa Puntos 6428

Así es como acelero mis peticiones de geocodificación en javascript, siendo las direcciones un array que contiene cada dirección a geocodificar:

for (i=0;i<=addresses.length;i++) {
    setTimeout( function () {
            geocoder.geocode( { 'address': addresses[i]}, function(results, status) {

                if (status == google.maps.GeocoderStatus.OK) { 

                    //create and add marker to map based off geocode result
                    var marker = new google.maps.Marker({  
                        map: map,
                        title: results[0].formatted_address,
                        position: results[0].geometry.location
                    });

                 } //EDIT, was missing the closing bracket here
            });

    }, i * 1500);
}

Esto añade esencialmente un segundo y medio entre cada solicitud de geocodificación.

5voto

Celso Puntos 66

He probado la página ahora y parece que funciona ahora mismo .

Si bien creo que el enfoque del temporizador que está utilizando actualmente es correcto y, por lo que sé, el único que funcionará sin requerir algún apoyo del lado del servidor, debo sugerir los siguientes cambios (me tomé la libertad de reescribir sus funciones de geocodificación) para aprovechar localStorage .

LocalStorage es una tecnología relativamente nueva integrada en la mayoría de los navegadores que permite a la página web almacenar datos en el cliente. Es algo similar a las cookies, pero es mucho más potente y no siempre se reenvía al servidor (a diferencia de las cookies).

Mi objetivo es guardar la dirección geocodificada en el cliente para que si un usuario refresca la página no sea necesario volver a invocar las funciones de geocodificación de Google sobre él. La implementación de abajo es rudimentaria (habría que añadir código para comprobar si hay registros antiguos y probablemente se necesite una clave de caché mejor que la del índice) pero debería ser suficiente para empezar. Espero que te sirva de ayuda.

(function() { 

window.onload = function() { 
 var mc;
// Creating an object literal containing the properties we want to pass to the map 
var options = { 
zoom: 0, maxZoom: 0, 
center: new google.maps.LatLng(52.40, -3.61), 
mapTypeId: google.maps.MapTypeId.ROADMAP 
}; 

// Creating the map 
var map = new google.maps.Map(document.getElementById('map'), options); 

// Creating a LatLngBounds object 
var bounds = new google.maps.LatLngBounds(); 

// Creating an array that will contain the addresses 
var places = []; 

// Creating a variable that will hold the InfoWindow object 
var infowindow; 
mc = new MarkerClusterer(map);
var popup_content = [..redacted..];

var geocoder = new google.maps.Geocoder(); 

var markers = [];

// Adding a LatLng object for each city 
function geocodeAddress(i) {
     // check if localStorage is available (it is now available on most modern browsers)
     // http://html5tutorial.net/tutorials/working-with-html5-localstorage.html
     // NB: this *must* be improved to handle quota limits, age/freshness, etc
     if(localStorage && localStorage['address_'+i]) {
        places[i]=JSON.parse(localStorage['address_'+i]);
        addPlace(i);
     } else {
      geocoder.geocode( {'address': address[i]}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            places[i] = results[0].geometry.location;
            if(localStorage) {
               // cache result locally on the browser, this will help reducing the number of requests
               // to the google geocoder in case the user refreshes the page
               // remember: the more he will refresh, the more he's likely to hit the limit
               // (this is one case where refreshing or closing the browser does not work)
               localStorage['address_'+i]=JSON.stringify(results[0].geometry.location);
            }

            addPlace(i);
        } else { 
            console.log("Geocoding of address "+address[i]+" failed");
        }
    })
}

function addPlace(i) {
    // Adding the markers 
    var marker = new google.maps.Marker({position: places[i], map: map});
    markers.push(marker);
    mc.addMarker(marker);

    // Creating the event listener. It now has access to the values of i and marker as they were during its creation
    google.maps.event.addListener(marker, 'click', function() {
        // Check to see if we already have an InfoWindow
        if (!infowindow) {
            infowindow = new google.maps.InfoWindow();
        }

        // Setting the content of the InfoWindow
        infowindow.setContent(popup_content[i]);

        // Tying the InfoWindow to the marker 
        infowindow.open(map, marker);
    });

    // Extending the bounds object with each LatLng 
    bounds.extend(places[i]); 

    // Adjusting the map to new bounding box 
    map.fitBounds(bounds);
}

function geocode() {
    if (geoIndex < address.length) {
        geocodeAddress(geoIndex);
        ++geoIndex;
    }
    else {
        clearInterval(geoTimer);
    }
}
var geoIndex = 0;
var geoTimer = setInterval(geocode, 600);  // 200 milliseconds (to try out)

var markerCluster = new MarkerClusterer(map, markers); 
} 
})
();

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X