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

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

  • как понять атмосферу заведения и добавили новый атрибут «вайб-фильтры»;

  • как находить похожие места по изображениям и сделали поиск по фото.

  • как дать пользователю возможность искать «по смыслу» и реализовали ИИ-поиск. 

Как понять атмосферу заведения: вайб-фильтры

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

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

Так мы добавили в поиск новый фильтр — «Вайб». Он учитывает не только тип кухни и оценки, но и повод, настроение, особенности атмосферу заведения. Алгоритмы ИИ анализируют карточки компаний, отзывы, меню и фото, чтобы предложить подходящие варианты. . 

Вера Романцова

Руководитель команды Качество данных 2ГИС

Чтобы сделать вайб-фильтры, мы:

  • Анализировали карточки компаний, отзывы, меню и фотографии интерьеров и блюд.

  • Использовали LLM для семантической разметки вайбов.

  • Придумали промпты для каждого вайба и автоматизировали сбор данных.

  • Проводили перекрёстную проверку разметки с помощью другой LLM.

Не обошлось и без подводных камней. В процессе работы мы часто сталкивались с тем, что два вайба могут давать неоднозначную картину о заведении. Например, «поработать» — это про наличие розетки у стола и уединённого местечка в зале. А «покормить детей» — это про наличие детского столика и уголка с игрушками. Как быть, если в одном заведении окажутся оба вайба, и человек, решивший поработать, придёт и обнаружит, что столик с розетками находится рядом с шумным детским уголком? Мы решили эту задачу с помощью дополнительной логики

Или другое — уточнение «границ» вайба. Например, вайб «добавить мистики» мы изначально задумывали как нечто загадочное — полагали, что сможем находить рестораны и кафе с приятной атмосферой приглушённого света. Однако в процессе реализации поняли, что в пул фотографий с приглушённым светом попадает всё, что угодно, и это не совсем то, что мы хотим видеть в рамках этого вайба. Тогда мы решили сместить акцент: добавив в фокус мистические элементы — свечи, черепа, узоры — мы смогли собрать пул заведений с более чёткой тематикой и интересной атмосферой.

Как находить похожие места:  фотопоиск 

Люди всё чаще ориентируются на визуальные впечатления. Им важно, как выглядит место, интерьер, подача блюд. Иногда хочется найти заведение, похожее на любимое кафе в другом городе. Или просто увидел фото десерта — и захотел найти, где подают нечто подобное. Раньше это было возможно только вручную. 

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

Егор Осинкин

Специалист по анализу данных 2ГИС

Вполне ожидаемо, что для фотопоиска нам нужно уметь переводить изображения в эмбеддинги — многомерные векторы признаков, по которым уже будем измерять сходство фотографий. Два фото похожи, если косинусное расстояние между их эмбеддингами маленькое. Как правило, эмбеддинги берут с последних слоёв глубоких нейросетей (далее по тексту будем называть нейросети моделями), поскольку те наилучшим образом описывают изображение целиком. Когда мы посчитаем эмбеддинги для всех фото, нужно будет их куда-то сложить, и, конечно, здесь нам нужна векторная база данных, которая, помимо хранения, осуществляет тот самый поиск по косинусному расстоянию. 

Поиск работает примерно так: пользователь выбирает фото, мы достаём из базы эмбеддинг этого фото и ищем в базе N других фото, эмбеддинги которых наиболее близки к референсному фото.

Выбор модели

Модель-эмбеддер выбирали, опираясь на метрики. Для этого на крауд-платформе был собран датасет, где разметчики ранжировали по сходству с референсной пять фотографий-кандидатов. Мы планировали раскатывать фотопоиск в первую очередь для рубрики «Поесть», то есть для заведений, связанных с едой. В этих заведениях в 2ГИС фотографии уже классифицируются на несколько альбомов, таких как «Еда и напитки», «Интерьер», «Атмосфера» и др. Наша цель — найти такую модель-эмбеддер, которая для всех альбомов будет одинаково хорошо подбирать фото, релевантные к референсному. Выбирали между Florence, Siglip2, Siglip2giant, Eva, AnyLoc (с понижением размерности эмбеддингов через SVD) и RADIOv2. Лучше всех на нашем бенчмарке себя показал Siglip2giant с небольшим отрывом от RADIOv2.

Выбор базы данных

Первое демо мы собрали с QDrant, но опыт использования этой базы в других проектах показывал, что потребление оперативной памяти этой базой растёт довольно быстро. Нам не хотелось регулярно докидывать ресурсы под поды в k8s, поэтому решили поискать альтернативы — выбор пал на pgvector. Путём настройки параметров Postgres и индексов мы получили 500 RPS — примерно в 5 раз больше, чем планировали для этой фичи. При этом потребление оперативной памяти жёстко ограничено конфигурацией Postgres, и в рамках нагрузочного тестирования значительного роста потребления RAM замечено не было.

Проблемы с полнотой поиска

В первой версии фичи мы планировали показывать ровно 100 похожих заведений, но в процессе разработки бэкенда обнаружилось несколько подводных камней. Во-первых, дубликаты, которые засоряют ленту: если у заведения несколько подразделений в городе, велик шанс, что фотографии в них похожи, а значит, все они всплывут в поиске. Поэтому из базы мы выбираем больше записей, чем нужно, и делаем дедупликацию. Вторая проблема — HNSW-индекс подразумевает трейд-офф между скоростью и полнотой поиска, поэтому в редких случаях для фото не находилось ни одного похожего, и нам очень хотелось это исправить. Улучшить ситуацию помогли индивидуальные HNSW-индексы для городов-миллионников, однако полностью проблема не ушла.

  • Решением стал fallback-механизм: в случае значительного недобора записей из БД повторяем запрос, но с более «жадными» параметрами поиска (т.е. мы жертвуем скоростью в пользу полноты):

    # Размер списка кандидатов при поиске в HNSW индексе
    # При поиске алгоритм поддерживает список из ef_search наиболее близких кандидатов
    # Чем больше значение, тем более тщательный поиск
    hnsw.ef_search: 256
    
    # Разрешаем базе совершать несколько итераций поиска пока не наберётся нужное число записей
    # по-умолчанию отключено.
    hnsw.iterative_scan: strict_order
    
    # Ограничивает количество векторов, которые будут рассмотрены, по-умолчанию 20000
    # Сильно влияет на полноту поиска
    hnsw.max_scan_tuples: 30000
    
    # Контролирует объем памяти для буферизации при сканировании
    # Значение 2 = выделяется в 2 раза больше памяти чем базовое
    # Больше памяти = меньше обращений к диску = быстрее поиск
    hnsw.scan_mem_multiplier: 2

    В отладке и подборе параметров очень помог этот issue на GitHub. Замеры показали, что latency при жадном поиске не превышает 300 мс, что вполне нас устраивает. К тому же ситуации, когда жадный поиск срабатывает, возникают крайне редко.

Как искать по смыслу: ИИ-поиск

Поиск в 2ГИС много лет работал на основе классических текстовых алгоритмов по структурированному справочнику организаций и адресов с учетом морфологии, геопозиции и популярности объектов. Это позволяло закрывать огромное количество сценариев. Но были и ограничения: если пользователь формулировал запрос в свободной форме («бар для шумных тусовок» или «паста с лисичками»), система не всегда находила релевантные результаты.

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

Никита Шварц

Руководитель команды NLP Search 2ГИС

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

Чтобы сделать поиск по смыслу возможным, нам пришлось решить сразу несколько задач.

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

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

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

  • разбор и интерпретация текста запроса;

  • формирование поискового пространства;

  • быстрый поиск ближайших кандидатов;

  • ранжирование и фильтрация результатов.

Дополнительный вызов — производительность. Поиск в 2ГИС обрабатывает сотни запросов в секунду. Это значит, что семантический поиск должен не только быть точным, но и работать в режиме реального времени. Для этого мы используем оптимизированные индексы для векторного поиска и распределенные сервисы, которые агрегируют сотни гигабайтов данных и обеспечивают стабильную скорость ответа.

В итоговом пайплайне это выглядит так:

  1. Обработка запроса — разбираем текст, извлекаем сущности и намерения, кодируем их в эмбеддинг. 

  2. Обработка данных — отзывы, меню, карточки, фото и другие источники также отображаем в векторные представления. 

  3. Формирование поискового пространства — каждая организация описана десятками векторных признаков. 

  4. Сопоставление — помещаем запрос в это пространство и ищем ближайшие точки к запросу по семантической близости. 

  5. Ранжирование и фильтрация — учитываем геопозицию, популярность и другие параметры и формируем финальную поисковую выдачу. 

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

Продолжение следует

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

Мы продолжим развивать ИИ-поиск и уже добавили ещё одну деталь — короткие описания заведений прямо в выдаче. Эти тексты формируются автоматически на основе отзывов пользователей: мы обучили локальные LLM-модели решать задачу саммаризации и превращать десятки мнений наших пользователей в компактный абзац. В нём отражаются атмосфера, популярные блюда или особенности сервиса — всё то, что помогает понять особенности заведения еще до перехода в карточку.

И это только начало, впереди ещё много интересного!

Если хотите работать в 2ГИС, мы как раз ищем NLP-инженера, который поможет нам улучшать понимание пользовательских запросов, развивать ML-модели для поиска и работать с большим объемом данных.

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