Ariadna. Зачем нужен еще один геокодер для ОСМ?

в 12:24, , рубрики: Go, OpenStreetMap, OSM, Геоинформационные сервисы, геокодинг, поиск, реверс геокодинг

Всем привет!

Совсем недавно я закончил делать геокодер для своих целей Ariadna
Под катом рассказ о том, зачем я его делал и что он умеет.

В статье не будет ни строчки кода на Go. Зато будет полное описание работы геокодера и проблем, с которыми я встречался. А код можете посмотреть на гитхабе.

Предыстория

Я работаю в одной из бишкекских служб такси, что в Кыргызстане. Решили мы пооптимизировать нахождение координат по адресу для более оптимального распределения заказов.

Чего у нас нет:

  • Полной карты Яндекса, Гугла или 2Гис
  • Доверия к GPS данным

Что у нас есть:

  • Очень разношерстные данные на входе
  • Openstreetmap
  • Своя накопленная база адресов с координатами

Что пользователи могут вводить?

Пользователи могут вводить адреса в разных форматах:

  • Улица дом
  • Перекресток
  • Название заведения
  • Название точки
  • микрорайон дом
  • микрорайон улица дом

И таких вариантов очень много, например
Киевская 28
Киевская Советская
5-42
5 микрорайон советская 42
ЦУМ
кафе у Ашота
шлагбаум
И так далее

Постановка задачи

Сделать геокодер, который бы умел принимать любые данные на вход и отдавать им координаты
Язык поиска — только русский.

Как докатился до такой жизни

Перед тем, как делать свой велосипед я решил поресерчить решения, которые уже есть.
Были:

Чем не устраивал номинатим, который у нас был:

  • Сложен сам по себе
  • Сделан на php+с(Это не потому что пхп плохой, а потому что только для этого инструмента у нас стоит апач и пхп)
  • Сложная логика в хранимых процедурах Postgresql

Чем понравился Pelias:

  • Может работать с многими источниками геоданных
  • Поиск организован на ElasticSearch

В итоге решил отказаться от всех трех геокодеров и сделать свой инструмент по нескольким причинам:

  1. Я хочу разобраться с данными в OSM и импортить только нужные для поиска
  2. Я могу обрабатывать геоданные перед занесением в индекс
  3. Мне не нравиться жаваскрипт и node.js, отсюда и не желание делать поиск на основе пелиаса

Проектирование

Был заложен следующий алгоритм:

  1. Сначала получаем геометрию по крупным населенным пунктам(города, столицы, деревни, жилые массивы)
  2. Выгружаем все возможные адреса и соотносим их к нужному жилому массиву, городу и другому населенному пункту, выставляя нужное значение
  3. Выгружаем все дороги
  4. Ищем пересечение дорог
  5. Кладем все в индекс
  6. Ищем

Для реализации я выбрал Go, учитывая проекты типа pbf2json, golang-geo и многих других для обработки геоданных. Также хотелось покачать скилл именно в нем.

Реализация

С получением и парсингом данных с осм вроде разобрался. Для жилых массивов используем теги place=city,place=village,place=suburb,place=town,place=neighbourhood для фильтрации. Для получения адресов, зданий addr:street+addr:housenumber,amenity,shop,addr:housenumber
Все дороги можно получить с помощью тега highway

Встали сложности с поиском англоязычных названий на русском языке. Как пробовал это решить:

  1. Простая автоматическая транслитерация в русский. В итоге получалось абсурдной и не корректной. Пример конвертации данных был таким: City House -> Цити Хоусе
  2. Давай попробуем преобразовывать так. Получать транскрипцию слова и ее уже транслитерировать. Получилось что-то вроде Adrenaline rush -> Эрденалин Рэш. Сносно, но нужен русский акцент, типа адреналин раш.
  3. Подошел такой механизм. Автоматически транслитеризуем все данные, применяя словарь замен. Все-таки простая и тупая транслитерация работает сносно. Словарь наполнился в принципе быстро через несколько прогонов на данных.

С этим разобрались к этому моменту мы уже получаем данные, которые:

  1. Нормализированы и приведены к русскому языку
  2. адреса приведены к формату Страна, город, село или поселок, микрорайон или жилой массив, улица, дом

Следующая часть квеста — найти пересечения дорог. Сделал ее по быстрому и получил очень медленную реализацию, сложностью O(n^2). Как временный выход использую Postgres+postgis для нахождения пересечений, пока не нашел хорошего алгоритма для поиска пересечений.

В итоге получился хороший парсер данных с осм, который кладет данные в ElasticSearch. Который получил простое название importer

Автоматизируй это

Учитывая то, что постоянно выкачивать и создавать индексы в эластиксерче в скоре надоело, появился компонент updater. Появилась также автоматическая конфигурация в JSON формате.

Процесс выкачивания файла и импорт его в elastic search автоматизировался. Плюс к этому появилась возможность обновлять данные в эластиксерче без даунтайма, благодаря алиасам.

Как это работает:

  1. Updater качает файл
  2. Узнает текущую версию индекса с конфига
  3. Инкрементит версию и создает новый индекс
  4. Заполняет его данными
  5. Меняет алиасы
  6. Удаляет старый индекс

Получил такие бенефиты от этого:

  1. Пишем конфиг
  2. Запускаем ./ariadna update
  3. Идем пить кофе
  4. Получаем готовый настроенный индекс.

Также для удобства прикрутил простой вебинтерфейс с картой и возможностью поиска.

Автоматическое пополнение данными

Помимо ОСМ у нас еще есть много водителей и операторы, которые забивают заказы.
Соотвественно у нас есть имя и координаты
Сделана такая схема:

  1. Треки водителей хранятся в индексе drivers_data
  2. Данные с ОСМ хранятся в индексе osm_data
  3. Объединены они через алиас addresses по которому и происходит поиск адресов

Данные от водителей заносятся, если у нас погрешность в определенных координатах больше, чем 200 метров.

Итого

Получился геокодер который умеет:

  1. Искать координаты по синонимам. например ШВК — ШампанВинКомбинат
  2. Умеет искать адреса в определенном радиусе (например для себя с сделал поиск адресов в 30 км от центра города)
  3. Искать по названию заведений (кафе у Ашота например)
  4. Искать перекрестки
  5. Искать адреса в микрорайонах и жил массивах
  6. Делать реверс геокодинг
  7. Автоматически пополнятся новыми данными от водителей

Состоит из трех компонентов:

  1. Импортер данных
  2. Апдейтер данных
  3. Веб интерфейс

Минусы

  1. Протестирован только для Кыргызстана
  2. Нет демки
  3. Нет поддержки всех схем адресации

Поэтому надеюсь кто-нибудь поможет его допилить и для хорошего поиска по другим странам и городам.

Если кому-то проект показался интересным, то я не против любой критики, пул реквестов, issues на гитхабе и фидбека в целом.

Автор: Gen1us2k

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js