Sphinx - Источники данных в формате xml
В предыдущих статьях я рассказал о том, что в качестве источника данных для Sphinx можно использовать базы данных, в частности MS SQL Server. Во многих случаях этого наиболее удобный способ построения индекса, поскольку Sphinx может получить все данные одним запросом. Даже на очень больших объёмах данных этот запрос можно разбить на несколько ranged-запросов и получать данные из базы небольшими порциями.
Но данные в базе могут иметь сложную структуру со множеством связей, и получить их одним запросом может быть сложно. К тому же может потребоваться получать данные из источника, который Sphinx просто не поддерживает. Наиболее универсальным источником данных для Sphinx являются данные в формате xml. Именно об этом я и хочу рассказать в этой статье.
Пример 1: Индексация xml-файла
Для начала рассмотрим самый простой пример, когда индексируемые данные находятся в xml-файле, а схема индекса описывается в файле конфигурации.
Шаг 1. Создадим файл product.xml (я поместил его в папку c:\sphinx\data\source\) с документами, которые собираемся индексировать.
<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset xmlns:sphinx="http://sphinxsearch.com/">
<sphinx:document id="849">
<name>Men's Sports Shorts</name>
<price>24.7459</price>
</sphinx:document>
<sphinx:document id="852">
<name>Women's Tights</name>
<price>30.9334</price>
</sphinx:document>
<sphinx:document id="855">
<name>Men's Bib-Shorts</name>
<price>37.1209</price>
</sphinx:document>
</sphinx:docset>
Как вы видите, корневым элементом xml-файла является элемент sphinx:docset
, в
котором при помощи элементов sphinx:document
описаны индексируемые документы.
Каждый документ имеет уникальный атрибут id
и несколько вложенных элементов,
названия которых соответствуют названиям полей и атрибутов в схеме индекса.
Шаг 2. Опишем источник данных и индекс в файле конфигурации.
searchd
{
listen = 9306:mysql41
pid_file = c:/sphinx/data/searchd.pid
log = c:/sphinx/data/log/log.txt
query_log = c:/sphinx/data/log/query_log.txt
binlog_path = c:/sphinx/data/binlog/
}
source product
{
type = xmlpipe2
xmlpipe_command = type c:\sphinx\data\source\product.xml
xmlpipe_field_string = name
xmlpipe_attr_float = price
}
index product
{
source = product
path = c:/sphinx/data/index/product
charset_type = utf-8
}
Блоки searchd
и index product
вряд ли нуждаются в пояснении. Они
полностью аналогичны тому, что мы делали при индексации базы данных. Основной интерес
представляет блок source product
.
Опция type
указывает тип источника данных. Sphinx поддерживает два типа источников
данных в формате xml: xmlpipe и
xmlpipe2. Однако тип xmlpipe
считается уже устаревшим поэтому мы использует тип xmlpipe2.
Опция xmlpipe_command
указывает команду для получения данных. Эта команда должна
выводить xml-документ в стандартный выходной поток. Мы используем команду type
,
которая выводит содержимое файла, название которого передано ей в качестве аргумента. Убедиться
в этом можно, если ввести эту команду в командную строку.
type c:\sphinx\data\source\product.xml
Опций xmlpipe_field_string
и xmlpipe_attr_float
определяют поле
name
и атрибуты name
и price
, которые будут содержаться
в индексе. Полный список всех опций для определения полей и атрибутов можно найти в
документации.
Шаг 3. Выполним индексацию.
c:\sphinx\bin\indexer product --config c:\sphinx\data\config.txt --rotate
После того, как индексация успешно завершится, можно проверить, что индекс действительно был создан, подключившись к Sphinx и выполнив простой запрос.
select id, name, price from product;
Пример 2: Описание схемы в индексируемом xml-файле
Отличительной особенностью источников данных в формате xml является то, что схема индекса (набор полей и атрибутов) может быть описана не только в файле конфигурации, но и в самих данных. Это весьма полезная возможность, поскольку она позволяет изменять схему индекса без изменения файла конфигурации и последующего перезапуска Sphinx.
Шаг 1. Добавим схему индекса в файл product.xml
<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset xmlns:sphinx="http://sphinxsearch.com/">
<sphinx:schema>
<sphinx:field name="name" attr="string" />
<sphinx:attr name="price" type="float"/>
</sphinx:schema>
<sphinx:document id="849">
<name>Men's Sports Shorts</name>
<price>24.7459</price>
</sphinx:document>
<sphinx:document id="852">
<name>Women's Tights</name>
<price>30.9334</price>
</sphinx:document>
<sphinx:document id="855">
<name>Men's Bib-Shorts</name>
<price>37.1209</price>
</sphinx:document>
</sphinx:docset>
Схема индекса описывается при помощи элемента sphinx:schema
, который может
содержать элементы sphinx:field
и sphinx:attr
.
Элемент sphinx:field
определяет поле с названием, указанным в атрибуте
name
. Также в этом элементе может содержаться необязательный атрибут
attr
, который указывает, что вместе с полем нужно создать одноимённый атрибут.
Значение атрибута attr
при этом указывает тип создаваемого атрибута (обычно это
строковой тип).
Элемент sphinx:attr
определяет атрибут с названием, указанным в атрибуте
name
и типом, указанным в атрибуте type
.
Более подробно про элементы sphinx:field
и sphinx:attr
можно прочитать
в документации.
Шаг 2. Изменим файл конфигурации, убрав определение полей и атрибутов из блока
source
.
source product
{
type = xmlpipe2
xmlpipe_command = type c:\sphinx\data\source\product.xml
}
Тут всё очень просто. Поскольку схема теперь описана в xml-файле, то никакой необходимости дублировать её в файле конфигурации.
Шаг 3. Снова выполним индексацию командой:
c:\sphinx\bin\indexer product --config c:\sphinx\data\config.txt --rotate
Как мы видим, индексация снова прошла успешно.
Пример 3: Индексация потоковых данных
В предыдущих примерах мы индексировали готовые xml-файлы, используя для этого команду
type
. Однако создавать этот файл не обязательно. Вместо команды type
можно указать любую программу, которая будет выводить данные в стандартный выходной поток.
Шаг 1. Воспользуемся Visual Studio и создадим консольное приложение SphinxSourceApp на
языке C#, которое будет выводить данные из предыдущего примера при помощи класса
XmlTextWriter
.
public static class Program
{
private const string sphinxns = "http://sphinxsearch.com";
public static void Main(string[] args)
{
var products = new[]
{
new { ID = 849, Name = "Men's Sports Shorts", Price = 24.7459M },
new { ID = 852, Name = "Women's Tights", Price = 30.9334M },
new { ID = 855, Name = "Men's Bib-Shorts", Price = 37.1209M },
};
Console.OutputEncoding = Encoding.UTF8;
using (var writer = new XmlTextWriter(Console.Out))
{
writer.WriteStartDocument();
writer.WriteStartElement("sphinx", "docset", sphinxns);
// <sphinx:schema>
writer.WriteStartElement("sphinx", "schema", sphinxns);
// <sphinx:field />
writer.WriteStartElement("sphinx", "field", sphinxns);
writer.WriteAttributeString("name", "name");
writer.WriteAttributeString("attr", "string");
writer.WriteEndElement();
// <sphinx:attr />
writer.WriteStartElement("sphinx", "attr", sphinxns);
writer.WriteAttributeString("name", "price");
writer.WriteAttributeString("type", "float");
writer.WriteEndElement();
writer.WriteEndElement();
// </sphinx:schema>
foreach (var product in products)
{
// <sphinx:document>
writer.WriteStartElement("sphinx", "document", sphinxns);
writer.WriteAttributeString("id", product.ID.ToString());
writer.WriteElementString("name", product.Name);
writer.WriteElementString("price", product.Price.ToString());
writer.WriteEndElement();
// </sphinx:document>
}
writer.WriteEndElement();
}
}
}
Скомпилируем это приложение и скопируем его в папку c:\sphinx\data\source\.
Шаг 2. Отредактируем файл конфигурации, изменив опцию xmlpipe_command
.
source product
{
type = xmlpipe2
xmlpipe_command = c:\sphinx\data\source\SphinxSourceApp.exe
}
Шаг 3. Ещё раз выполним индексацию командой:
c:\sphinx\bin\indexer product --config c:\sphinx\data\config.txt --rotate
Индексация снова прошла успешно.
Заключение
Источники данных в формате xml во многом являются более гибкими, чем источники, связанные с базами данных. Они позволяют индексировать как относительно небольшие xml-файлы, так и большие объёмы данных, генерируемые «на лету». При этом они не ограничивают вас жёстко заданной схемой, позволяя вместо этого передавать её вместе с данными.
Скачать материалы к этой статье (скрипты, файлы конфигурации, xml-файлы и приложение SphinxSourceApp)