Bagaimana cara memuat OpenStreetMap di Hive?

Dalam artikel sebelumnya, saya memeriksa geocoding terbalik menggunakan Spark. Sekarang bayangkan kita menghadapi tantangan geocoding langsung alamat email. Artinya, menerima alamat yang direkam oleh teks dari beberapa koordinat geografis.

Alamat untuk definiteness adalah Rusia, dan yang paling penting - mereka sering ditulis miring, yaitu, dengan kesalahan, ambiguitas dan kesenangan lainnya. Dan alamat ini ada di database Hive, di cluster Hadoop.


Sepertinya, - kami mengambil Google Maps Geocoding API (atau, jika Anda adalah pendukung substitusi impor, maka Yandex Maps API), dan kami bekerja. Tapi di sini kita, juga dengan geocoding terbalik, sedang menunggu penyergapan kecil.

Atau besar, itu seperti tampilan. Faktanya adalah bahwa saat ini kita perlu memproses sekitar 5 juta alamat. Dan mungkin 50 - itu tidak segera jelas. Seperti yang Anda tahu, Google akan mencekal IP Anda setelah sekitar 10 ribu alamat, Yandex akan melakukan hal yang sama dengan Anda, meskipun mungkin beberapa saat kemudian (25 ribu permintaan sehari, misalnya). Dan selain itu, kedua API adalah REST, yang berarti relatif lambat. Dan bahkan jika Anda membeli langganan berbayar, kecepatan dari ini tidak akan meningkat satu sen pun.

Namun - kami kehabisan amunisi (an) anekdot.

Saya lupa hal yang paling penting - cluster Hadoop kami terletak di intranet, dan Google Maps, untuk perusahaan dengan Yandex Maps, dan semua orang lain, pada umumnya tidak dapat diakses oleh kami dari cluster. Artinya, kami membutuhkan solusi otonom.

Saya akan mengatakan segera - Anda tidak akan menemukan solusi yang sudah jadi di sini. Saya hanya akan menjelaskan pendekatan yang kami rencanakan untuk diterapkan, dan sedikit lebih detail - salah satu langkah menuju solusi.

Tentu saja, kami memiliki sesuatu sebagai cadangan. Ada server ArcGIS internal yang telah saya sebutkan. Kami tidak diizinkan untuk menyetir mereka, tetapi diizinkan untuk menggunakan layanan REST-nya.

Hal pertama yang kami lakukan adalah mengacaukannya. Dia tidak melarang kami, tetapi kadang-kadang dimatikan untuk pemeliharaan. Dan bagusnya - memiliki mode batch geocoding, ketika Anda mengirimkan paket alamat ke input (setelah mengonfigurasi server, kami memiliki ukuran paket 1000 buah, secara default sepertinya ada urutan besarnya atau dua lebih kecil). Semua ini juga tidak mudah, dan kami, serta dukungan ArcGIS, terlibat dalam pergulatan sumo dengan server untuk waktu yang lama, tetapi ini adalah cerita lain.

Setelah semua trik dan tikungan, kami dapat memproses lima juta kami dalam waktu sekitar satu hari. Itu perlu untuk bergerak, dan mencoba untuk mempercepat.

Pada saat yang sama, menjadi jelas bahwa geocoder dengan REST kemungkinan besar tidak cocok untuk kita. Selain itu, kami melihat Nominatim, dan Pelias, dan pada Photon, dan gisgraphy, dan secara umum tidak puas dengan apa pun. Kualitas dan kinerja (atau keduanya) jauh dari ideal.

Misalnya, tidak ada yang tahu cara membuat geocode paket (dan ini sangat dipercepat dengan ArcGIS).

Atau kualitas - buka server demo gisgraphy.com dan coba temukan Moskow. Anda akan mendapatkan beberapa lusin jawaban, termasuk: Moskow (sebuah kota di Federasi Rusia), Kota Kansas (sebuah kota di AS), Khimki, Kaluga, Vykhino-Zhulebino, dan banyak objek lain yang tidak ingin saya lihat dalam jawaban geocoder ketika cari Moskow.

Nah, masalah terakhir (tetapi tidak penting bagi kami) adalah jauh dari semua geocoder, API dipikirkan dengan baik, misalnya, Google Maps. Katakanlah API ArcGIS sudah jauh lebih tidak nyaman, dan sisanya sebagian besar bahkan lebih buruk. Jika Anda melakukan geocode alamat untuk UI, maka sebagai aturan seseorang terlibat dalam memilih opsi terbaik. Dan dia melakukannya lebih baik daripada programnya. Dan dalam kasus geocoding massal, seperti yang kita miliki, menilai kualitas hasil untuk alamat tertentu adalah salah satu komponen penting dari kesuksesan.

Akibatnya, opsi seperti "Perluas Nominatim Anda sendiri", misalnya, juga telah hilang.

Apa yang harus dilakukan


Solusi yang agak jelas adalah ini: karena alamat tidak diambil dari mana saja dan tidak menghilang, rumah-rumah tidak dibangun setiap hari, dan jalan-jalan tidak dibangun, Anda hanya perlu menambahkan database alamat yang ada secara resmi ke proses kami. Lebih baik segera dengan koordinat, dan jika ini tidak terjadi, maka geocode sekali. Dalam hal ini, cukup bagi kami untuk memperbarui basis kami dengan frekuensi yang sama dengan rumah atau jalan baru yang muncul, yaitu, tidak sering.

Kandidat pertama dan utama untuk basis alamat yang ada adalah FIAS . Tunggu sebentar, katamu, tetapi FIAS hanya memiliki beberapa juta alamat - dan Anda memiliki sebanyak 50 juta? Ya, sebenarnya hanya ada beberapa juta rumah . Dan 50 kami adalah 50 juta alamat pengguna kami, yaitu, ini adalah alamat orang, dan mereka tiba-tiba memiliki apartemen di alamat itu. Lima juta rumah dari 1-100 apartemen, beberapa orang tinggal di setiap apartemen ... well, Anda mengerti segalanya. Dan pilihan kedua adalah alamat kantor, di mana juga satu pusat kantor memiliki hingga ratusan tempat, yang terkadang disewakan.

Pada saat yang sama, kami jelas tidak perlu alamat dengan nomor apartemen (atau kantor) - pertama, ini adalah data pribadi dengan semua konsekuensinya, dan kedua, kami masih tidak tertarik pada bagaimana apartemen berada di rumah tertentu, dan berapa koordinatnya. . Hanya rumah yang dibutuhkan. Untuk kantor, ini tidak sepenuhnya benar, tetapi lokasi kantor di gedung berdasarkan lantai masih belum ditentukan oleh koordinat.

Pada akhirnya, dengan memiliki basis, katakanlah, 5 juta rumah (secara kondisional) yang ada, kita dapat menyelesaikan masalah geocoding dari 50 atau 100 juta alamat hanya dengan membuang apartemen atau kantor dari alamat dan mencocokkannya dengan basis.

Dan di mana bisa mendapatkan koordinat rumah? Hanya ada satu open source yang jelas - OpenStreetMap, ada rumah di sana, dengan geometri, dan segala macam atribut lainnya seperti jumlah lantai atau bahkan warna atap.

Setelah semua diskusi, kami punya rencana Napoleon. Ini satu:

  • memuat data peta dari OSM ke Hadoop
  • unggah data FIAS dengan alamat
  • buat daftar alamat lengkap unik dengan nomor rumah
  • kami melakukan geocode dengan mencari alamat di OSM, dan apa yang tidak kami temukan adalah melalui ArcGIS


Kami mendapatkan basis rumah dengan lintang dan bujur. Selamat menikmati. Menuai manfaatnya. Minuman bonus (lelucon).

Dalam artikel ini saya akan memberi tahu Anda bagaimana kami menerapkan poin pertama dari rencana ini.

Apa itu OpenStreetMap


Jika Anda melihat OSM dari sudut pandang data, maka kartu dapat dibayangkan dalam bentuk tiga tabel:

  • poin
  • garis (cara)
  • hubungan


Skema nyata dari data ini akan diberikan di bawah ini.

Hanya titik yang memiliki koordinat (lintang dan bujur, dalam derajat). Garis adalah urutan titik yang dipesan. Hubungan adalah seperangkat titik dan garis, yang masing-masing memiliki peran .

Yang lainnya adalah tag yang disebut. Yaitu, misalnya, ATM, atau toko, atau pintu masuk ke metro - itu bisa berupa titik yang dilengkapi dengan tag amenity = atm, atau toko = menjual sesuatu, atau sesuatu yang lain. Ada direktori tag yang direkomendasikan secara resmi (untuk setiap bahasa dan negara yang berlaku, mereka dapat sebagian milik mereka sendiri), dan praktik menciptakan yang tidak standar.

Selain tag, setiap elemen peta memiliki id numerik yang unik, serta beberapa atribut yang terkait dengan riwayat - yang mengedit kapan, mengedit nomor, dll.

Basis data dengan kartu hadir dalam beberapa format:
- pbf adalah Google Protobuf, format serialisasi data portabel.
- xml jelas XML. Volume lebih banyak.

Anda perlu memahami bahwa basis data diperbarui setiap hari. Oleh karena itu, pembongkaran lengkap dan bertahap.

Kami memilih PBF karena lebih ringkas.

Untuk membacanya di Hadoop, ada Java API yang khusus dibuat untuk OSM yang disebut proyek osmosis ini. Pada prinsipnya, bekerja dengannya sederhana - Anda mengunggah file dan menggilir elemen peta. Tambahkan titik di satu tempat, garis di tempat lain, hubungan di tempat ketiga. Pada prinsipnya, osmosis dan misalnya Spark sudah cukup untuk mengunduh semua data.

Untungnya, dalam proses penerapan sepeda saya, entah bagaimana terpikir oleh saya untuk mencari di Internet untuk mengubah OSM ke dalam format yang diterima di Hadoop - Parket (parket) dan Avro. Dalam arti, keduanya adalah analog PBF, jadi ada peluang untuk menemukan konverter. Dan dia ditemukan, tetapi tidak satu pun.

Temui OSM Parquetizer


Lihat apa yang saya temukan!

Untuk orang-orang malas - tepat di readme proyek di baris pertama dikatakan: Telenav menerbitkan unduhan mingguan planet ini ke alamatnya .

Untuk orang-orang yang sangat malas: bersiap-siap untuk mengirim sekitar 700 gigabytes;) Nah, jika Anda tentu membutuhkan sebuah planet. Anda biasanya dapat bertahan dengan, katakanlah, Eropa.

Jika Anda tidak ingin memuat, prosesnya terlihat seperti ini: unduh peta dalam format PBF, misalnya dari geofactory . Ini adalah 2,5 gigabytes jika Anda membutuhkan Rusia, dan 19 jika Eropa. Juga tidak sedikit, tetapi Anda dapat menemukan sampel cincang lebih halus. Selanjutnya, letakkan file di disk, dan jalankan program:

java -jar ./osm-parquetizer.jar russia-latest.osm.pbf 

Setelah beberapa menit atau bahkan detik, tergantung pada kinerja mesin Anda, Anda mendapatkan tiga file dalam format parket. Inilah yang terlihat seperti penulis (dia dari 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 

Skema file .parquet yang diterima:

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


Seperti yang Anda lihat, semuanya sederhana di sini. Kemudian kita lakukan hal berikut:

  • kita meletakkan file pada cluster Hadoop dengan perintah hdfs dfs -put
  • katakanlah dalam Hue dan buat skema / basis, dan tiga tabel untuknya, berdasarkan data di atas
  • jalankan pilih * dari osm.nodes, dan nikmati hasilnya.

Nuansa kecil: dalam versi Hive kami (dan mungkin juga milik Anda), ia tidak dapat membuat tabel berdasarkan skema dari Parket. Anda harus mengonversi di atas menjadi CREATE TABLE (yang, secara umum, tidak sulit, dan saya akan meninggalkan ini sebagai latihan rumahan untuk pembaca), atau untuk melakukan sedikit lebih rumit: Spark dapat membaca diagram dan data dari lantai, dan membuat tabel sementara berdasarkan pada mereka . Jadi kita bisa membaca data di Spark Shell seperti ini:

 val nodeDF = sqlContext.read.parquet("file:/tmp/osm/romania-latest.osm.pbf.node.parquet") nodeDF.createOrReplaceTempView("nodes") 

Maka Anda sudah bisa membuat tabel di Hive menggunakan simpul LIKE.

Komentar lain untuk orang yang malas: penulis memiliki contoh yang sangat bagus, yang secara umum semuanya menjadi jelas (baik, jika Anda memiliki Spark). Ini tentu saja bukan Spark Shell, tetapi Databricks Notebook, tetapi butuh sekitar 15 menit untuk mengetuk satu keyboard untuk menerjemahkan satu ke yang lain. Dan dalam 30-40 menit dimungkinkan untuk mengonversikan semuanya menjadi kueri untuk Hive menggunakan beberapa analog yang sedikit berbeda dari percikan.

Contoh Permintaan Nyata


Apa yang bisa kita dapatkan dari database ini dalam bentuk saat ini? Secara umum, cukup banyak. Jika Anda memiliki Hive atau Spark, Kerangka Spasial, API Geometri, atau salah satu alternatifnya, yaitu GeoSpark atau GeoMesa, misalnya, Anda dapat memecahkan banyak masalah berbeda berdasarkan ini.

Mari kita lihat sebuah contoh. Cara termudah untuk bekerja dengan poin. Misalnya, permintaan untuk mendapatkan daftar ATM dengan koordinatnya terlihat seperti ini:

 select * from nodes where tags['amenity']='atm' 

Cara membuat kueri seperti itu, Anda bisa menebak dengan membaca halaman di wiki . Di sana Anda akan menemukan apa itu tag lain, dan beberapa di antaranya dapat dimasukkan dalam permintaan Anda alih-alih *, dalam bentuk tag ['operator'], misalnya, untuk menunjukkan nama bank.

Dari halaman yang sama berikut bahwa markup ATM dimungkinkan dalam bentuk tag amenity = bank dan atm = ya. Sayangnya, ambiguitas seperti itu ada di mana-mana dalam OSM.

Jika Anda seorang pemula, dan hanya berkenalan dengan OSM, saya sangat merekomendasikan menguasai (dengan contoh yang baik di wiki) overpass-turbo . Ini adalah alat yang memungkinkan Anda untuk melakukan berbagai jenis pencarian pada data peta, baik dengan kondisi geometris dan dengan kondisi untuk tag.

Dan di mana alamatnya?


Pertanyaan yang bagus Alamat dalam OSM adalah elemen peta yang dilengkapi dengan addr: * tag, mis. dimulai dengan addr. Keterangan akan Anda temukan di sini . Pada prinsipnya, mengetahui semua yang telah saya nyatakan di atas, Anda sudah dapat menulis beberapa permintaan kerja:

 select * from nodes where tags['addr:housenumber']!=null 

Masalah apa yang menunggu kita di sini? Pertama, alamat ditempatkan pada titik (misalnya, pintu masuk gedung), dan pada poligon, yaitu di jalan. Jadi setidaknya kita harus menduplikasi permintaan. Dan kedua, pada halaman yang disebutkan di atas, wiki ditulis dalam teks biasa sehingga tidak disarankan untuk menempatkan tag yang menunjukkan kota, wilayah, wilayah dan negara, tetapi ini harus dihitung secara geometris. Bagaimana cara melakukannya? Secara umum, ini praktis tugas membalik geocoding, dengan modifikasi ringan, dan itu dijelaskan dalam posting sebelumnya.

Artinya, secara umum, Anda perlu menemukan batas administrasi, dan untuk semua alamat yang ada di dalamnya, tambahkan alamat ke area dan semua yang di atas. Bagaimana batas-batas entitas administratif diatur dijelaskan di sini .

Secara umum, tugas ini tidak terlalu sederhana, tetapi cukup dapat dipecahkan, dan tidak diselesaikan dengan geocoding, tetapi dengan mengunduh pembaruan OSM ke database kami, dalam suasana yang santai.

Apa yang berguna untuk dilakukan selanjutnya


Pada prinsipnya, Anda sudah dapat bekerja dengan node, cara, dan tabel relasi yang kami miliki, tetapi lebih baik untuk mengubah skema sedikit, membuatnya lebih cocok untuk Hive dan Spark. Faktanya adalah bahwa skema OSM sepenuhnya dinormalisasi, cara dan hubungan tidak mengandung koordinat sama sekali. Untuk membangun poligon, Anda harus bergabung dengan node. Saya akan merekomendasikan melakukan operasi ini segera, menyimpan poligon baik sebagai array struktur (Hive dapat bekerja dengan array tipe komposit, peta dan struct), atau segera sebagai representasi serial, katakanlah, kelas Geometri. Cara melakukan ini adalah dalam contoh parket penulis.

Anda dapat mengulangi operasi serupa di tingkat hubungan, jika Anda mau, tetapi tidak sepadan. Pertama, Anda tidak akan selalu membutuhkan semua elemen hubungan, dan kedua, hubungan itu sendiri dalam OSM jauh lebih kecil.

Konverter ke Avro


Berikut ini adalah konverter lain, kali ini ke format Avro. Dan di sini dijelaskan di mana mendapatkan file yang selesai. Saya tidak mengukur ukuran, tapi saya pikir sekitar 15-20 file per planet harus sebanding dengan PBF. Artinya, ini adalah gigabyte, dan banyak.

Beberapa kesimpulan


Dan di mana geocoding, Anda bertanya? Ya, mengunduh peta dan mengekstraksi alamat hanyalah bagian dari keseluruhan tugas. Saya harap ini yang terjadi.

Source: https://habr.com/ru/post/id438374/


All Articles