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

Что должен находить поиск

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

Рассмотрим небольшую учебную библиотеку, похожую по устройству на ProfessorWeb. Постепенно мы подготовим её документы из Markdown, добавим браузерный индекс, а затем сравним его с отдельным поисковым сервисом. В конце появится поиск по смыслу. Сейчас не нужны сервер, модель или библиотека ранжирования: нам требуется договориться о данных и ожидаемом поведении.

Три разных намерения

Запрос «Запросы LINQ to XML» похож на название конкретного урока. Посетитель ожидает увидеть этот урок среди первых результатов. Запрос «обработка XML» шире: подходящими могут оказаться несколько материалов, объясняющих разные операции. Вопрос «как выбрать элементы документа» выражает задачу, но может вообще не содержать названия используемой технологии.

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

Добавим ещё один случай: технический идентификатор. В нашей библиотеке есть C#, .NET и метод fetch. Знак решётки или точка могут быть частью названия. Алгоритм, который без объяснения удаляет всю пунктуацию, способен смешать разные термины. Позднее мы разберём нормализацию; пока отметим, что точный технический запрос тоже должен присутствовать в оценке.

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

Общая библиотека курса

Создайте для собственной практики папку search-lab. В учебных исходниках будут шесть опубликованных документов и один черновик. Сокращённый список позволяет вручную объяснить каждый результат, прежде чем переходить к тысячам страниц.

ID Материал Постоянный URL
xml Запросы LINQ to XML /my/LINQ/linq_xml/level7/7_1.php
markdown Статический сайт из Markdown /articles/markdown-guide.html
nginx Настройка Nginx /articles/nginx-basics.html
sql Соединение таблиц SQL /articles/sql-joins.html
csharp Типы данных C# /articles/csharp-types.html
fetch Запросы Fetch /articles/javascript-fetch.html

Старый путь XML-урока взят из существующей библиотеки ProfessorWeb. Остальные адреса здесь обозначают учебные страницы; они не являются обещанием, что такие статьи уже опубликованы на настоящем сайте. Короткие тексты примеров мы подготовим отдельно. Их назначение — показать работу алгоритма, а не заменить полный материал.

ID связывает документ с ожидаемым результатом. URL нужен для перехода читателя. Заголовок описывает материал. Если текст урока изменился, эти роли не должны случайно поменяться: обновление содержания не требует нового публичного адреса или новой личности документа.

Черновик оставим в исходниках специально. Он поможет увидеть разницу между библиотекой редактора и публичным поиском. Исключение черновика должно происходить до публикации поисковых данных: скрыть его карточку в интерфейсе недостаточно, если текст уже доступен в скачиваемом JSON.

Реестр контрольных запросов

В папке search-lab/data подготовим queries.json. Ниже полный начальный набор; поле relevant содержит ID документов, которые редактор считает подходящими для указанной задачи.

[
  {"id":"q1","query":"LINQ XML","relevant":["xml"]},
  {"id":"q2","query":"Markdown","relevant":["markdown"]},
  {"id":"q3","query":"ngnix","relevant":["nginx"]},
  {"id":"q4","query":"соединить таблицы","relevant":["sql"]},
  {"id":"q5","query":"C#","relevant":["csharp"]},
  {"id":"q6","query":"получить данные с сервера","relevant":["fetch"]},
  {"id":"q7","query":"несуществующийтерминxyz","relevant":[]}
]

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

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

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

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

Что будем сравнивать

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

Быстрота не заменяет качество, а качество не позволяет игнорировать время ожидания. Результат, открывающийся через слишком долгую паузу, может мешать посетителю. Но до замеров не нужно назначать произвольное число миллисекунд обязательным пределом для любого устройства.

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

Зафиксируйте исходную версию набора запросов и документов. Пока в журнале результатов нет измерений: значения появятся после выполнения соответствующего примера. Слово «ожидается» означает прогноз по механизму, а не скрытое заявление о уже проведённой проверке.

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