Как мы расписание общественного транспорта в 2ГИС добавляли

ivvqvzsblexpxjsszzlpjetb3ry.png

2ГИС помогает ориентироваться в городе. Открываешь приложение, вводишь в поиск название улицы или организации, находишь, радуешься. После того, как нужная организация найдена, возникает резонный вопрос: как же туда добраться? И если автомобильным сценариям мы в последнее время уделяли значительное внимание, то поиск проезда на общественном транспорте оказался немного подзабыт. Я расскажу про то, как создавался поиск проезда, поделюсь тонкостями сбора и обработки информации.

Откуда взялась задача


Мы любим общаться с пользователями. В конце 2016 года мы провели опрос, дабы выяснить, как пользуются общественным транспортом наши пользователи. Результат получился любопытным — делимся.

i-9u6r_jys61twylegtvt41f2fe.png

»Как часто вы пользуетесь общественным транспортом? »

В целом, во всех городах присутствия 2ГИС более половины респондентов пользуются общественным транспортом каждый день. Чем крупнее город, тем больше людей использует общественный транспорт ежедневно. В будние дни он максимально популярен у жителей Москвы и Санкт-Петербурга, а в остальных городах люди активно пользуются общественным транспортом и в выходные.

С частотой использования разобрались, время посмотреть, какие виды общественного транспорта — фавориты горожан.

tsvoo9wtcalya_eudsy1cprznoe.png

»Какие виды транспорта вы предпочитаете? »

Относительно топовых позиций результат вполне ожидаем. В крупных городах предпочтительный вид транспорта — метро. Второе место у автобусов. Более трети москвичей пользуются электричкой. В Новосибирске ездят на маршрутках, а в Петербурге, помимо всего прочего, любят трамваи.

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

Следующим этапом стало выяснение слабых сторон 2ГИС. Мы пришли к пользователям с вопросом — чего нам не хватает?

vyupoxdh2-wozlhte0_wrszbiwu.png

»Чего не хватает в 2ГИС? »

Задачу с выбором конкретных видов транспорта мы решили с помощью недавно выпущенных фильтров, где пользователь может указать, каким видом транспорта он хочет воспользоваться. А вот вопрос «Когда приедет автобус?» остался актуальным для 64% опрошенных пользователей.

Именно в этот момент мы задумались о добавлении расписания движения общественного транспорта в 2ГИС и о том, как же все наши желания реализовать.

Где взять данные?


Это первый вопрос, с которым мы столкнулись. Ведь в большинстве случаев для нашего продукта мы собираем данные самостоятельно. Когда в городе построен новый микрорайон, специалист по сбору информации едет на заявленное место и выверяет всю необходимые детали «в полях». С новой фичей привычный подход не сработал бы. Отправить специалистов на остановки — бесполезная трата времени и сил, так как расписание постоянно меняется. Появляются новые перевозчики, маршруты оптимизируются, зима сменяется весной. За время сбора плановые расписания и интервалы движения просто-напросто устарели бы.

Да. К сожалению, данные устаревают, и это была вторая проблема, вставшая перед нами. Логичным и вполне очевидным решением было обратиться к тем, кто это расписание составляет и контролирует — в подведомственные учреждения. Зачастую конструктивный диалог начинался только через тернистый бюрократизированный путь и советов, вроде: «Пишите в Минтранс/Дептранс, а потом поговорим».

Нашли ответственного, начали диалог — полбеды.

Далее начинался марафон с:

  1. Объяснениями, что мы хотим и зачем нам это.
  2. Убеждениями, что наша задумка полезна для жителей и гостей города.
  3. Доказательством, что 2ГИС не монетизирует построение маршрутов с учётом периодичности движения.
  4. Заверениями, что это безопасно.


Победа? А вот и нет.

Самое курьёзное — техническая сторона вопроса, а в частности — формат передачи данных. Да, в каких-то городах есть автоматизированные системы по ведению расписания и API для доступа к этим данным (gtfs или передача в json в собственном формате), но это ждало нас далеко не везде. Где-то просто предлагали парсить сайт, опять-таки из соображений безопасности не предоставляя доступа к базам. Где-то были готовы выслать файлы (.xls, .doc, .pdf), но только один раз, без возможности своевременно обновлять информацию в нашем справочнике.

Первое место по оригинальности мы присвоили фотографии листочка бумаги с расписанием движения общественного транспорта.

А ведь изначально задачка казалась тривиальной — получить общедоступные данные от первоисточника!

Загрузка данных во внутреннюю систему


Получив доступ и загрузив к себе данные, мы встали ещё перед одной проблемой. Нельзя просто так взять и загрузить чужие данные во внутреннюю систему.

Почему?


Самое время рассказать, как внутри 2ГИС хранятся исходные данные.
Все внутренние продукты для сбора и хранения информации мы разрабатываем сами. Софт для картографов (которые отвечают не только за карту, но и за транспорт) называется Fiji — подробный рассказ здесь (если кратко, то в Fiji картографы рисуют транспортный граф, вносят данные по общественному транспорту, хранят расписание. В систему уже внесены все собранные маршруты).

Первый анализ показал, что маршруты внутри нашей системы и у поставщиков различаются, причём местами — кардинально. Нужно было как-то сопоставить свои собственные маршруты и маршруты поставщика. Можно, конечно, сделать это вручную, но мы решили написать свой собственный матчер.

lbucfqgsyqgi1ocukur1lni5s3k.png

В качестве промежуточного формата для хранения выбрали GTFS, как уже общепринятый стандарт, плюс некоторые поставщики умеют выдавать расписание в этом формате. Для промежуточной БД, на которой работает матчер, выбрали PostgreSQL, а сам матчер написали для простоты на Python.

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

При этом ошибки в сопоставлении всё равно есть, так как у поставщиков бывает очень большое количество направлений: отдельно на каждый будний день, отдельно на каждый выходной. Также возникают ошибки в сопоставлении кольцевых маршрутов, если они по разному заведены у поставщика и в нашей внутренней системе (Fiji).

Поэтому конечное решение-таки за человеком — картограф может вручную отменить сопоставление расписания, если поймет, что алгоритм отработал неправильно.

Алгоритм


Ядро алгоритма поиска написано на C++. На самом деле, поиск проезда на общественном транспорте это не один алгоритм, а несколько. Поиск прохода до ближайших остановок считается нашим алгоритмом пешеходной маршрутизации, который, в свою очередь, состоит из двух алгоритмов — «пиксельного» (с помощью которого мы строим проход по территории без графа дорог) и обычного (уже по пешеходному графу до остановки).
В качестве же поискового алгоритма проезда между остановками у нас используется сильно модифицированный A*, в который мы добавили поддержку учёта расписания. И если раньше время ожидания транспорта на остановке было неким «среднестатистическим» временем для каждого проекта и каждого типа транспорта, то теперь учитывается или точное или интервальное расписание.

При этом в алгоритме пришлось учитывать много забавных нюансов в данных. Например, маршрут может иметь время отправления с остановки в 25 или даже в 47 часов. С точки зрения данных это значит, что это тот же рейс, что ходил в предыдущих сутках, и он просто ещё не завершил свою работу. Также нужно учитывать, что рейс может начать ходить «завтра» и, если пользователь ищет маршрут в конце текущих суток, то нужно заглядывать и в следующий день (актуально, если вы храните расписание по дням).

Отдельно решали проблему того, как комбинировать данные с расписанием и без расписания. В итоге решили, что маршруты без расписания по-прежнему участвуют в поиске, просто имеют меньший вес. При этом, если маршрут без расписания совпадает по остановочным платформам с маршрутом с расписанием, то мы его просто подклеим в выдачу, а если он идёт как-то по-другому, то это будет отдельный вариант проезда с меньшим весом, так как мы ничего не знаем про время ожидания на остановке.

Поскольку 2ГИС работает как онлайн, так и офлайн, то алгоритм работает и внутри приложения, и на сервере. Несмотря на то, что данные расписания более-менее статичны, серверный поиск у нас также используется, поскольку на медленных устройствах в случае наличия интернета запрос к серверу отработает намного быстрее, чем локальный поиск. Для серверного поиска у нас задействовано 8 поисковых бекендов, расположенных в трёх дата-центрах в Новосибирске, Москве и Дронтене (Голландия).

Релиз


Итоговый результат добавления расписания общественного транспорта в 2ГИС вы можете оценить в нашем мобильном приложении в Google Play и App Store. В веб-версии появится чуть позднее.

Зарелизившись, мы получили довольно много фидбэка. Проанализировав негативный, выделили две основные причины жалоб:

  1. Мы не рассказали пользователям должным образом, что в поиске проезда сейчас используется расписание и сломали привычные сценарии работы с приложением.
    При поиске маршрута вечером или ночью у пользователей пропали привычные маршруты в выдаче. Контрол выбора даты/времени поездки при построении маршрута выпал из сферы видимости.

    Большая часть обращений в техподдержку выглядела примерно так:

     — Здраствуйте, у вас поиск проезда в общественном транспорте стал неадекватным, потому что …. /описание конкретной проблемы/.
     — Вы знаете, мы выпустили расписание в поиске проезда на общественном транспорте, вот тут контрол, вы можете задать время, на которое планируется поездка.
     — Понятно, большое спасибо!

  2. Алгоритм старался не предлагать маршруты без расписания (или опускать их в выдаче) при наличии альтернативы с расписанием. Из-за этого в каких-то кейсах выдача стала менее релевантной.

    Нашим технологам пришлось в экстренном порядке уточнять и вручную вносить интервальное расписание по всем оставшимся видам транспорта, чтобы вернуть их в выдачу, а нам — проводить дополнительную настройку алгоритмов поиска.


Капитанские выводы


Какие же выводы можно сделать по итогам запуска?

  • Если планируете использовать чужие данные у себя в приложении — обязательно подумайте, как будете эти самые данные добывать. Не факт, что ваши ожидания и реальность совпадут. Учитывайте риски.
  • Если сильно меняете текущую логику работы приложения — обязательно расскажите пользователям об этом и научите их пользоваться новыми фичами: «Что нового» в сторах читают единицы.
  • Подготовьте техподдержку к всплеску обращений независимо от того, насколько хорошо вы рассказали про новую фичу и как ей пользоваться.


P.S. Про полноту данных


Поскольку договориться удалось не со всеми Дептрансами/Минтрансами — расписание пока есть только в Москве, Санкт-Петербурге, Новосибирске, Екатеринбурге, Красноярске, Омске, Челябинске, Краснодаре и Ростове-на-Дону. Повышать покрытие транспорта расписанием в этих городах, ровно как и добавлять новые города, мы будем по мере получения данных.

© Habrahabr.ru