Игорь Чакрыгин Игорь Чакрыгин

У любой задачи существует по крайней мере одно очевидное и невероятно простое для понимания неправильное решение

Sphinx - Источники данных, индексы, поля и атрибуты

В предыдущей статье я максимально подробно постарался описать процесс установки Sphinx в Windows. При этом я не останавливался на вопросах, что же это такое и для чего оно нужно.

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

Sphinx

Sphinx - это бесплатный механизм для полнотекстового поиска с открытым исходным кодом, ключевыми особенностями которого являются:

  • высокая скорость индексации и поиска;
  • возможность работы с различными источниками данных (базы данных, xml-файлы);
  • постобработка результатов (фильтрация, сортировка и группировка);
  • хорошая масштабируемость.

Приложения могут взаимодействовать со Sphinx несколькими способами, но самым простым и удобным, на мой взгляд, является специальный sql-подобный язык запросов, который носит название SphinxQL. В этом случае Sphinx использует протокол базы данных MySql, поэтому на каком бы языке мы не программировали, использовав нужный коннектор для этой базы данных, мы легко сможем подключиться к нему, выполнить запросы и получить результаты их выполнения.

Источники данных

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

source product
{
    type = ...
    ...
}

Опция type отвечает за тип источника данных. Она может иметь значения mysql, pgsql, mssql или odbc, если мы собираемся индексировать базу данных, или значения xmlpipe или xmlpipe2, если проиндексировать необходимо xml-файлы. Помимо этого в блоке source могут находиться другие опции, которые зависят от типа источника данных.

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

source mssql
{
    type = mssql
    ...
}
source product : mssql
{
    ...
}

Индексы

Для того, чтобы быстро выполнять полнотекстовый поиск, Sphinx строит структуру данных, которая специально оптимизирована для этого. Эта структура называется индексом. Все индексы, также как и источники данных, должны быть объявлены в файле конфигурации с помощью блока index (и тоже могут наследоваться), например:

index product
{
    type = ...
    ...
}

Существует три типа индексов: дисковые индексы (disk indexes), индексы реального времени (real-time indexes) и распределённые индексы (distributed indexes).

Дисковые индексы

Дисковые индексы строятся путём индексации одного или нескольких источников данных, которые указываются в качестве опций. Эти индексы обеспечивают максимальную скорость индексации и поиска. При объявлении дискового индекса в файле конфигурации опция type должна иметь значение plain (или вообще отсутствовать, т.к. значение plain является значением по умолчанию).

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

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

Индексы реального времени

Индексы реального времени (далее rt индексы), в отличии от дисковых индексов, вообще не используют источники данных. Вместо этого, как можно догадаться из названия, они позволяют добавлять документы в индекс и обновлять их в любой момент при помощи запросов на языке SphinxQL. При объявлении дискового rt индекса в файле конфигурации опция type должна иметь значение rt.

Распределённые индексы

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

Поля и атрибуты

С точки зрения Sphinx`а, данные, которые находятся в индексе представляют собой набор документов, каждый из которых имеет набор полей и атрибутов.

Поля

Поля документов содержат текстовую информацию, по которой Sphinx может быстро находить те документы, которые соответствуют определённым ключевым словам. В языке SphinxQL для поиска по полям существует специальный оператор match. Этот оператор получает в качестве параметра строку с поисковым запросом и определяет, соответствует ли тот или иной документ этому запросу или нет.

Например, при помощи следующего запроса в индексе product можно найти документы, любое из полей которых соответствует слову «red»:

select id, name, price from product
where match('red') limit 5;

Помимо ключевых слов поисковой запрос может содержать различные операторы. Так, например, можно найти документы, любое из полей которых соответствует либо слову «red», либо слову «blue»:

select id, name, price from product
where match('red | blue') limit 5;

Вертикальная черта в данном случае является оператором «или». Если бы её не было, то искались бы документы, любое из полей которых соответствует и слову «red», и слову «blue» одновременно.

А так, например, можно найти те документы, у которых слову «black» соответствует только поле name:

select id, name, price from product
where match('@name black') limit 5;

Стоит отметить, что в последнем примере name, указанный в операторе match, и name, указанный после ключевого слова select и возвращаемый в одной из колонок, это не одно и тоже. В первом случае мы имеем дело с полем name, по которому Shpinx выполняет полнотекстовый поиск. Во втором случае name - это одноимённый атрибут.

Вообще говоря, при создании индекса Sphinx даже не сохраняет оригинальный текст, который индексирует, поэтому по полям можно производить полнотекстовый поиск, но нельзя возвращать их в качестве результата. Для этого нужно использовать атрибуты.

Атрибуты

Атрибуты документов содержат дополнительные значения которые можно использовать для фильтрации, группировки и сортировки результатов (но не для полнотекстового поиска в операторе match).

Например, при помощи следующего запроса можно найти документы соответствующие слову «silver», имеющие цену меньше 1000 и отсортированные по названию:

select id, name, price from product
where match('silver') and price < 1000 order by name asc limit 5;

Каждый атрибут в Sphinx имеет свой тип:

  • uint - хранит 32-х битное целое число без знака;
  • bool - хранит значение 0 или 1;
  • bigint - хранит 64-х битное целое число со знаком;
  • timestamp - хранит дату и время в UNIX-формате (т.е. количество секунд, прошедших с 1 января 1970 года), используя 32-х битное целое число без знака;
  • float - хранит 32-х битное число с плавающей точкой;
  • string -хранит строку;
  • str2ordinal - при индексации ожидает на входе строку и хранит порядковый номер этой строки в индексе, может использоваться для сортировки по строке без хранения значений самой строки;
  • str2wordcount - при индексации ожидает на входе строку и хранит количество слов в этой строке, может использоваться в формуле ранжирования результатов поиска;
  • multi - хранит список значений типа uint, bigint или timestamp, играет особую роль в группировках;
  • json - хранит объекты в формате json и позволяет делать фильтрацию, группировку и сортировку результатов используя отдельные свойства этих объектов (появился в версии 2.1.1 и в настоящий момент поддерживает только один уровень вложенности объектов).

Заключение

В этой статье я кратко рассказал про основные возможности Sphinx.

В следующей статье я перейду от теории к практике и подробно расскажу про создание индексов, использующих в качестве источника данных базу данных MS SQL Server.

3 комментария

  1. "Sphinx использует протокол базы данных MySql, поэтому на каком бы языке мы не программировали, использовав нужный коннектор для этой базы данных, мы легко сможем подключиться к нему, выполнить запросы и получить результаты их выполнения."

    Добрый день. Вы пробовали на практике соединятся со Sphinx при помощи этих коннекторов? Особенно меня интересует соединение при помощи Connector/Net. При использовании последней версии коннектора я получаю исключение с сообщением о том, что версии сервера ниже 5 не поддерживаются, а при использовании коннектора версии 5.2.7 MySqlException с сообщением "An incorrect response was received from the server". Не могли бы Вы рассказать, как правильно соединится со сфинксом из C# с использованием стандартного коннектора или порекомендовать какой либо готовый проверенный клиент?

    ОтветитьУдалить
    Ответы
    1. Да, постоянно на работе используем именно коннектор для .net.
      Если в двух словах. Сфинкс действительно не дружит с последней версией коннектора. По этому поводу даже есть баг в их багтрекере. Чтобы использовать предыдущую версию, нужно в конфиге сфинкса в блоке searchd указать опцию, которая задаёт версию mysql, и там указать версию 5.
      Постараюсь за эти выходные расписать всё подробно =)

      Удалить
    2. Вот более подробный ответ: http://chakrygin.ru/2013/05/sphinx-and-dot-net.html

      Удалить

© Игорь Чакрыгин. Все права защищены при помощи чёрной магии. Технологии Blogger.