Процесс создания геокодера на основе ElasticSearch, который ищет координаты по синонимам и по названиям заведений, ищет перекрестки и адреса в определенном радиусе, а также умеет делать реверс геокодинга и автоматически пополняется новыми данными от водителей. Репозиторий доступен по ссылке.
Предыстория
Когда мы проектировали геокодер для нужд Namba-Taxi мы столкнулись с недостатком важных данных.
Чего у нас не было:
- Полной карты от Яндекса, Google или 2GIS
- Доверия к GPS данным
Что у нас было:
- Очень разношерстные данные на входе
- Мы кое-где использовали Openstreetmap
- Своя накопленная база адресов с координатами
Что операторы могли вводить?
Операторы могли вводить адреса в разных форматах:
- Улица дом;
- Перекресток;
- Название заведения;
- Название точки;
- Микрорайон дом;
- Микрорайон улица дом.
И таких вариантов очень много, например:
- Киевская 28
- Киевская Советская
- 5–42
- 5 микрорайон советская 42
- ЦУМ
- кафе у Ашота
- шлагбаум
Проектирование
Был заложен следующий алгоритм:
- Сначала получаем геометрию по крупным населенным пунктам(города, столицы, деревни, жилые массивы);
- Выгружаем все возможные адреса и соотносим их к нужному жилому массиву, городу и другому населенному пункту, выставляя нужное значение;
- Выгружаем все дороги;
- Ищем пересечение дорог;
- Кладем все в индекс;
- Ищем.
Реализация
Учитывая то, что основной источник данных у нас это OSM, то фильтры для того, чтобы получить данные у нас такие:
- place=city,place=village,place=suburb,place=town,place=neighbourhood — для получения всех микрорайоны
- addr:street+addr:housenumber,amenity,shop,addr:housenumber — для получения адресов и названий заведений
- highway — для получения всех дорог
Встали сложности с поиском англоязычных названий на русском языке. Как пробовали это решить:
- Простая автоматическая транслитерация в русский. В итоге получалось абсурдной и не корректной. Пример конвертации данных был таким: City House -> Цити Хоусе
- Получение транскрипции слова и уже ее транслитерация. Получилось что-то вроде Adrenaline rush -> Эрденалин Рэш. Сносно, но нужен русский акцент, типа адреналин раш. Не подходит.
- Автоматическая транслитерация всех данных, с применением словаря замен. Подошел именно такой механизм. Все-таки простая транслитерация работает сносно. В итоге словарь наполнился в принципе быстро через несколько прогонов на данных.
С этим разобрались к этому моменту мы уже получаем данные, которые:
- Нормализированы и приведены к русскому языку;
- Адреса приведены к формату — страна, город, село или поселок, микрорайон или жилой массив, улица, дом
Следующая часть квеста — найти пересечения дорог. Сделали ее по-быстрому и получили очень медленную реализацию, сложностью O(n²). Как временный выход использовал Postgres+postgis для нахождения пересечений, пока не нашел хорошего алгоритма для поиска пересечений.
В итоге получился хороший парсер данных с OSM, который кладет данные в ElasticSearch. Который получил простое название importer.
Автоматизация
Учитывая то, что постоянно выкачивать и создавать индексы в ElasticSearch в скоре надоело, появился компонент updater. Появилась также автоматическая конфигурация в JSON формате.
Процесс выкачивания файла и импорт его в ElasticSearch автоматизировался. Плюс к этому появилась возможность обновлять данные в ElasticSearch без даунтайма, благодаря алиасам.
Как это работает:
- Updater качает файл;
- Узнает текущую версию индекса с конфига;
- Инкрементит версию и создает новый индекс;
- Заполняет его данными;
- Меняет алиасы;
- Удаляет старый индекс.
Получил такие бенефиты от этого:
- Пишем конфиг;
- Запускаем ./ariadna update;
- Идем пить кофе;
- Получаем готовый настроенный индекс.
Также для удобства прикрутил простой вебинтерфейс с картой и возможностью поиска.
Автоматическое пополнение данными
Помимо ОСМ у нас еще есть много водителей и операторы, которые забивают заказы. Соотвественно у нас есть имя и координаты Сделана такая схема:
- Треки водителей хранятся в индексе drivers_data;
- Данные с ОСМ хранятся в индексе osm_data;
- Объединены они через алиас addresses по которому и происходит поиск адресов.
Данные от водителей заносятся, если у нас погрешность в определенных координатах больше, чем 200 метров.
Заключение
Что умеет геокодер Ariadna?
- Искать координаты по синонимам. например ШВК — ШампанВинКомбинат;
- Умеет искать адреса в определенном радиусе (например для себя с сделал поиск адресов в 30 км от центра города);
- Искать по названию заведений (кафе у Ашота например);
- Искать перекрестки;
- Искать адреса в микрорайонах и жил массивах;
- Делать реверс геокодинг;
- Автоматически пополнятся новыми данными от водителей;
- Реверс геокодинга.
Из каких компонентов состоит геокодер:
- Импортер данных;
- Апдейтер данных;
- Веб интерфейс.
Минусы
- Протестирован только для Кыргызстана;
- Нет демки (Хотя работу его можете увидеть в приложении Namba-Taxi, когда мы определяем ваш адрес по местоположению);
- Нет поддержки всех схем адресации.
Поэтому будем рады, если кто-нибудь поможет его допилить и для хорошего поиска по другим странам и городам.
Если кому-то проект показался интересным, то мы не против любой критики, пул реквестов, issues на гитхабе и фидбека в целом.
Ранее статья была опубликована тут.