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

Всем привет!

Совсем недавно я закончил делать геокодер для своих целей 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 на гитхабе и фидбека в целом.

© Habrahabr.ru