¿A qué velocidad debo esperar PostGIS para geocodificar bien-formato de direcciones?
He instalado PostgreSQL 9.3.7 y PostGIS 2.1.7, cargado de la nación de datos y todos los estados de los datos, pero se han encontrado geocodificación a ser mucho más lento de lo que yo esperaba. ¿Puedo fijar mis expectativas demasiado altas? Estoy recibiendo un promedio de 3 individuales geocodifica por segundo. Tengo que hacer cerca de 5 millones y no quiero esperar tres semanas para esto.
Esta es una máquina virtual para el procesamiento de gigante R matrices y he instalado esta base de datos en el lado de modo que la configuración puede parece un poco tonto. Si una alteración importante en la configuración de la máquina virtual de ayuda, puede modificar la configuración.
Especificaciones de Hardware
Memoria: 65GB
procesadores: 6
lscpu
me da esto:
# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 6
On-line CPU(s) list: 0-5
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 6
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 58
Stepping: 0
CPU MHz: 2400.000
BogoMIPS: 4800.00
Hypervisor vendor: VMware
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 30720K
NUMA node0 CPU(s): 0-5
Sistema operativo es centos, uname -rv
da esto:
# uname -rv
2.6.32-504.16.2.el6.x86_64 #1 SMP Wed Apr 22 06:48:29 UTC 2015
Postgresql config
> select version()
"PostgreSQL 9.3.7 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit"
> select PostGIS_Full_version()
POSTGIS="2.1.7 r13414" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.2, released 2012/10/08" LIBXML="2.7.6" LIBJSON="UNKNOWN" TOPOLOGY RASTER"
Basado en las sugerencias anteriores para estos tipos de consultas, he subido shared_buffers
en la postgresql.conf
de archivo de hasta 1/4 de la memoria RAM disponible y efectiva tamaño de la caché a 1/2 de la RAM:
shared_buffers = 16096MB
effective_cache_size = 31765MB
He installed_missing_indexes()
y (después de la resolución de duplicados se inserta en algunas tablas) no tiene ningún error.
Geocodificación de SQL ejemplo #1 (lote) ~ el tiempo medio es de 2,8/seg.
Estoy siguiendo el ejemplo de http://postgis.net/docs/Geocode.html, lo que me tiene crear una tabla que contiene la dirección de geocodificación y, a continuación, hacer un SQL UPDATE
:
UPDATE addresses_to_geocode
SET (rating, longitude, latitude,geo)
= ( COALESCE((g.geom).rating,-1),
ST_X((g.geom).geomout)::numeric(8,5),
ST_Y((g.geom).geomout)::numeric(8,5),
geo )
FROM (SELECT "PatientId" as PatientId
FROM addresses_to_geocode
WHERE "rating" IS NULL ORDER BY PatientId LIMIT 1000) As a
LEFT JOIN (SELECT "PatientId" as PatientId, (geocode("Address",1)) As geom
FROM addresses_to_geocode As ag
WHERE ag.rating IS NULL ORDER BY PatientId LIMIT 1000) As g ON a.PatientId = g.PatientId
WHERE a.PatientId = addresses_to_geocode."PatientId";
Estoy usando un tamaño de lote de 1000 arriba y lo devuelve en el 337.70 segundos. Es un poco más lento para lotes más pequeños.
Geocodificación de SQL ejemplo #2 (fila por fila) ~ el tiempo medio es de 1.2/seg.
Al profundizar en mis direcciones haciendo el geocodifica de una en una con una declaración de que se parece a esto (por cierto, el ejemplo a continuación tomó 4.14 segundos),
SELECT g.rating, ST_X(g.geomout) As lon, ST_Y(g.geomout) As lat,
(addy).address As stno, (addy).streetname As street,
(addy).streettypeabbrev As styp, (addy).location As city,
(addy).stateabbrev As st,(addy).zip
FROM geocode('6433 DROMOLAND Cir NW, MASSILLON, OH 44646',1) As g;
es un poco más lento (2.5 x por registro), pero puedo mirar la distribución de los tiempos de consulta y ver que es una minoría de largas consultas que se están desacelerando esta abajo de la mayoría (sólo la primera 2600 de 5 millones de ha de búsqueda veces). Es decir, el 10% superior está tomando un promedio de alrededor de 100 ms, la parte inferior del 10% promedio de 3,69 segundos, mientras que la media es de 754 ms y la mediana es de 340 ms.
# Just some interaction with the data in R
> range(lookupTimes[1:2600])
[1] 0.00 11.54
> median(lookupTimes[1:2600])
[1] 0.34
> mean(lookupTimes[1:2600])
[1] 0.7541808
> mean(sort(lookupTimes[1:2600])[1:260])
[1] 0.09984615
> mean(sort(lookupTimes[1:2600],decreasing=TRUE)[1:260])
[1] 3.691269
> hist(lookupTimes[1:2600]
Otros pensamientos
Si no puedo obtener una orden de magnitud de aumento en el rendimiento, pensé que al menos podría hacer una conjetura acerca de la predicción de lento geocodificar veces, pero no es obvio para mí ¿por qué el más lento direcciones parecen estar tomando mucho más tiempo. Me estoy quedando en la dirección original a través de un custom paso de normalización para asegurarse de que está bien formateado antes de la geocode()
función obtiene:
sql=paste0("select pprint_addy(normalize_address('",myAddress,"'))")
donde myAddress
es [Address], [City], [ST] [Zip]
cadena compilado a partir de un usuario de la tabla de direcciones de un no-la base de datos postgresql.
He intentado (no) para instalar el pagc_normalize_address
extensión, pero no está claro que esto traerá el tipo de mejora que estoy buscando.
Editado para añadir el monitoreo de información como por la sugerencia
Rendimiento
Una CPU está vinculado: [editar, sólo un procesador por consulta, así que tengo 5 no utilizado Cpu]
top - 14:10:26 up 1 day, 3:11, 4 users, load average: 1.02, 1.01, 0.93
Tasks: 219 total, 2 running, 217 sleeping, 0 stopped, 0 zombie
Cpu(s): 15.4%us, 1.5%sy, 0.0%ni, 83.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 65056588k total, 64613476k used, 443112k free, 97096k buffers
Swap: 262139900k total, 77164k used, 262062736k free, 62745284k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3130 postgres 20 0 16.3g 8.8g 8.7g R 99.7 14.2 170:14.06 postmaster
11139 aolsson 20 0 15140 1316 932 R 0.3 0.0 0:07.78 top
11675 aolsson 20 0 135m 1836 1504 S 0.3 0.0 0:00.01 wget
1 root 20 0 19364 1064 884 S 0.0 0.0 0:01.84 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.06 kthreadd
Ejemplo de actividad de disco en la partición de datos, mientras que un proc está vinculada al 100%: [edit: un solo procesador en el uso de esta consulta]
# dstat -tdD dm-3 1
----system---- --dsk/dm-3-
date/time | read writ
12-06 14:06:36|1818k 3632k
12-06 14:06:37| 0 0
12-06 14:06:38| 0 0
12-06 14:06:39| 0 0
12-06 14:06:40| 0 40k
12-06 14:06:41| 0 0
12-06 14:06:42| 0 0
12-06 14:06:43| 0 8192B
12-06 14:06:44| 0 8192B
12-06 14:06:45| 120k 60k
12-06 14:06:46| 0 0
12-06 14:06:47| 0 0
12-06 14:06:48| 0 0
12-06 14:06:49| 0 0
12-06 14:06:50| 0 28k
12-06 14:06:51| 0 96k
12-06 14:06:52| 0 0
12-06 14:06:53| 0 0
12-06 14:06:54| 0 0 ^C
Analizar que SQL
Esto es de EXPLAIN ANALYZE
en esa consulta:
"Update on addresses_to_geocode (cost=1.30..8390.04 rows=1000 width=272) (actual time=363608.219..363608.219 rows=0 loops=1)"
" -> Merge Left Join (cost=1.30..8390.04 rows=1000 width=272) (actual time=110.934..324648.385 rows=1000 loops=1)"
" Merge Cond: (a.patientid = g.patientid)"
" -> Nested Loop (cost=0.86..8336.82 rows=1000 width=184) (actual time=10.676..34.241 rows=1000 loops=1)"
" -> Subquery Scan on a (cost=0.43..54.32 rows=1000 width=32) (actual time=10.664..18.779 rows=1000 loops=1)"
" -> Limit (cost=0.43..44.32 rows=1000 width=4) (actual time=10.658..17.478 rows=1000 loops=1)"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode addresses_to_geocode_1 (cost=0.43..195279.22 rows=4449758 width=4) (actual time=10.657..17.021 rows=1000 loops=1)"
" Filter: (rating IS NULL)"
" Rows Removed by Filter: 24110"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode (cost=0.43..8.27 rows=1 width=152) (actual time=0.010..0.013 rows=1 loops=1000)"
" Index Cond: ("PatientId" = a.patientid)"
" -> Materialize (cost=0.43..18.22 rows=1000 width=96) (actual time=100.233..324594.558 rows=943 loops=1)"
" -> Subquery Scan on g (cost=0.43..15.72 rows=1000 width=96) (actual time=100.230..324593.435 rows=943 loops=1)"
" -> Limit (cost=0.43..5.72 rows=1000 width=42) (actual time=100.225..324591.603 rows=943 loops=1)"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode ag (cost=0.43..23534259.93 rows=4449758000 width=42) (actual time=100.225..324591.146 rows=943 loops=1)"
" Filter: (rating IS NULL)"
" Rows Removed by Filter: 24110"
"Total runtime: 363608.316 ms"
Ver mejor avería en el http://explain.depesz.com/s/vogS