Разработчик
0,0
рейтинг
11 февраля в 15:24

Разработка → 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 на гитхабе и фидбека в целом.
Минкин Андрей @Gen1us2k
карма
21,0
рейтинг 0,0
Разработчик
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (14)

  • 0
            {"address":
                {"properties":
                    {
                        "centroid": {
                            "type": "geo_point" # need to reverse geocoding
                        }
    
                    }
                }
            }
    


    Судя по этому фрагменту конфига для эластика, обратный геокодинг не гарантирует нахождение если визуально попали в здание, алгоритм может посчитать иначе?
    • 0
      Да. Сейчас у меня в апи ищеться по дистанции 20 метров.
      На продакшне же по дистанции 200 метров и отсортированы по возрастанию.
      Проблем с реверсом нет
  • –1
    А ссылку на GitHub дадите?
  • 0
    Данные geofabrik.de для чего-нибудь вроде Кубы пробовали?
    • 0
      Посмотрел Кубу. Ничего хорошего сказать не могу :(
  • +1
    Есть ещё Gazetteer
  • 0
    Когда были проблемы (очень долго) поиска пересечений, разбивал карту на NxN частей, для каждой части считал попадающие куски, после чего на каждой части для кусков искал пересечения.
  • 0
    Gen1us2k, спасибо! можно подробнее о том, как Вы делаете «Автоматически пополнятся новыми данными от водителей»?
    • 0
      Оператор оформляет заказ, мы получаем по нему координаты из ES.
      Водитель когда забирает клиента, шлет свои координаты. Мы смотрим, если расстояние между точкой, откуда забрал водитель и точкой, которая разрезолвилась по поиску больше 200 метров, то кладем данные в рядом стоящий индекс. В дальнейшем может быть будем как-то использовать эти данные для импорта в осм например
      • 0
        Не нужно импорт. Максимум заметки автоматом ставить.
      • 0
        Прям все-все водители с координатами?
        • 0
          Есть проверка на нулевые координаты. Импортить данные автоматически в ОСМ будет сложно
  • 0
    Имел честь испытать потыкать на данных Челябинской области. В поиск поэтому лучше всего было вбивать в начале город, а то непредсказуемо кидало по разным НП. Короче (а долго тыкать не стал) в первую очередь поискал свой дом с дробью. Дробь не ищется, вместо нее следует ставить пробел, и то только в полном формате (см. выше). Худо-бедно получилось, вот только иногда вместо дома с дробью находит например детский сад с таким же номером на той же улице (так совпало), но естественно с другим адресом. Видимо надо приоритеты подкручивать.
    По словам экспериментатора (Го-адепт все дела) индексация одной области занимает весьма существенное время, так что про целую страну нечего и думать на домашних мощностях. В общем ожидайте от него пуллреквестов и успеха в развитии проекта! Да собственно вы уже в слаке вовсю общаетесь, чего я тут распинаюсь… ))

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.