Перейти к содержанию

Управление ранжированием через контрольные запросы

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

Используем прежний корпус «Индекса» и build_query из query.py. Поисковые запросы, сравнения и замеры не запускались. Файл control-queries.json в архиве содержит предметные ожидания для будущего ручного наблюдения, а не результаты выполненных тестов. Основной механизм фразы описан в официальной документации match_phrase.

Требование до изменения весов

Запрос «HTTP кеширование» имеет понятный кандидат: article-107, где тема отражена в заголовке и основном объяснении. Запрос «Node.js» должен помогать найти материал о Node.js, а не просто любую статью, в которой есть слово node. Запрос «запросы» шире: у него может быть несколько полезных документов, и требование единственного победителя было бы искусственным.

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

Для начала сравните порядок с одинаковыми весами полей и с title^3. Если заголовок точно обозначает тему, усиление может приблизить нужную статью. Но если заголовки редакционно широкие, а тело содержит подробный ответ, чрезмерный вес title способен ухудшить выбор. Параметр должен отвечать устройству вашего корпуса, а не считаться обязательной формулой любого поиска.

Предпочтение связной фразы

В bool.should добавлено условие фразы по title. Следующий листинг — полный список дополнительных предпочтений из итогового запроса; text уже проверен в build_query:

'should': [
    {'match_phrase': {'title': {
        'query': text.strip(), 'boost': 2
    }}},
    {'term': {'identifiers': {
        'value': text.strip().lower(), 'boost': 3
    }}}
]

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

В окружающем bool есть must и filter. Дополнительные should здесь используются как предпочтения уже допустимых кандидатов, а не как единственное условие допуска. Это существенная деталь: если создать новый bool только из should, его правила обязательности будут иными. Нельзя копировать такой список в произвольное место DSL и предполагать тот же смысл.

Фразовое предпочтение помогает различать материал, где слова обозначают единую тему, и статью, где они встречаются далеко друг от друга. Однако короткое совпадение в названии не доказывает полноту ответа. Поэтому контрольный набор должен включать и запросы, где подробное объяснение находится только в теле. Иначе настройка будет оптимизирована для наиболее удобных заголовков.

Точный идентификатор имеет ограниченный вклад

Поле identifiers хранит node.js, c#, http и другие явно перечисленные обозначения. Дополнительный term получает всю строку поиска в нижнем регистре. Следовательно, запрос Node.js может совпасть с одним идентификатором, а запрос Node.js HTTP не превращается автоматически в два точных условия. Для нескольких обозначений нужен отдельный разбор намерения или другой договор запроса.

Это ограничение полезно: мы не пытаемся угадать, является ли каждое слово поисковой фразы технологией. Смешанная фраза продолжает работать через полнотекстовые поля, а точный канал помогает простому обозначению. Если продукту нужен специальный выбор технологии, лучше добавить явный фильтр identifiers с собственной проверкой значений.

В основном must остаётся multi_match. Поэтому точное совпадение identifiers само по себе не гарантирует попадание документа в кандидаты. Если tokenizer основного текста не даёт подходящего совпадения, дополнительный boost его не создаст. При будущей настройке нужно решить, следует ли точному идентификатору быть альтернативным способом допуска, и явно изменить query, а не только повысить число.

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

Сравнение результата без выдуманного измерения

Ожидаемый протокол будущего ручного наблюдения:

Запрос: HTTP кеширование
Проверить: article-107 присутствует в допустимых кандидатах
Сопоставить: порядок до и после предпочтения title
Объяснить: какая часть query создаёт совпадение, какая меняет вклад
Не утверждать: фиксированный score или измеренный процент улучшения

Здесь сначала проверяем присутствие нужного документа. Если он отфильтрован как staff или не прошёл условие and, обсуждать его позицию бессмысленно. Затем смотрим порядок, фрагменты и предметную полезность. Одно число score не показывает, отвечает ли статья на вопрос читателя, и не заменяет прочтение контрольных материалов.

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

Предпочтения не должны скрывать ошибки данных

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

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

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

Для самостоятельного разбора добавьте документ с очень коротким заголовком «HTTP», но текстом о другой задаче. Объясните, почему он может усилиться для короткого запроса и почему фраза «HTTP кеширование» должна проверяться отдельно. Далее обновим и удалим документы, сохраняя известное состояние импорта.

Оглавление серии