En un
artículo anterior, examiné la geocodificación inversa usando Spark. Ahora imagine que enfrentamos el desafío de la geocodificación directa de direcciones de correo. Es decir, recibir por la dirección registrada por el texto de algunas coordenadas geográficas.
Las direcciones para la definición son rusas, y lo más importante: a menudo se escriben torcidamente, es decir, con errores, ambigüedades y otras delicias. Y estas direcciones están en la base de datos de Hive, en el clúster de Hadoop.
Bueno, parece que tomamos la API de geocodificación de Google Maps (o, si usted es partidario de la sustitución de importaciones, entonces la API de Yandex Maps), y trabajamos. Pero aquí, así como con geocodificación inversa, estamos esperando una pequeña emboscada.
O grande, es como una mirada. El hecho es que esta vez necesitamos procesar alrededor de 5 millones de direcciones. Y tal vez 50, no estaba claro de inmediato. Como sabes, Google prohibirá tu IP después de aproximadamente 10 mil direcciones, Yandex hará lo mismo contigo, aunque es posible un poco más tarde (25 mil solicitudes al día, como). Y además, ambas API son REST, lo que significa que es relativamente lento. E incluso si compra una suscripción paga, la velocidad de esto no aumentará ni un centavo.
Y sin embargo, se nos acabó la anécdota de munición (es).
Olvidé lo más importante: nuestro clúster de Hadoop está ubicado en la intranet y Google Maps, para la compañía con Yandex Maps, y todos los demás, generalmente son inaccesibles para nosotros desde el clúster. Es decir, necesitábamos una solución autónoma.
Diré de inmediato: aquí no encontrará una solución preparada. Solo describiré el enfoque que planeamos aplicar, y con un poco más de detalle, uno de los pasos en un largo camino hacia una solución.
Por supuesto, teníamos algo en reserva. Había un servidor ArcGIS interno que ya mencioné. No se nos permitió dirigirlos, pero se nos permitió usar sus servicios REST.
Lo primero que hicimos fue atornillarlo a la tarea. No nos prohibió, sino que a veces simplemente se apagó por mantenimiento. Y lo que es bueno: tenía un modo de geocodificación por lotes, cuando enviaba un paquete de direcciones a la entrada (después de configurar el servidor, teníamos un tamaño de paquete de 1000 piezas, por defecto parece que algo es un orden de magnitud o dos más pequeño). Todo esto tampoco fue fácil, y nosotros, y el soporte de ArcGIS, estuvimos involucrados en la lucha de sumo con el servidor durante mucho tiempo, pero esta es otra historia.
Después de todos los trucos, giros y vueltas, pudimos procesar nuestros cinco millones en aproximadamente un día. Era necesario seguir adelante e intentar acelerar aún.
Al mismo tiempo, quedó claro que cualquier geocodificador con REST probablemente no sea adecuado para nosotros. Además, miramos a Nominatim, Pelias, Photon y gisgrafía, y en general no quedamos satisfechos con ninguno. La calidad y el rendimiento (o ambos) estaban lejos de ser ideales.
Por ejemplo, nadie sabe cómo geocodificar paquetes (y esto aceleró enormemente el trabajo con ArcGIS).
O calidad: vaya al servidor de demostración gisgraphy.com e intente encontrar Moscú. Recibirá un par de docenas de respuestas, que incluyen: Moscú (una ciudad en la Federación de Rusia), Kansas City (una ciudad en los EE. UU.), Khimki, Kaluga, Vykhino-Zhulebino y muchos otros objetos que no quisiera ver en la respuesta del geocodificador cuando buscar Moscú
Bueno, el último problema (pero no importante para nosotros) es que, lejos de todos los geocodificadores, la API está tan bien pensada como, por ejemplo, Google Maps. Digamos que la API de ArcGIS ya es mucho más inconveniente, y el resto es en su mayor parte aún peor. Si geocodifica direcciones para la interfaz de usuario, por lo general, una persona se dedica a elegir la mejor opción. Y lo hace mejor que el programa. Y en el caso de la geocodificación en masa, como lo hemos hecho, evaluar la calidad del resultado para una dirección particular es uno de los componentes importantes del éxito.
Como resultado, opciones como "Expande tu propio Nominatim", por ejemplo, también han desaparecido.
Que hacer
Una solución bastante obvia fue esta: dado que las direcciones no se toman de ningún lado y no desaparecen, las casas no se construyen todos los días y las calles no se construyen, solo necesita agregar una base de datos de direcciones oficialmente existentes a nuestro proceso. Mejor inmediatamente con las coordenadas, y si esto no sucede, geocodifique una vez. En este caso, será suficiente para nosotros actualizar nuestra base con la misma frecuencia que aparecen nuevas casas o calles, es decir, no con frecuencia.
El primer y principal candidato para la base de direcciones existentes es
FIAS . Espera un momento, dices, pero FIAS tiene solo unos pocos millones de direcciones, ¿y tienes hasta 50 millones? Sí, realmente solo hay unos pocos millones de
hogares . Y nuestros 50 son 50 millones de direcciones de nuestros usuarios, es decir, estas son las direcciones de personas, y de repente tienen un departamento en la dirección. Cinco millones de casas de 1-100 apartamentos, varias personas viven en cada apartamento ... bueno, lo entiendes todo. Y la segunda opción son las direcciones de las oficinas, donde también un centro de oficinas tiene hasta cientos de locales, que a veces se alquilan.
Al mismo tiempo, obviamente no necesitamos una dirección con el número del apartamento (u oficina); en primer lugar, se trata de datos personales con todas las consecuencias, y en segundo lugar, todavía no estamos interesados en cómo se encuentran los apartamentos en una casa en particular y cuáles son sus coordenadas. . Solo se necesita una casa. Para las oficinas, esto no es del todo cierto, pero la ubicación de las oficinas en un edificio por pisos aún no está determinada por las coordenadas.
En última instancia, teniendo una base de, digamos, 5 millones de casas existentes (condicionalmente), podemos resolver el problema de geocodificación de 50 o 100 millones de direcciones simplemente tirando el departamento u oficina fuera de la dirección y emparejándolo con la base.
¿Y dónde obtener las coordenadas de las casas? Solo hay un código abierto obvio: OpenStreetMap, hay casas allí, con geometrías y varios otros atributos, como el número de pisos o incluso el color del techo.
Después de todas las discusiones, teníamos un plan napoleónico. Aquí hay uno:
- cargando datos de mapas de OSM en Hadoop
- cargar datos FIAS con direcciones
- construir una lista de direcciones completas únicas con números de casa
- lo geocodificamos buscando direcciones en OSM, y lo que no encontramos es a través de ArcGIS
Obtenemos la base de casas con latitud y longitud. Disfruta Cosechando los beneficios. Beber bonos (broma).
En este artículo te contaré cómo implementamos el primer punto de este plan.
¿Qué es OpenStreetMap?
Si observa OSM desde el punto de vista de los datos, las tarjetas se pueden imaginar en forma de tres tablas:
- puntos
- líneas (formas)
- relaciones
Los esquemas reales de estos datos se darán a continuación.
Solo los puntos tienen coordenadas (latitud y longitud, en grados). Las líneas son una secuencia ordenada de puntos. Las relaciones son un conjunto de puntos y líneas, cada uno de los cuales tiene un
papel .
Todo lo demás son las llamadas etiquetas. Es decir, por ejemplo, un cajero automático, una tienda o una entrada al metro; puede ser un punto equipado con la etiqueta amenity = atm, o shop = vende algo u otra cosa. Hay un directorio de etiquetas oficialmente recomendadas (para cada idioma y país aplicable, pueden ser parcialmente propias), y la práctica de inventar etiquetas no estándar.
Además de las etiquetas, cada elemento del mapa tiene una identificación numérica única, así como algunos atributos relacionados con el historial: quién editó cuándo, editó el número, etc.
La base de datos con la tarjeta viene en varios formatos:
- pbf es Google Protobuf, un formato de serialización de datos portátil.
- XML es obviamente XML. Mucho más en volumen.
Debe comprender que la base de datos se actualiza diariamente. Por lo tanto, las descargas son completas e incrementales.
Elegimos PBF como más compacto.
Para leerlo en Hadoop, hay una API de Java hecha específicamente para OSM llamada este proyecto de ósmosis. En principio, trabajar con él es simple: carga un archivo y recorre los elementos del mapa. Agregue los puntos en un lugar, las líneas en otro, la relación en el tercero. En principio, la ósmosis y, por ejemplo, Spark ya son suficientes para descargar todos los datos.
Afortunadamente, en el proceso de implementación de mi bicicleta, de alguna manera se me ocurrió buscar en Internet para convertir OSM en los formatos aceptados en Hadoop - Parquet (parquet) y Avro. En cierto sentido, ambos son análogos de PBF, por lo que hubo la posibilidad de encontrar un convertidor. Y fue encontrado, pero ninguno.
Conoce OSM Parquetizer
¡Mira
lo que encontré!Para la gente perezosa, justo en el archivo Léame del proyecto en la primera línea dice: Telenav publica descargas semanales del planeta
en la dirección .
Para personas muy vagas: prepárate para enviar unos 700 gigabytes;) Bueno, si realmente necesitas un planeta. Por lo general, puedes arreglártelas con, por ejemplo, Europa.
Si no desea cargar, el proceso se ve así: descargue un mapa en formato PBF, por ejemplo, desde una
geofábrica . Esto es 2.5 gigabytes si necesita Rusia, y 19 si Europa. Tampoco un poco, pero puedes encontrar muestras más finamente picadas. Luego, coloque el archivo en el disco y ejecute el programa:
java -jar ./osm-parquetizer.jar russia-latest.osm.pbf
Después de unos minutos o incluso segundos, dependiendo del rendimiento de su máquina, obtiene tres archivos en formato parquet. Así es como se ve el autor (él es de Rumania):
-rw-r--r-- 1 adrianbona adrianbona 145M Apr 3 19:57 romania-latest.osm.pbf -rw-r--r-- 1 adrianbona adrianbona 372M Apr 3 19:58 romania-latest.osm.pbf.node.parquet -rw-r--r-- 1 adrianbona adrianbona 1.1M Apr 3 19:58 romania-latest.osm.pbf.relation.parquet -rw-r--r-- 1 adrianbona adrianbona 123M Apr 3 19:58 romania-latest.osm.pbf.way.parquet
Esquemas de los archivos .parquet recibidos:
node
|-- id: long
|-- version: integer
|-- timestamp: long
|-- changeset: long
|-- uid: integer
|-- user_sid: string
|-- tags: array
| |-- element: struct
| | |-- key: string
| | |-- value: string
|-- latitude: double
|-- longitude: double
way
|-- id: long
|-- version: integer
|-- timestamp: long
|-- changeset: long
|-- uid: integer
|-- user_sid: string
|-- tags: array
| |-- element: struct
| | |-- key: string
| | |-- value: string
|-- nodes: array
| |-- element: struct
| | |-- index: integer
| | |-- nodeId: long
relation
|-- id: long
|-- version: integer
|-- timestamp: long
|-- changeset: long
|-- uid: integer
|-- user_sid: string
|-- tags: array
| |-- element: struct
| | |-- key: string
| | |-- value: string
|-- members: array
| |-- element: struct
| | |-- id: long
| | |-- role: string
| | |-- type: string
Como puede ver, todo es simple aquí. Luego hacemos lo siguiente:
- colocamos archivos en el clúster de Hadoop con el comando hdfs dfs -put
- vamos a decir en Hue y crear un esquema / base, y tres tablas para ello, en base a los datos anteriores
- ejecute select * desde osm.nodes y disfrute el resultado.
Un pequeño matiz: en nuestra versión de Hive (y posiblemente también en la suya), no puede crear tablas basadas en el esquema de Parquet. Debe convertir lo anterior a CREAR TABLA (que, en general, no es difícil, y lo dejaré como un ejercicio en el hogar para los lectores), o hacer un poco más complicado: Spark puede leer el diagrama y los datos desde el piso, y crear tablas temporales basadas en ellos . Entonces podemos leer los datos en Spark Shell así:
val nodeDF = sqlContext.read.parquet("file:/tmp/osm/romania-latest.osm.pbf.node.parquet") nodeDF.createOrReplaceTempView("nodes")
Entonces ya puede crear tablas en Hive utilizando nodos LIKE.
Otro comentario para la gente perezosa: el autor tiene un
ejemplo tan maravilloso, del que, en general, todo queda claro (bueno, si posee Spark). Por supuesto, esto no es Spark Shell, sino el Databricks Notebook, pero me llevó unos 15 minutos tocar un teclado para traducir uno a otro. Y en 30-40 minutos fue posible convertirlo todo en consultas para Hive usando algunos análogos que son ligeramente diferentes de la chispa.
Ejemplo de solicitud real
¿Qué podemos obtener de esta base de datos en su forma actual? En general, bastante. Si tiene un Hive o Spark, Spatial Framework, Geometry API o una de las alternativas, que son GeoSpark o, por ejemplo, GeoMesa, puede resolver muchos problemas diferentes sobre esta base.
Veamos un ejemplo. La forma más fácil de trabajar con puntos. Por ejemplo, una consulta para obtener una lista de cajeros automáticos con sus coordenadas se ve así:
select * from nodes where tags['amenity']='atm'
Cómo construir una consulta de este tipo, puede adivinar leyendo la
página en la wiki . Allí encontrará qué otras etiquetas son, y algunas de ellas se pueden incluir en su solicitud en lugar de *, en forma de etiquetas ['operador'], por ejemplo, para mostrar el nombre del banco.
De la misma página se deduce que el marcado ATM es posible en forma de etiquetas amenity = bank y atm = yes. Por desgracia, tales ambigüedades están en todas partes en OSM.
Si eres un principiante y te familiarizas con OSM, te recomiendo dominar (con buenos ejemplos en la wiki)
overpass-turbo . Esta es una herramienta que le permite realizar varios tipos de búsquedas en los datos del mapa, tanto con condiciones geométricas como con condiciones para etiquetas.
¿Y dónde están las direcciones?
Buena pregunta Las direcciones en OSM son elementos de mapa provistos con las etiquetas addr: *, es decir comenzando con addr. Descripción que encontrarás
aquí . En principio, sabiendo todo lo que he dicho anteriormente, ya puede escribir alguna solicitud de trabajo:
select * from nodes where tags['addr:housenumber']!=null
¿Qué problemas nos esperan aquí? En primer lugar, las direcciones se colocan tanto en puntos (por ejemplo, entradas de edificios) como en polígonos, es decir. en formas. Entonces tenemos que duplicar la solicitud al menos. Y en segundo lugar, en la página mencionada anteriormente, el wiki está escrito en texto plano que no se recomienda poner etiquetas que indiquen la ciudad, región, región y país, pero esto debe calcularse geométricamente. Como hacerlo En general, esta es prácticamente la tarea de geocodificación inversa, con ligeras modificaciones, y se describió en una publicación anterior.
Es decir, en general, necesita encontrar límites administrativos, y para todas las direcciones que están dentro de ellos, agregue la dirección al área y todo lo anterior.
Aquí se describe cómo se organizan los límites de las entidades administrativas.
En general, esta tarea no es demasiado simple, pero es bastante solucionable, y no se resuelve mediante geocodificación, sino descargando actualizaciones de OSM a nuestra base de datos, en un ambiente relajado.
¿Qué es útil hacer a continuación?
En principio, ya puede trabajar con los nodos, las formas y las tablas de relaciones que tenemos, pero es mejor cambiar un poco el esquema, haciéndolo más adecuado para Hive y Spark. El hecho es que el esquema OSM está completamente normalizado, las formas y las relaciones no contienen coordenadas en absoluto. Para construir un polígono para el camino, debe unirse con nodos. Recomendaría hacer esta operación de inmediato, guardando los polígonos como una matriz de estructuras (Hive puede trabajar con la matriz de tipos compuestos, mapa y estructura), o inmediatamente como una representación serializada de, digamos, la clase Geometry. Cómo hacer esto está en el ejemplo del autor parquetizer.
Puede repetir una operación similar a nivel de relaciones, si lo desea, pero apenas vale la pena. En primer lugar, no siempre necesitará todos los elementos de una relación y, en segundo lugar, las relaciones en sí mismas en OSM son mucho más pequeñas.
Convertidor a Avro
Aquí hay otro conversor, esta vez al formato Avro. Y
aquí se describe dónde obtener los archivos terminados. No medí los tamaños, pero creo que aproximadamente 15-20 archivos por planeta deberían ser comparables con PBF. Es decir, estos son gigabytes, y mucho.
Algunas conclusiones
¿Y dónde está la geocodificación, preguntas? Sí, descargar mapas y extraer direcciones es solo una parte de la tarea general. Espero que se trate de esto.