Sphinx - Настраиваем поиск
Несомненно, одной из основных причин, почему вам может потребоваться использовать Sphinx, является возможность полнотекстового поиска. Благодаря большому количеству настроек, можно отрегулировать поиск таким образом, чтобы он максимально удовлетворял потребностям каждой конкретной задачи. В этой статье я постараюсь рассказать про некоторые из этих настроек более подробно, а также приведу примеры их использования.
Опция «charset_table»
Когда Sphinx индексирует документы или обрабатывает поисковой запрос, прежде всего он разбивает текст на слова (токены), но для того, чтобы правильно это сделать, ему необходимо знать, какие символы в тексте могут являться частью слов, а какие не могут.
Опция charset_table
задаёт таблицу допустимых символов. Если несколько допустимых символов в тексте идут один за
другим, то Sphinx воспринимает их как одно слово. Если символ не указан в таблице символов и,
соответственно, не считается допустимым, то Sphinx воспринимает его как разделитель.
По умолчанию для индексов с кодировкой utf-8 опция charset_table
выглядит следующим
образом:
charset_table = 0..9, A..Z->a..z, _, a..z, \
U+410..U+42F->U+430..U+44F, U+430..U+44F, U+401->U+451, U+451
Допустимые символы в таблице символов указываются через запятую. Записи 0..9
и
a..z
обозначают, что все символы идущие между указанными символами считаются
допустимыми. Можно также указывать отдельные символы, как это сделано с символом _
.
Запись A..Z->a..z
обозначает, что символы A..Z
считаются допустимыми,
но при обработке заменяются символами a..z
, т.е. по сути приводятся к нижнему
регистру. Это необходимо, чтобы поиск не был чувствителен к регистру.
Наконец, вторая строка по аналогии определяет правила обработки символов для кирилицы, которые
заданы в формате U+xxx
, что обязательно для всех символов, код которых больше 127.
По сути это означает следующее:
charset_table = 0..9, A..Z->a..z, _, a..z, \
А..Я->а..я, а..я, Ё->ё, ё
Пример
По умолчанию Sphinx воспринимает символы «Е» и «Ё» как различные. Мы можем изменить это поведение, чтобы, например, иметь возможность по запросу «сгущёнка» также находить документы со словом «сгущенка». Для этого в таблице символов необходимо изменить правила для символов «Ё» (U+401) и «ё» (U+451) тамим образом, чтобы эти символы отображались на символ «е» (U+0435).
charset_table = 0..9, A..Z->a..z, _, a..z, \
U+410..U+42F->U+430..U+44F, U+430..U+44F, U+401->U+0435, U+451->U+0435
Теперь во всех запросах символы «Е» и «Ё» будут считаться одинаковыми.
select * from recipes where match('сгущёнка');
Опция «blend_chars»
Опция blend_chars
похожа на опцию charset_table
, но задаёт смешанные символы, которые будут считаться
и допустимыми, и разделитеелями одновременно. При нахождении таких символов в тексте во время
индексации, Sphinx будет индексировать все возможные варианты. Например, если символ «&»
считается смешанным, а в индексируемом документе встретится текст «Рога&Копыта», то
проиндексированы будут три слова: «рога», «копыта» и «рога&копыта». При поиске же всегда будет
использоваться вариант, в котором все смешанные символы считаются допустимыми. Например, если
поисковой запрос будет содержать слово «рога&копыта», то поиск будет производиться именно по
нему, а не по словам «рога» и «копыта».
Опцию blend_chars
можно использовать вместе со связанной опцией
blend_mode
,
которая задаёт, какие комбинации допустимых и смешанных символов следует проиндексировать.
Например, можно индексировать слова со смешанными символами в начале слова, отбросив при этом
смешанные символы в конце, или наоборот. При этом можно указать несколько значений,
проиндексировав тем самым несколько различных комбинаций.
Пример
Предположим, что мы хотим организовать поиск книг по названию и найти книни по языкам «C#» или «C++»:
select * from book where match('C#');
select * from book where match('C++');
Поскольку символы «#» и «+» не являются допустимым (не указаны в таблице символов), то Sphinx
считает их разделителями и производит поиск только по слову «C». Добавить эти символы в таблицу
символов было бы неправильно. Вместо этого, укажем их в опции blend_chars
. Обратите
внимание, что символ «#» указан как «U+23», поскольку иначе он бы считался началом комментария.
blend_chars = +, U+23
Обновив индекс и повторив поиск, мы убедимся в том, что теперь Sphinx ищет именно по словам «C#» и «C++».
select * from book where match('C#');
select * from book where match('C++');
Опция «ignore_chars»
Опция ignore_chars
задаёт символы, которые Sphinx будет игнорировать, как будто их вообще нет в тексте. Таким
образом, если два слова разделены только игнорируемым символом, они «склеятся» и будут считаться
одним словом. Обычно, эту опцию следует использовать, если в индексируемом тексте присутствуют
символы мягкого переноса, поэтому чаще всего её использование выглядит следующим образом:
ignore_chars = U+AD
Опция «morphology»
После того, как обрабатываемый текст разбит на слова, в дело вступают морфологические алгоритмы
(если они, конечно, включены), которые заменяют все найденные слова на их нормализованную форму,
позволяя тем самым, например, по запросу «книга» находить документы, содержащие слова «книги»,
«книгу» или «книгой». В Sphinx могут использоваться три типа морфологических алгоритмов: стеммер
(stemmer), лемматайзер (lemmatizer) или фонетические алгоритмы. Для использования одного из них
необходимо в настройках индекса указать опцию
morphology
.
Стеммер
Стеммер является наиболее простым и быстрым алгоритмом, позволяющим найти основу слова (часть слова, которая является одинаковой для разных его форм) без использования дополнительных словарей и основываясь только на определённых правилах удаления суффиксов и окончаний для конкретного языка. Основным минусом стеммера является то, что он далеко не всегда позволяет точно определить основу слова. Например, слова «девушка» и «девушек» будут считаться различными, поскольку после обработки стеммером первое слово превратится в «девушк», а второе не изменится. Возможна и обратная ситуация, когда два морфологически различных слова приводятся стеммером к одной и той же основе и поэтому считаются одинаковыми.
Вот пример того, как стеммер нормализует слова «девушка», «девушки» и «девушек»:
Для использования стеммера для русского и английского языков необходимо в опции
morphology
указать значение stem_enru
.
morphology = stem_enru
Лемматайзер
Лемматайзер (появившийся только в версии 2.1.1-beta), в отличие от стеммера, использует морфологические словари, поэтому позволяет не просто находить основу слова, а приводить его к нормальной (словарной) форме. Поиск с использованием лемматайзера более точен, но за всё приходится платить - работает он немного медленнее, чем стеммер.
Вот пример того, как слова «девушка», «девушки» и «девушек» нормализует лемматайзер:
Поддержка лемматайзера в настоящее время реализована только для русского языка, реализация для
английского языка скорее всего будет доступна в следующих версиях Sphinx. Для использования
лемматайзера в первую очередь необходимо скачать
морфологические словари с сайта sphinxsearch.com и в
файле конфигурации в блоке indexer
указать путь к папке со словарями при помощи
опции lemmatizer_base
.
indexer
{
...
lemmatizer_base = c:/sphinx/data/dict/
}
После этого в опции morphology
нужно указать значение lemmatize_ru
или
lemmatize_ru_all
. При использовании опции lemmatize_ru_all
, Sphinx
будет индексировать все нормальные формы слова, если их несколько. Например, для слова «чайку»
нормальной формой может быть как «чайка», так и «чаёк».
morphology = lemmatize_ru
Фонетические алгоритмы
Помимо стеммера и лематайзера Sphinx также поддерживает два фонетических алгоритма: Soundex и Metaphone, которые, однако, работают только для английского яыка. Эти алгоритмы заменяют слова на их фонетический код таким образом, что разные по написанию, но схожие по звучанию слова будут считаться одинаковыми. Наиболее полезными фонетические алгоритмы могут оказаться, например, для поиска по фамилиям.
Для использования фонетических алгоритмов необходимо в опции morphology
указать
значение soundex
или metaphone
.
morphology = metaphone
Опция «wordforms»
Опция wordforms
задаёт путь к пользовательскому файлу словоформ, который имеет два основных назначения.
Во-первых, этот файл может быть использован, чтобы указать правильную нормализованную форму слова в тех случаях, когда стеммер делает это неправильно. Например, если необходимо указать, что слово «девушек» всё таки является словоформой от слова «девушка», то в файл словоформ можно дорбавить следующую строку:
девушек => девушк
Обратите внимание, что при использовании стеммера после знака =>
должна идти именно
основа слова («девушк», а не «девушка»), т.к. именно по основе слова впоследствии будет
производится поиск. Также обратите внимание, что если вы используете индекс в кодировке utf-8,
то файл словоформ тоже обязательно должен быть сохранён в этой же кодировке.
В результате слова «девушка» и «девушек» станут приводиться к одной основе «девушк» и будут считаться одинаковыми при поиске.
Во-вторых, при помощи файла словоформ можно организовать словарь поисковых синонимов. Например, если слову «Эппл» необходимо находить документы, содержащие слово «Яблоко», то в файл словоформ нужно добавить одну из следующих строк (в зависимости от того, пользуетесь вы стеммером или лемматайзером):
эппл => Яблок # Стеммер
эппл => Яблоко # Лемматайзер
Такие результаты будут получены при поиске по слову «Эппл» для стеммера:
А такие для лемматайзера
Опция «stopwords»
Опция stopwords
задаёт путь к файлу стоп-слов, которые игнорируются при индексации и поиске. Обычно в этот файл
рекомендуется помещать слова, которые встречаются в индексе настолько часто, что никак не влияют
на результат. Как правило это различные предлоги или союзы.
Например, если мы хотим, чтобы союз «и» игнорировался при поиске, мы можем добавить его в список стоп-слов. Тогда при поиске он будет игнорироваться:
Заключение
Если подытожить, то Sphinx имеет достаточно большое количество опций, правильная настройка которых может значительно влиять на качество поиска. Помимо опций, описанных в этой статье, он также поддерживает поиск по точному совпадению и по подстроке, а также поиск в html-документах.
А в следующей статье про Sphinx я планирую немного рассказать про распределённый поиск и привести несколько примеров.