На первый взгляд кажется, что всё происходит мгновенно — пользователь вводит distributed systems и уже через несколько десятков миллисекунд получает результат. Но за это время поисковая система выполняет несколько этапов.
Сначала запрос анализируется: система приводит текст к нижнему регистру, разбивает его на слова, удаляет лишние символы и может применить stemming или добавить синонимы.
Например: cars может превратиться в car automobile.
После этого начинается поиск кандидатов.
Поисковая система обращается к инвертированному индексу и находит все документы, в которых встречаются слова из запроса. Это может быть:
- тысяча документов;
- сто тысяч документов;
- миллион документов.
Очевидно, показывать пользователю миллион результатов бессмысленно.
Поэтому следующий этап — ранжирование. Для каждого документа вычисляется score — оценка релевантности. В Elasticsearch по умолчанию для этого используется BM25. Алгоритм учитывает:
- как часто слово встречается в документе;
- насколько это слово редкое;
- насколько длинный документ.
В результате документы сортируются по score:
- Distributed Computing — 15.3
- Distributed Systems — 13.8
- Cluster Computing — 8.7
После этого Search API возвращает пользователю только верхнюю часть списка — например, первые 10 результатов.
Если говорить о современных поисковых системах, то всё становится ещё интереснее. Часто после BM25 запускается второй этап ранжирования:
- ML модели;
- CatBoost;
- нейронные сети;
- векторный поиск.
То есть BM25 сначала находит несколько сотен кандидатов, а ML выбирает лучшие из них.
Именно поэтому хороший поиск — это уже давно не просто база данных с текстовым индексом. Это целый pipeline, который начинается с анализа запроса и заканчивается сложным ранжированием результатов.