Поиск по MongoDB на примере Quto.ru

December 6, 2015

В далеком 2014 году я пришел на работу в компанию Rambler&Co и одним из моих первых заданий было улучшение текущего поиска. Задача была достаточно сложной (на тот момент), потому как незнание проекта и структуры хранения его в данных доставляло некоторые неудобства.

Более того, есть понятие “пакетов опций” (к примеру климат контроль отдельно стоит дороже чем в пакете) и “взаимоисключения опций” (к примеру кандей и климат контроль вместе не установить), а так же “возможнолсть взаимоисключения пакетов опций”.

После долгого “курения” структуры данных (она достаточна простая, однако дерево достаточно большое) было принято решение не городить изгороду из джоинов и кешей, которые на само деле нельзя было там применять по простой причине разных фильтров.

Как всегда, хочется не просто сделать работу, а сделать ее красиво и качественно. Было принято решение не просто написать поиск по фильтру, а так же считать на лету с учетом выбраных фильтров еще и их цену и, соответственно, вхождение в дельту по цене с учетом этих фильтров. К примеру, есть у нас опция “климат-контроль” и есть машинв “лада приора”.

Стоимость лады приоры, к примеру, 400 000 рублей. С учетом опции стоимость уже 450 000 рублей.

При условии указания дельты цены 200 000 - 400 000 не должны входить в поиск машины за 450 000 с учетом установленной опции.

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

В конечном итоге, спустя 2 недели, на продакшен был выкачен новый поиск.

###Что в итоге получили:

  • количество страниц в поиске + постраничная навигация (хоть и смешно, но до этого момента не было)
  • легкий индекс данных в Mongo (всего 11 Мб коллекция)
  • простой и расширяемый интерфейс для дальнейшего улучшения
  • легкая и быстрая индексация из БД в Mongo
  • быстрый поиск

###С чем пришлось столкнуться

  • были проблемы с сортировкой после UNWIND, оказалось что после того как снова собираются в группу - сортировка пропадает. Происходит это по вине асинхронности аггрегативных функций.
  • отсутствие связности (к примеру бренд-модель) заставило идти в сторону хранения дополнительной (избыточной) информации.

###Краткое описание

В Gist’e несколько файлов, вот их описание:

  • mongo_document_example.json - вид единичного документа в Mongo (пример);
  • mongo_query_example.json - пример запроса в Mongo, который генерирует набор скриптов;
  • Result.php - обработка результирующих данных
  • Search.php - объект (класс), осуществляющий поиск
  • SearchCriteriaBuilder.php - “строитель” запросов по условиям
  • SearchCriteriaDefault.php - “базовое условие” на основе фильтра
  • SearchHelper.php - для удобства =)

Конечно, рефакторинг бы не помешал. Уж очень стремно и глупо этот код поныне выглядит. Однако, свою задачу он выполняет. Разобраться в нем сможет даже джуниор. Добавить специфический фильтр не составит труда.

Все детали формирования запроса и логика его формирования в классе: SearchCriteriaDefault.

Посмотреть код на gist.github.com!

Благодарю за внимание!

Комментарии

comments powered by Disqus