En geocode
función en PostGIS tigre geocoder extensión tienen un ejemplo de geocodificación por lotes que parece ser utilizado por muchas personas. Sin embargo no estoy seguro si el comportamiento de este ejemplo que observé es intencional.
UPDATE addresses_to_geocode SET (rating, new_address, lon, lat) = ( COALESCE((g.geo).rating,-1), pprint_addy((g.geo).addy), ST_X((g.geo).geomout)::numeric(8,5), ST_Y((g.geo).geomout)::numeric(8,5) ) FROM (SELECT addid FROM addresses_to_geocode WHERE rating IS NULL ORDER BY addid LIMIT 3) As a LEFT JOIN (SELECT addid, (geocode(address,1)) As geo FROM addresses_to_geocode As ag WHERE ag.rating IS NULL ORDER BY addid LIMIT 3) As g ON a.addid = g.addid WHERE a.addid = addresses_to_geocode.addid;
El código de ejemplo se suponía que sólo geocodificar 3 direcciones que no ser geocodificado luego actualizar la tabla. Así que usted puede ejecutar este código una y otra vez, cada vez que se actualizará 3 filas.
Con una tabla de 10 direcciones, el código de ejemplo necesita 18 segundos para ejecutarse (sabía que el rendimiento en mi configuración no es bueno, solía ser mucho mejor cuando sólo tenía datos de 3 estados en SSD. Ahora tengo 100G de datos en un disco duro normal y es mucho más lento), y 10 segundos en la segunda ejecución.
Con una tabla de 20 direcciones, necesita 45 s para ejecutarse, 40 s para la 2ª ejecución. Con una tabla de 500 direcciones, sigue funcionando antes de que lo cancele.
Esto me hace creer que el código de ejemplo en realidad geocodifica primero todas las filas de la tabla y luego elige los 3 primeros resultados para actualizar la tabla.
He observado este tipo de comportamiento antes con limit
:
SELECT geocode(address_string,1) FROM address_sample LIMIT 4;
tardará mucho más tiempo si la mesa es grande. Mientras que esta línea siempre utiliza un tiempo similar sin importar el tamaño de la tabla:
SELECT geocode(sample.address_string, 1)
FROM (SELECT address_string FROM address_sample LIMIT 4) as sample;
Así que he modificado el código de ejemplo en esto:
UPDATE address_table SET (rating, output_address, lon, lat, geomout) = ( COALESCE((a.geo).rating,-1), pprint_addy((a.geo).addy), ST_X((a.geo).geomout)::numeric(8,5), ST_Y((a.geo).geomout)::numeric(8,5), (a.geo).geomout) FROM (SELECT sample.addid, geocode(sample.input_address,1) as geo from (select addid, input_address from address_table WHERE rating IS NULL ORDER BY addid LIMIT 3) as sample ) as a WHERE a.addid = address_table.addid;
Ahora siempre se ejecuta en 5 segundos sin importar el tamaño de la tabla. Sin embargo, hay un nuevo problema: la primera fila de mi tabla es una dirección incorrecta. El código original asignará la calificación como -1 cuando no pueda encontrar una coincidencia, entonces las ejecuciones posteriores omitirán esta dirección mala. Mi versión modificada no actualizó la columna de calificación como -1, por lo que cada ejecución intentará geocodificarla y saltársela.
En resumen, en realidad tengo dos preguntas:
-
¿Es intencionado el comportamiento que he observado en el código de ejemplo? El documento dice
para un gran número de direcciones que no desea actualizar todas a la vez, ya que todo el geocódigo debe confirmarse a la vez.
No estoy seguro de lo que esto significa. Si siempre geocodifica toda la tabla, ¿por qué limita la salida?
- ¿Cómo hacer que mi versión modificada establezca la columna de calificación de la dirección incorrecta como -1?
EDIT: He resuelto mi segunda pregunta.
En LEFT JOIN
en el código de ejemplo es necesario para devolver una tabla de resultados que con la mala calificación de dirección como -1. El nuevo código se ejecuta 3~4 segundos para 3 filas cada vez, sin importar el tamaño de la tabla.
UPDATE address_table SET (rating, output_address, lon, lat, geomout) = ( COALESCE((g.geo).rating,-1), pprint_addy((g.geo).addy), ST_X((g.geo).geomout)::numeric(8,5), ST_Y((g.geo).geomout)::numeric(8,5), (g.geo).geomout) FROM (select addid from address_table WHERE rating IS NULL ORDER BY addid LIMIT 3) as a left join (SELECT sample.addid, geocode(sample.input_address,1) as geo from (select addid, input_address from address_table WHERE rating IS NULL ORDER BY addid LIMIT 3) as sample ) as g on a.addid = g.addid WHERE a.addid = address_table.addid;
EDITAR 2 : He ejecutado los comandos de vacío siguiendo la sugerencia de @LR1234567. No mejoró el rendimiento general de geocodificación, pero el código de ejemplo ahora tienen un rendimiento similar con mi versión modificada. ¿Tal vez el uso en el código de ejemplo depende de la limpieza del esquema de tigre?
EDITAR 3 : El código de ejemplo sigue teniendo problemas. Mis datos tienen una dirección no válida (con código postal incompleto) en la primera fila. El código de ejemplo tardará una eternidad en ejecutarse si se inicia desde la primera fila, y ese tiempo está directamente relacionado con el tamaño de la tabla, 271 segundos para una tabla de 100 filas. Una vez procesada esta fila inválida y marcada como -1, el código de ejemplo puede procesar las filas normales en un tiempo razonable. Sin embargo mi código modificado puede procesar la fila inválida en 4 segundos.
La única diferencia entre el código de ejemplo y mi versión es que en la cláusula from, en lugar de en la cláusula where, hago un subconjunto de la tabla.
EDITAR4 Aquí están los resultados del análisis de las explicaciones que verificaron mi observación:
- El código de ejemplo se ejecuta en una tabla de 100 filas por primera vez, con la dirección de la primera fila inválida:
El primer paso del escaneado tarda 284 s para 99 filas de geocodificación
el segundo paso de limitar a 3 filas ocurrió después, demasiado tarde
- Mi código modificado para la misma tabla:
El primer paso de la geocodificación sólo procesó 3 filas
el segundo paso del límite en realidad tienen el mismo tiempo de inicio y final de la primera etapa, por lo que se produjeron juntos
- Una vez marcada la primera fila de direcciones no válidas con -1, ejecute de nuevo el código de ejemplo para las demás filas:
las filas se limitaron antes de la geocodificación
Así que esto podría ser algo relacionado con cómo PostgreSQL planificación de la consulta si hay una fila no válida. Tal vez las otras personas no tenían la fila inválida en la parte superior entonces no encontraron este problema. Ordené mi dirección de entrada por código postal para que la fila no válida apareciera en la parte superior.