Поезда пригородного сообщения — электрички — остаются одним из самых массовых видов пассажирского транспорта в России. За год ими пользуются миллионы пассажиров, которые проезжают суммарно сотни миллиардов километров на тысячах электричек. Только в январе 2017 года, по данным столичного департамента транспорта, опубликованным в едином хранилище данных правительства Москвы (ЕХД), пассажиропоток пригородного железнодорожного транспорта составил 42,6 млн человек. Это выше на 4,1% по сравнению с показателями прошлого года.
Наличие, доступность и точность расписания курсирования электричек волнует каждого пассажира, а для тех, кто его формирует и доносит до людей, является важной и очень непростой задачей.
Меня зовут Александр Подлевских, я ведущий инженер-разработчик компании Туту.ру, тимлид в команде электричек, и в статье расскажу про технические детали и сложности построения онлайн расписания, как все это работает, каким образом мы используем данные, предоставляемые РЖД, и как наши пользователи помогают нам поддерживать расписание в актуальном состоянии, не догадываясь об этом.
![](https://habrastorage.org/r/w1560/web/ed5/dec/75c/ed5dec75c3fd49c7a604fd6a5fde2c27.png)
График движения поездов — это отображение процесса движения поезда в декартовой системе координат. В таком виде представляется график движения поездов на железной дороге.
На территории России действует порядка 30 пригородных пассажирских компаний (ППК), каждая из которых отвечает за обслуживание пассажиров на определенной территории. Каждая ППК на основании транспортного заказа регионов, пожеланий пассажиров и исследований формирует предложения по изменению расписания, которые раз в год (примерно в начале лета) направляются в ОАО «РЖД».
ОАО «РЖД», получив заявки на расписание электричек, пассажирских и грузовых поездов, в течение нескольких месяцев разрабатывает новый график движения поездов (новое расписание) и в конце года вводит его в действие. Такое расписание, действующее со второго воскресенья декабря каждого года по вторую субботу декабря следующего года, называется нормативным или базовым. Именно оно, как правило, вывешивается на больших стендах на станциях и платформах, именно оно напечатано в книжках, которые можно купить в кассе на ряде станций.
Вместе с тем, большинство пассажиров крупных железнодорожных узлов (например, московского) знают, что на участках с интенсивным движением смысла в базовом расписании немного. Дело в том, что на железной дороге регулярно требуется проводить ремонтные работы, которые в большинстве случаев невозможно провести без частичного закрытия движения поездов. И тогда ОАО «РЖД» разрабатывает вариантный график движения поездов, предусматривающий, например, поочередное движение поездов по одному пути в обе стороны на одном из перегонов. Другими словами, в базовое расписание вносятся временные изменения. И такие изменения вносятся в расписание постоянно, и не только из-за ремонтных работ.
До появления интернет-ресурсов с расписанием узнать о временных изменениях можно было в основном только из объявлений на станциях. Причем объявление — это не расписание на конкретный день, а, как правило, листочек формата А4 с изменениями к базовому расписанию. И таких листочков могло быть несколько на один день. Например, по одному из них электричка шла в 15:50 вместо 15:30, по другому — эта же электричка шла с пропуском ряда остановок, а по третьему — с изменениями на поздний вечер, куда мало кто смотрел (к примеру, запускалась электричка, которая шла в 15:40 вместо 22:00). Кстати, на многих станциях до сих пор есть такие объявления. Иллюстрацией может служить пример из жизни: как-то раз решил мой коллега из Туту.ру поехать из Москвы в Ржевский район с пересадкой, доехал на электричке из Москвы до Волоколамска и узнал, что нужный ему пригородный поезд до Ржева из-за ремонтных работ будет только завтра, в Москве информации об этом не было.
С появлением онлайн-ресурсов узнавать расписание стало значительно проще — достаточно зайти на сайт или в мобильное приложение, ввести станции отправления и назначения, дату, и система покажет, какие электрички будут именно в этот день с учетом всех плановых временных изменений, известных к настоящему моменту. Не нужно изучать кучу бумажек с изменениями. И Туту.ру стал первым в России онлайн ресурсом, на котором еще в 2003 году стало публиковаться не только базовое расписание, но и временные изменения.
Создать такой ресурс и поддерживать расписание в актуальном состоянии было непросто. За изменениями приходилось следить вручную: сами создатели сервиса ездили по вокзалам, фотографировали и переписывали расписание и объявления. Понятно, что объехать все-все станции было физически невозможно, поэтому изменения в расписания вносились с неточностями. И тут очень помогали наши пользователи — писали и звонили в Туту.ру, предоставляли нам информацию из первых рук.
Но все равно ошибки в расписании были, поэтому мы стали искать дополнительные источники информации. Так, вскоре после появления пригородных пассажирских компаний (ППК), которые были также заинтересованы в корректном информировании пассажиров о расписании, мы договорились с ними о получении данных о расписании и изменениях к нему по всем поездам по всем станциям. Появление данного источника информации позволило существенно повысить качество расписания. Если еще в 2005 году практически каждый пользователь сталкивался хоть с одной ошибкой на сайте, то спустя 10 лет подавляющее большинство пользователей всегда видело точное и достоверное расписание.
Поскольку ошибки в данных от ППК хоть и редко, но встречаются, и наши операторы тоже иногда ошибаются, мы не стали останавливаться и подключили ещё один источник — Центральную базу данных пригородного расписания Главного вычислительного центра ОАО «РЖД», в которую сотрудники ОАО «РЖД» вносят расписание пригородных поездов и изменения к нему по всей России.
Сейчас на Туту.ру можно найти информацию о расписаниях, маршрутах и графиках движения электричек по 17 «регионам» (условная разбивка территории, примерно по границам действия ответственности соответствующих ППК). Туту.ру получает данные основного расписания перед введением его в действие, а также информацию о временных изменениях в расписании (варианты движения электричек на конкретные дни).
Эта информация попадает в нашу базу данных силами операторов, которые в полуручном режиме вносят ее через интерфейс. По тем направлениям, с которыми у нас нет партнерских отношений, специалисты вручную просматривают сайты расписаний и вносят данные в ручном режиме. Такой подход требует больших трудозатрат и может приводить к ошибкам, в результате которых наше расписание не полностью совпадает с реальным.
Когда мы решили подключать базу данных ГВЦ, мы не знали точно, каким образом получится ее использовать. Изначально предполагалось, что это станет дополнительным источником данных для получения большего количества данных, возможно, более точных. Известно было, что некоторые детали в модели расписаний у нас и в системе ГВЦ отличаются: например, электричка двигается по одному маршруту, доезжает до конечной станции, какое-то время стоит на этой станции, потом у нее меняется номер и она продолжает движение дальше, но по другому расписанию и маршруту. Как правило, в системе ГВЦ эти два поезда фигурируют как разные, и на сайте РЖД не будет этого поезда в расписании от станции из первого участка до станции из второго. У нас такие ситуации обрабатываются индивидуально, и если есть уверенность, что этот состав просто стоит на станции и потом продолжает ехать дальше, поменяв номер, то он заводится как один объект. У него будет составной номер — номера исходных электричек, указанные через разделитель «/», — и этот состав будет присутствовать в результате поиска электричек между станциями из разных участков.
Изменения, которые отправляются из некоторых ППК (например ЦППК или СЗ ППК) партнерам/подписчикам, содержат данные не обо всех остановках электропоезда, а только об отдельных пунктах (железнодорожная станция, блок-пост, разъезд, путевой пост и т.п.), а время прохождения составом промежуточных пунктов (таких как остановочный пункт, платформа и другие), на которых она, тем не менее, останавливается, каждый партнер вычисляет по-своему.
Рассмотрим пример: электропоезд №6600 по Рижскому направлению по обычному расписанию следует ежедневно и имеет остановки в Нахабино в 5:04, Опалихе 5:10, Красногорской 5:14, Павшино 5:18 и далее. На 9 июля у поезда меняется расписание и от компании перевозчика приходит информация, что из Нахабино электричка будет выезжать в 4:57, а Павшино и далее будет ехать по стандартному графику.
Данные в ГВЦ вносятся такие: по станциям Нахабино и Павшино вносятся 4:57 и 5:18 соответственно, а время прохождения промежуточных станций вычисляется пропорционально изначальному графику хождения, т. е. в соотношении 6:4:4 (как будто электричка на этом участке идет медленнее) и получается, остановка в Опалихе переносится на 5:06, а на станцию Красногорская поезд проследует в 5:12. На сайте Туту.ру долгое время алгоритм вычисления был похожим и в 99% случаев именно такое движение и будет у поезда. Но бывали случаи, когда причина изменения исчезала (например, ремонт) и электричка двигалась на участке с обычной скоростью. В нашем примере это означало бы, что до Опалихи она бы доехала за 6 минут (5:03), далее до Красногорской еще за 4 минуты (5:07), до Павшино еще за 4 минуты (5:11). После чего, чтобы следовать графику, состав бы стоял на станции до 5:18 и дальше бы шел согласно графику.
Что бы это означало для пользователей? Пользователь, пришедший на станцию Красногорская в 5:10, в итоге ждал бы следующую электричку. Из-за таких случаев на сайте Туту.ру время прохождения остановочных пунктов, по которым точное время неизвестно, теперь вводится по алгоритму, отличному от ГВЦ. Время вычисляется на основании исходного графика движения или, вообще, минимального времени прохождения электрички, между заданными станциями. Мы даем пользователю, с большой долей вероятности, время меньшее на несколько минут, чем поедет электричка. Лучше ведь прийти на платформу на пару минут раньше, чем на пару минут позже.
Кроме того, были замечены и ошибки, связанные с человеческим фактором, которые были допущены при внесении расписания в систему ГВЦ. По этим и другим причинам было решено, что напрямую импортировать данные из ГВЦ нежелательно. Вместо этого важнее выяснить, чем отличаются данные, которые хранятся в ГВЦ и у нас. На основании этих данных, а также на основании других источников (в том числе, фактических проверок следования поездов на станциях в сложных случаях), специалисты будут принимать решение, какие данные «вернее» (или будут полезнее пользователям).
Но прежде чем что-то сравнивать, нужно установить хотя бы какие-то связи между объектами. Изначально у нас не было ни соответствий поездов, ни соответствий станций и не было полей, по которым это соответствие можно было строго установить. В базе ГВЦ обнаружилось примерно 25 тысяч объектов станций и 15 тысяч объектов поездов, что осложняло поиск соответствующих поездов «в лоб», т. е. перебором и сравнением каждой станции с каждой станцией и каждого поезда с каждым поездом.
С учетом описанных выше возможных расхождений в алгоритме заполнения моделей, сравнение пришлось бы проводить нечеткое. Это значит, что мы искали бы не точное равенство объектов, а объекты с незначительными отличиями в одном из полей данных, например, отличие времени отправления на 2-3 минуты на одну из дат следования. Нечеткое сравнение довольно дорогостоящее действие, а с учетом того, что пар объектов для сравнения были бы сотни миллионов, такой метод не дал бы результата за разумное время. И в итоге, установленных соответствий было бы немного, потому что изначально не были известны все особенности.
Делалось это в несколько этапов и несколько проходов. Первым делом нужно было установить соответствия между объектами станций. По тем идентификаторам, которые были у нас и в базе ГВЦ, соответствие однозначно установить не удавалось. Например, в России существует 9 остановочных пунктов «105 КМ» и 17 остановочных пунктов «106 КМ». Так что, сравнивать названия было не очень эффективно: станций с уникальными названиями, для которых удалось найти уникальные станции в базе ГВЦ, оказалось порядка 10%.
В этом плане очень помог наш специалист по базе данных расписаний Алексей Деркачев, который где-то раскопал соответствие между семизначными кодами станций Экспресс-3 (которые у нас широко используются в качестве одного из идентификаторов станций) и кодом станции из базы данных ГВЦ. С помощью этой таблицы удалось найти пару примерно для половины станций, которые у нас участвуют в расписаниях электричек. После того как получилось сопоставить хотя бы такое количество станций, можно было приступить к следующему этапу: попробовать найти одни и те же поезда.
Для этого автоматический скрипт прошелся по всем найденным парам станций и сделал выборку расписаний электричек по конкретной станции. Далее каждый набор полученных электричек сравнивался, и при нахождении точного соответствия (т.е. количество станций в маршруте одно и то же, время прибытия/отправления поезда по каждой станции по порядку совпадает, номер электрички похож, недельный график совпадает), дубли удалялись и в нашем расписании оставалась только одна электричка.
Таким образом, для части электричек удалось найти пары. После установки соответствий между поездами, можно было опять вернуться к станциям — пройтись по найденным парам поездов и, раз они одинаковые, то и станции в маршруте скорее всего одни и те же. Это дало еще некоторое количество соответствий станций. После чего можно было опять попробовать поискать соответствия поездов. Попутно можно было экспериментировать с разными параметрами поиска, разными допущениями, учитывать все новые и новые особенности формирования и хранения расписания. После десятка итераций базу соответствий можно было уже использовать.
Данные расписаний электричек меняются достаточно часто: вносятся сотни изменений в день, а перед началом и окончанием дачного сезона изменения могут доходить до нескольких тысяч в день. Кроме того, изменения не всегда одновременно попадают и в нашу базу, и в базу ГВЦ, тем более что по регламенту взаимодействия, подгружать обновления данных мы можем только в определенное время два раза в сутки. А вносить данные в свою базу специалисты могут круглосуточно.
Каждый раз делать сверку по всем поездам достаточно дорогостоящая по времени операция, критерии сравнения могут меняться (например, часть расхождений в одну минуту может считаться незначительной и на эти расхождения можно не обращать внимание) и сами данные могут поменяться за это время, могут добавиться новые электрички, для которых еще не найдены соответствия. В поиске несоответствий нам помогают наши клиенты. Каждую секунду на сайте происходит в среднем 10 поисков расписания.
По каждому поиску в фоновом режиме запрашиваются данные из локальной копии данных ГВЦ и происходит сравнение. Если электрички похожи (по номеру, недельному графику и времени прохождения станции), но для них нет соответствия, то оно устанавливается. Если соответствие есть, но данные расходятся, то найденное несоответствие сохраняется. И в дальнейшем специалисты расписания смогут посмотреть общий список несоответствий, расхождений по конкретной паре поездов и выяснить, почему данные расходятся, и затем принять решение, менять ли их у нас на сайте или нет.
На данный момент вся система находится еще в процессе доработки, как с точки зрения сравнения моделей, так и с точки зрения удобства отображения и работы с этим, потому что расхождений достаточно много, большинство из них незначительные и их не нужно показывать в первую очередь. Различия моделей и используемых принципов ведения расписания могут отражаться на точности сравнения.
Несколько лет назад в нашей компании благодаря команде DevOps появилась возможность создавать микросервисы. Стало возможным отдельно от монолита реализовывать в своем сервисе новый функционал.
Так появился микросервис, который хранит в себе все данные расписаний из ГВЦ в том же самом формате, которому отвечает база данных, и реализует АПИ, отвечающее на поисковые запросы (откуда-куда-дата, расписание по станции и маршрут конкретной электрички). Это микросервис, который отвечает на поисковые запросы данными из нашего хранилища, сравнивает два набора данных, хранит данные о расхождениях в моделях.
![](https://habrastorage.org/r/w1560/web/415/35d/8ce/41535d8ce36342a6b2e0b4c70eb61564.png)
При поиске электричек по какому-нибудь маршруту на сайте происходит вызов сервиса расписания, и перед тем как вернуть результат, из него в шину отправляется событие с вычисленными данными. Сервис сравнения прослушивает эти события, при получении данных запрашивает аналогичные данные из сервиса-хранилища данных из ГВЦ и производит сравнение двух полученных наборов.
Если по поездам с уже установленными связями находится расхождение в данных, то об этом генерируется еще одно событие, которое прослушивается в сервисе-хранилище несоответствий. Если же для каких-то поездов связи нет, но по данным видно, что они сильно похожи, то они связываются.
![](https://habrastorage.org/r/w1560/web/99d/0b1/03c/99d0b103c14b4d1ea6c4e35f38cd025c.png)
![](https://habrastorage.org/r/w1560/web/848/873/4af/8488734af8a74dc5bfe2731ce1c8936c.png)
Система не стоит на месте и мы все время ее дорабатываем. Пока еще есть различия в способах формирования и заполнения моделей данных расписания. Из-за них в итоговом списке различий накапливается значительное количество записей, которые не нужно учитывать, что сильно усложняет ориентирование в нем и, как следствие, реагировать на проблемы сложнее. Но мы работаем над этим.
Мы продолжаем работать над автоматической установкой соответствий между объектами станций и поездов. «Команда электричек» постоянно работает над улучшением сервиса, чтобы вам было удобно им пользоваться.
В следующей статье я планирую рассказать в деталях про структуру моделей, подробнее остановлюсь на алгоритме их сравнения. Помимо этого, опишу выявленные отличия и как эволюционирует система на их основании. Если у вас есть вопросы по теме статьи либо предложения и пожелания по самому продукту, то обязательно пишите.
Наличие, доступность и точность расписания курсирования электричек волнует каждого пассажира, а для тех, кто его формирует и доносит до людей, является важной и очень непростой задачей.
Меня зовут Александр Подлевских, я ведущий инженер-разработчик компании Туту.ру, тимлид в команде электричек, и в статье расскажу про технические детали и сложности построения онлайн расписания, как все это работает, каким образом мы используем данные, предоставляемые РЖД, и как наши пользователи помогают нам поддерживать расписание в актуальном состоянии, не догадываясь об этом.
![](https://habrastorage.org/web/ed5/dec/75c/ed5dec75c3fd49c7a604fd6a5fde2c27.png)
График движения поездов — это отображение процесса движения поезда в декартовой системе координат. В таком виде представляется график движения поездов на железной дороге.
На территории России действует порядка 30 пригородных пассажирских компаний (ППК), каждая из которых отвечает за обслуживание пассажиров на определенной территории. Каждая ППК на основании транспортного заказа регионов, пожеланий пассажиров и исследований формирует предложения по изменению расписания, которые раз в год (примерно в начале лета) направляются в ОАО «РЖД».
ОАО «РЖД», получив заявки на расписание электричек, пассажирских и грузовых поездов, в течение нескольких месяцев разрабатывает новый график движения поездов (новое расписание) и в конце года вводит его в действие. Такое расписание, действующее со второго воскресенья декабря каждого года по вторую субботу декабря следующего года, называется нормативным или базовым. Именно оно, как правило, вывешивается на больших стендах на станциях и платформах, именно оно напечатано в книжках, которые можно купить в кассе на ряде станций.
Вместе с тем, большинство пассажиров крупных железнодорожных узлов (например, московского) знают, что на участках с интенсивным движением смысла в базовом расписании немного. Дело в том, что на железной дороге регулярно требуется проводить ремонтные работы, которые в большинстве случаев невозможно провести без частичного закрытия движения поездов. И тогда ОАО «РЖД» разрабатывает вариантный график движения поездов, предусматривающий, например, поочередное движение поездов по одному пути в обе стороны на одном из перегонов. Другими словами, в базовое расписание вносятся временные изменения. И такие изменения вносятся в расписание постоянно, и не только из-за ремонтных работ.
До появления интернет-ресурсов с расписанием узнать о временных изменениях можно было в основном только из объявлений на станциях. Причем объявление — это не расписание на конкретный день, а, как правило, листочек формата А4 с изменениями к базовому расписанию. И таких листочков могло быть несколько на один день. Например, по одному из них электричка шла в 15:50 вместо 15:30, по другому — эта же электричка шла с пропуском ряда остановок, а по третьему — с изменениями на поздний вечер, куда мало кто смотрел (к примеру, запускалась электричка, которая шла в 15:40 вместо 22:00). Кстати, на многих станциях до сих пор есть такие объявления. Иллюстрацией может служить пример из жизни: как-то раз решил мой коллега из Туту.ру поехать из Москвы в Ржевский район с пересадкой, доехал на электричке из Москвы до Волоколамска и узнал, что нужный ему пригородный поезд до Ржева из-за ремонтных работ будет только завтра, в Москве информации об этом не было.
С появлением онлайн-ресурсов узнавать расписание стало значительно проще — достаточно зайти на сайт или в мобильное приложение, ввести станции отправления и назначения, дату, и система покажет, какие электрички будут именно в этот день с учетом всех плановых временных изменений, известных к настоящему моменту. Не нужно изучать кучу бумажек с изменениями. И Туту.ру стал первым в России онлайн ресурсом, на котором еще в 2003 году стало публиковаться не только базовое расписание, но и временные изменения.
Создать такой ресурс и поддерживать расписание в актуальном состоянии было непросто. За изменениями приходилось следить вручную: сами создатели сервиса ездили по вокзалам, фотографировали и переписывали расписание и объявления. Понятно, что объехать все-все станции было физически невозможно, поэтому изменения в расписания вносились с неточностями. И тут очень помогали наши пользователи — писали и звонили в Туту.ру, предоставляли нам информацию из первых рук.
Но все равно ошибки в расписании были, поэтому мы стали искать дополнительные источники информации. Так, вскоре после появления пригородных пассажирских компаний (ППК), которые были также заинтересованы в корректном информировании пассажиров о расписании, мы договорились с ними о получении данных о расписании и изменениях к нему по всем поездам по всем станциям. Появление данного источника информации позволило существенно повысить качество расписания. Если еще в 2005 году практически каждый пользователь сталкивался хоть с одной ошибкой на сайте, то спустя 10 лет подавляющее большинство пользователей всегда видело точное и достоверное расписание.
Поскольку ошибки в данных от ППК хоть и редко, но встречаются, и наши операторы тоже иногда ошибаются, мы не стали останавливаться и подключили ещё один источник — Центральную базу данных пригородного расписания Главного вычислительного центра ОАО «РЖД», в которую сотрудники ОАО «РЖД» вносят расписание пригородных поездов и изменения к нему по всей России.
Каким образом сервис Туту.ру поддерживает актуальность расписания
Сейчас на Туту.ру можно найти информацию о расписаниях, маршрутах и графиках движения электричек по 17 «регионам» (условная разбивка территории, примерно по границам действия ответственности соответствующих ППК). Туту.ру получает данные основного расписания перед введением его в действие, а также информацию о временных изменениях в расписании (варианты движения электричек на конкретные дни).
Эта информация попадает в нашу базу данных силами операторов, которые в полуручном режиме вносят ее через интерфейс. По тем направлениям, с которыми у нас нет партнерских отношений, специалисты вручную просматривают сайты расписаний и вносят данные в ручном режиме. Такой подход требует больших трудозатрат и может приводить к ошибкам, в результате которых наше расписание не полностью совпадает с реальным.
Когда мы решили подключать базу данных ГВЦ, мы не знали точно, каким образом получится ее использовать. Изначально предполагалось, что это станет дополнительным источником данных для получения большего количества данных, возможно, более точных. Известно было, что некоторые детали в модели расписаний у нас и в системе ГВЦ отличаются: например, электричка двигается по одному маршруту, доезжает до конечной станции, какое-то время стоит на этой станции, потом у нее меняется номер и она продолжает движение дальше, но по другому расписанию и маршруту. Как правило, в системе ГВЦ эти два поезда фигурируют как разные, и на сайте РЖД не будет этого поезда в расписании от станции из первого участка до станции из второго. У нас такие ситуации обрабатываются индивидуально, и если есть уверенность, что этот состав просто стоит на станции и потом продолжает ехать дальше, поменяв номер, то он заводится как один объект. У него будет составной номер — номера исходных электричек, указанные через разделитель «/», — и этот состав будет присутствовать в результате поиска электричек между станциями из разных участков.
Изменения, которые отправляются из некоторых ППК (например ЦППК или СЗ ППК) партнерам/подписчикам, содержат данные не обо всех остановках электропоезда, а только об отдельных пунктах (железнодорожная станция, блок-пост, разъезд, путевой пост и т.п.), а время прохождения составом промежуточных пунктов (таких как остановочный пункт, платформа и другие), на которых она, тем не менее, останавливается, каждый партнер вычисляет по-своему.
Рассмотрим пример: электропоезд №6600 по Рижскому направлению по обычному расписанию следует ежедневно и имеет остановки в Нахабино в 5:04, Опалихе 5:10, Красногорской 5:14, Павшино 5:18 и далее. На 9 июля у поезда меняется расписание и от компании перевозчика приходит информация, что из Нахабино электричка будет выезжать в 4:57, а Павшино и далее будет ехать по стандартному графику.
Данные в ГВЦ вносятся такие: по станциям Нахабино и Павшино вносятся 4:57 и 5:18 соответственно, а время прохождения промежуточных станций вычисляется пропорционально изначальному графику хождения, т. е. в соотношении 6:4:4 (как будто электричка на этом участке идет медленнее) и получается, остановка в Опалихе переносится на 5:06, а на станцию Красногорская поезд проследует в 5:12. На сайте Туту.ру долгое время алгоритм вычисления был похожим и в 99% случаев именно такое движение и будет у поезда. Но бывали случаи, когда причина изменения исчезала (например, ремонт) и электричка двигалась на участке с обычной скоростью. В нашем примере это означало бы, что до Опалихи она бы доехала за 6 минут (5:03), далее до Красногорской еще за 4 минуты (5:07), до Павшино еще за 4 минуты (5:11). После чего, чтобы следовать графику, состав бы стоял на станции до 5:18 и дальше бы шел согласно графику.
Что бы это означало для пользователей? Пользователь, пришедший на станцию Красногорская в 5:10, в итоге ждал бы следующую электричку. Из-за таких случаев на сайте Туту.ру время прохождения остановочных пунктов, по которым точное время неизвестно, теперь вводится по алгоритму, отличному от ГВЦ. Время вычисляется на основании исходного графика движения или, вообще, минимального времени прохождения электрички, между заданными станциями. Мы даем пользователю, с большой долей вероятности, время меньшее на несколько минут, чем поедет электричка. Лучше ведь прийти на платформу на пару минут раньше, чем на пару минут позже.
Кроме того, были замечены и ошибки, связанные с человеческим фактором, которые были допущены при внесении расписания в систему ГВЦ. По этим и другим причинам было решено, что напрямую импортировать данные из ГВЦ нежелательно. Вместо этого важнее выяснить, чем отличаются данные, которые хранятся в ГВЦ и у нас. На основании этих данных, а также на основании других источников (в том числе, фактических проверок следования поездов на станциях в сложных случаях), специалисты будут принимать решение, какие данные «вернее» (или будут полезнее пользователям).
Но прежде чем что-то сравнивать, нужно установить хотя бы какие-то связи между объектами. Изначально у нас не было ни соответствий поездов, ни соответствий станций и не было полей, по которым это соответствие можно было строго установить. В базе ГВЦ обнаружилось примерно 25 тысяч объектов станций и 15 тысяч объектов поездов, что осложняло поиск соответствующих поездов «в лоб», т. е. перебором и сравнением каждой станции с каждой станцией и каждого поезда с каждым поездом.
С учетом описанных выше возможных расхождений в алгоритме заполнения моделей, сравнение пришлось бы проводить нечеткое. Это значит, что мы искали бы не точное равенство объектов, а объекты с незначительными отличиями в одном из полей данных, например, отличие времени отправления на 2-3 минуты на одну из дат следования. Нечеткое сравнение довольно дорогостоящее действие, а с учетом того, что пар объектов для сравнения были бы сотни миллионов, такой метод не дал бы результата за разумное время. И в итоге, установленных соответствий было бы немного, потому что изначально не были известны все особенности.
Установка соответствий объектов станций и поездов
Делалось это в несколько этапов и несколько проходов. Первым делом нужно было установить соответствия между объектами станций. По тем идентификаторам, которые были у нас и в базе ГВЦ, соответствие однозначно установить не удавалось. Например, в России существует 9 остановочных пунктов «105 КМ» и 17 остановочных пунктов «106 КМ». Так что, сравнивать названия было не очень эффективно: станций с уникальными названиями, для которых удалось найти уникальные станции в базе ГВЦ, оказалось порядка 10%.
В этом плане очень помог наш специалист по базе данных расписаний Алексей Деркачев, который где-то раскопал соответствие между семизначными кодами станций Экспресс-3 (которые у нас широко используются в качестве одного из идентификаторов станций) и кодом станции из базы данных ГВЦ. С помощью этой таблицы удалось найти пару примерно для половины станций, которые у нас участвуют в расписаниях электричек. После того как получилось сопоставить хотя бы такое количество станций, можно было приступить к следующему этапу: попробовать найти одни и те же поезда.
Для этого автоматический скрипт прошелся по всем найденным парам станций и сделал выборку расписаний электричек по конкретной станции. Далее каждый набор полученных электричек сравнивался, и при нахождении точного соответствия (т.е. количество станций в маршруте одно и то же, время прибытия/отправления поезда по каждой станции по порядку совпадает, номер электрички похож, недельный график совпадает), дубли удалялись и в нашем расписании оставалась только одна электричка.
Таким образом, для части электричек удалось найти пары. После установки соответствий между поездами, можно было опять вернуться к станциям — пройтись по найденным парам поездов и, раз они одинаковые, то и станции в маршруте скорее всего одни и те же. Это дало еще некоторое количество соответствий станций. После чего можно было опять попробовать поискать соответствия поездов. Попутно можно было экспериментировать с разными параметрами поиска, разными допущениями, учитывать все новые и новые особенности формирования и хранения расписания. После десятка итераций базу соответствий можно было уже использовать.
Непрерывный поиск расхождений в расписании
Данные расписаний электричек меняются достаточно часто: вносятся сотни изменений в день, а перед началом и окончанием дачного сезона изменения могут доходить до нескольких тысяч в день. Кроме того, изменения не всегда одновременно попадают и в нашу базу, и в базу ГВЦ, тем более что по регламенту взаимодействия, подгружать обновления данных мы можем только в определенное время два раза в сутки. А вносить данные в свою базу специалисты могут круглосуточно.
Каждый раз делать сверку по всем поездам достаточно дорогостоящая по времени операция, критерии сравнения могут меняться (например, часть расхождений в одну минуту может считаться незначительной и на эти расхождения можно не обращать внимание) и сами данные могут поменяться за это время, могут добавиться новые электрички, для которых еще не найдены соответствия. В поиске несоответствий нам помогают наши клиенты. Каждую секунду на сайте происходит в среднем 10 поисков расписания.
По каждому поиску в фоновом режиме запрашиваются данные из локальной копии данных ГВЦ и происходит сравнение. Если электрички похожи (по номеру, недельному графику и времени прохождения станции), но для них нет соответствия, то оно устанавливается. Если соответствие есть, но данные расходятся, то найденное несоответствие сохраняется. И в дальнейшем специалисты расписания смогут посмотреть общий список несоответствий, расхождений по конкретной паре поездов и выяснить, почему данные расходятся, и затем принять решение, менять ли их у нас на сайте или нет.
На данный момент вся система находится еще в процессе доработки, как с точки зрения сравнения моделей, так и с точки зрения удобства отображения и работы с этим, потому что расхождений достаточно много, большинство из них незначительные и их не нужно показывать в первую очередь. Различия моделей и используемых принципов ведения расписания могут отражаться на точности сравнения.
Техническая реализация
Несколько лет назад в нашей компании благодаря команде DevOps появилась возможность создавать микросервисы. Стало возможным отдельно от монолита реализовывать в своем сервисе новый функционал.
Так появился микросервис, который хранит в себе все данные расписаний из ГВЦ в том же самом формате, которому отвечает база данных, и реализует АПИ, отвечающее на поисковые запросы (откуда-куда-дата, расписание по станции и маршрут конкретной электрички). Это микросервис, который отвечает на поисковые запросы данными из нашего хранилища, сравнивает два набора данных, хранит данные о расхождениях в моделях.
Пополнение базы расхождений
![](https://habrastorage.org/web/415/35d/8ce/41535d8ce36342a6b2e0b4c70eb61564.png)
При поиске электричек по какому-нибудь маршруту на сайте происходит вызов сервиса расписания, и перед тем как вернуть результат, из него в шину отправляется событие с вычисленными данными. Сервис сравнения прослушивает эти события, при получении данных запрашивает аналогичные данные из сервиса-хранилища данных из ГВЦ и производит сравнение двух полученных наборов.
Если по поездам с уже установленными связями находится расхождение в данных, то об этом генерируется еще одно событие, которое прослушивается в сервисе-хранилище несоответствий. Если же для каких-то поездов связи нет, но по данным видно, что они сильно похожи, то они связываются.
Процессы работы специалистов расписания электричек с базой несоответствий
![](https://habrastorage.org/web/99d/0b1/03c/99d0b103c14b4d1ea6c4e35f38cd025c.png)
Процессы актуализации данных расхождений
![](https://habrastorage.org/web/848/873/4af/8488734af8a74dc5bfe2731ce1c8936c.png)
Заключение
Система не стоит на месте и мы все время ее дорабатываем. Пока еще есть различия в способах формирования и заполнения моделей данных расписания. Из-за них в итоговом списке различий накапливается значительное количество записей, которые не нужно учитывать, что сильно усложняет ориентирование в нем и, как следствие, реагировать на проблемы сложнее. Но мы работаем над этим.
Мы продолжаем работать над автоматической установкой соответствий между объектами станций и поездов. «Команда электричек» постоянно работает над улучшением сервиса, чтобы вам было удобно им пользоваться.
В следующей статье я планирую рассказать в деталях про структуру моделей, подробнее остановлюсь на алгоритме их сравнения. Помимо этого, опишу выявленные отличия и как эволюционирует система на их основании. Если у вас есть вопросы по теме статьи либо предложения и пожелания по самому продукту, то обязательно пишите.