Когда-нибудь задумывались, как работает поисковая система? В этом посте я хотел бы показать вам общее представление о внутренней работе поисковой системы и о том, как ее можно использовать для быстрого доступа к вашим данным. Я не буду вдаваться в технические детали, то, что я здесь описываю, справедливо для любой поисковой системы на основе Lucene , будь то сама Lucene, Solr или Elasticsearch .
вход
Обычно поисковая система не зависит от реального источника данных индексации. Чаще всего вы помещаете в него данные через API, который уже должен быть в ожидаемом формате, в основном это строки и типы данных, например целые числа. Не имеет значения, находятся ли эти данные изначально в документе в файловой системе, на веб-сайте или в базе данных.
Поисковые системы работают с документами, которые состоят из полей и значений. Хотя не всегда используется напрямую, вы можете думать о документах как о документах JSON. Для этого поста представьте, что мы создаем базу данных книг. В нашем упрощенном мире книга состоит только из названия и одного или нескольких авторов. Это будет два примера документов:
1
2
3
4
5
6
7
8
|
{ "title" : "Search Patterns" , "authors" : [ "Morville" , "Callender" ], } { "title" : "Apache Solr Enterprise Search Server" , "authors" : [ "Smiley" , "Pugh" ] } |
Несмотря на то, что структура обоих документов в нашем случае одинакова, формат документа не нужно фиксировать. Оба документа могут иметь совершенно разные атрибуты, тем не менее оба могут храниться в одном и том же индексе. В действительности вы будете стараться, чтобы документы были похожими, в конце концов, вам нужен способ обработки документов в вашем приложении.
У самой Lucene нет даже понятия ключа. Но, конечно, вам нужен ключ для идентификации ваших документов при их обновлении. И Solr, и Elasticsearch имеют идентификаторы, которые могут быть выбраны приложением или автоматически сгенерированы.
Анализ
Для каждого индексируемого поля применяется специальный процесс, называемый анализом. То, что он делает, может отличаться от поля к полю. Например, в простом случае он может просто разделить термины на пустое пространство и удалить любую пунктуацию, чтобы шаблоны поиска стали двумя терминами: поиск и шаблоны .
Структура индекса
Перевернутый индекс, используемый поисковыми системами, похож на карту, которая содержит поисковые термины в качестве ключа и ссылку на документ в качестве значения. Таким образом, процесс поиска — это просто поиск термина в индексе, очень быстрый процесс. Это могут быть термины, которые индексируются для наших примеров документов.
поле | Срок | Идентификатор документа |
---|---|---|
заглавие | апаш | 2 |
предприятие | 2 | |
Узоры | 1 | |
Поиск | 1,2 | |
сервер | 2 | |
Solr | 2 | |
автор | Callender | 1 |
Morville | 1 | |
Pugh | 2 | |
Smiley | 2 |
Реальный индекс содержит больше информации, например, информацию о положении, чтобы включить запросы фраз и частоты для расчета релевантности документа для определенного поискового запроса.
Как мы видим, индекс содержит ссылку на документ. Этот документ, который также хранится с поисковым индексом, не обязательно должен совпадать с нашим входным документом. Вы можете определить для каждого поля, хотите ли вы сохранить исходное содержимое, которое обычно контролируется с помощью атрибута с именем сохранено. Как правило, у вас должны быть все поля, которые вы хотели бы отображать с результатами поиска. При индексировании большого количества полных книг, и вам не нужно отображать их на странице результатов, может быть лучше вообще не хранить их. Вы по-прежнему можете искать его, так как термины доступны в индексе, но вы не можете получить доступ к исходному контенту.
Подробнее об анализе
Глядя на структуру индекса выше, мы уже можем представить, как может работать процесс поиска книги. Пользователь вводит термин, например, Solr , этот термин затем используется для поиска документов, содержащих этот термин. Это хорошо работает для случаев, когда пользователь вводит термин правильно. Поиск solr не будет соответствовать нашему текущему примеру.
Чтобы смягчить эти трудности, мы можем использовать процесс анализа, уже упомянутый выше. Помимо токенизации, которая разбивает значение поля на токены, мы можем выполнить дополнительную предварительную обработку, например, удалить токены, добавить токены или изменить токены (TokenFilter).
Для нашего книжного шкафа на первых порах может быть достаточно сделать нижний регистр для входящих данных. Таким образом, значение поля Solr будет сохранено в индексе как solr . Чтобы позволить пользователю также искать Solr с заглавной буквой, нам нужно также выполнить анализ запроса. Часто для индексации используется один и тот же процесс, но существуют также случаи для разных анализаторов.
Процесс анализа зависит не только от содержания документов (типы полей, язык текстовых полей), но и от вашего приложения. Возьмем один общий сценарий: добавление синонимов для терминов в индекс. Вы можете подумать, что вы просто взяли огромный список синонимов, таких как WordNet, и добавили их в каждое ваше приложение. На самом деле это может снизить качество поиска ваших пользователей, так как слишком много ложных срабатываний. Кроме того, для определенных условий домена ваших пользователей WordNet может вообще не содержать правильных синонимов.
дупликация
При разработке структуры индекса есть две конкурирующие силы: часто вы либо оптимизируете скорость запроса, либо размер индекса. Если у вас много данных, вам, вероятно, следует позаботиться о том, чтобы хранить только те данные, которые вам действительно нужны, и даже помещать в индекс только те термины, которые необходимы для поиска. Зачастую для небольших наборов данных размер индекса не имеет большого значения, и вы можете спроектировать свой индекс для производительности запросов.
Давайте рассмотрим пример, который может иметь смысл для обоих случаев. В нашей книжной информационной системе мы хотели бы отобразить алфавитную навигацию по фамилии автора. Если пользователь нажимает на А, должны отображаться все книги авторов, начинающиеся с буквы А. При использовании синтаксиса запроса Lucene вы можете сделать что-то подобное с поддержкой подстановочных знаков: просто выполните запрос, содержащий букву, по которой щелкнул пользователь, и завершающий символ *, например * .
Запросы с подстановочными знаками стали очень быстрыми с последними версиями Lucene, тем не менее, это все еще влияет на время запроса. Вы также можете выбрать другой способ. При индексации данных вы можете добавить еще одно поле, в котором просто хранится первая буква имени. Вот как может выглядеть соответствующая конфигурация в Elasticsearch, но концепция для Lucene и Solr одинакова:
01
02
03
04
05
06
07
08
09
10
11
12
|
"author" : { "type" : "multi_field" , "fields" : { "author" : { "type" : "string" }, "letter" : { "type" : "string" , "analyzer" : "single_char_analyzer" } } } |
Под капотом будет создан другой словарь терминов для поля author.letter. Для нашего примера это будет выглядеть так:
поле | Срок | Идентификатор документа |
---|---|---|
author.letter | С | 1 |
M | 1 | |
п | 2 | |
S | 2 |
Теперь вместо выдачи запроса с подстановочными знаками в поле автора мы можем напрямую запросить поле author.letter с буквой. Вы можете даже построить навигацию из всех терминов в индексе, используя такие методы, как фасетирование, чтобы извлечь все доступные термины для поля из индекса.
Вывод
Это основы индексации данных для поисковой системы. Инвертированная структура индекса делает поиск действительно быстрым, переводя некоторую обработку в фазу индексации. Когда мы не связаны какими-либо проблемами размера индекса, мы можем спроектировать наш индекс для производительности запросов и добавить дополнительные поля, которые дублируют некоторые данные. Этот дизайн запросов делает поисковые системы похожими на то, как используется множество решений NoSQL.
Если вы хотите углубиться в темы, я рекомендую посмотреть выступление Адриана Гранда « Что есть в индексе Lucene ». Он показывает некоторые из концепций, которые я упомянул здесь (и многие другие), а также то, как они реализованы в Lucene.
Ссылка: | Абсолютные основы индексации данных от нашего партнера JCG Флориана Хопфа в блоге Dev Time . |