Главная > Tips and tricks > Полнотекстовый поиск в MongoDB используя Sphinx

Полнотекстовый поиск в MongoDB используя Sphinx

sphinx Многие из тех, кто успел попробовать MongoDB в действии, столкнулись с трудностями с полнотекстовым поиском. Встроенный механизм полнотекстового поиска в MongoDB (его так можно назвать с большой натяжкой) не пригоден для реальных потребностей.

Основная проблема заключается в том, что sphinx не позволяет использовать буквенно-цифровые значения в качестве ID документов. Есть несколько вариантов решения этой проблемы.

Строим индекс с помощью xmlpipe

Поскольку в Sphinx пока нет реализации источника данных для mongo, то придется использовать XMLpipe для индексации:

source src_test {
    type = xmlpipe
    xmlpipe_command = php /home/golotyuk/www/mongosphinx/index.php
}

index test {
        morphology              = stem_enru
        charset_type            = utf-8
        source                  = src_test
        path                    = /var/lib/sphinxsearch/data/test
}

Реализация XML генератора может быть приблизительно такая:

<?='<?xml version="1.0" encoding="utf-8"?><sphinx:docset>'?>

<sphinx:schema>
<sphinx:field name="content"/>
</sphinx:schema>

<?

$m = new Mongo();
$c = $m->test->documents;
$list = $c->find();

?>

<? foreach ( $list as $document ) { ?>
<sphinx:document id="<?=$document['numeric_id']?>">
<content><![CDATA[[<?=$document['text']?>]]></content>
</sphinx:document>
<? } ?>

</sphinx:docset>

Все предельно просто кроме одной проблемы - ID mongo документа представлен в буквенно-цифровом виде, чего не понимает сфинкс. Есть несколько подходов:

Решение проблемы с ID документа

Пользовательский ID

Первый вариант - хранить в каждом mongo-документе пользовательский (сгенерированный руками) цифровой ID отдельным свойством:

{
	"_id" : ObjectId("4bf2c7f38ead0e0d05070000"),
	"sid" : 7,
	"text" : "Много текста"
}

В этом случае свойство sid будет использоваться для индексации в качестве ID документа (в примере выше атрибут называется “numeric_id”).

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

В качестве альтернативного решения можно использовать таблицы соответствий ID документа Mongo и ID документа Sphinx (например в MySQL). В этом случае не нужно будет руками реализовывать механизм автоинкремента, но придется использовать дополнительную СУБД.

Выборка ID, как атрибута

ID mongo-документа можно выбирать как атрибут при индексации. Это наиболее верное решение, но учитывая, что атрибут строчный, понадобится обновиться до версии 0.9.10 (на этот момент эта версия еще не в релизе).

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

<sphinx:schema>
<sphinx:field name="content"/>
<sphinx:attr name="_id" type="string"/>
</sphinx:schema>

Как видно, id mongo-документа описан как строчный атрибут. Для генерации id документа sphinx можно использовать простой инкремент, например:

<? $i = 0; foreach ( $list as $document ) { ?>
<sphinx:document id="<?=$i + 1?>">
<content><![CDATA[[<?=$document['text']?>]]></content>
<_id><?=$document['_id']?></_id>
</sphinx:document>
<? } ?>

В результате sphinx будет возвращать атрибут “_id”, в котором будет находится идентификатор документа Mongo.

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com

Статьи по теме

Author: Den Golotyuk Categories: Tips and tricks Tags: ,
  1. 28 Май 2010 в 09:00 | #1

    В Sphinx 0.9.9 есть ordinal string.
    Текстовые идентификаторы легко приобразуются в ordinal и обратно.

  2. 28 Май 2010 в 11:14 | #2

    @Yaroslav Vorozhko
    К сожалению, не получится, т.к. атрибуты типа ordinal string используются только для сортировок. На стадии индексации sphinx преобразует их в числовое представление и не возвращает их при запросах к поисковому серверу.

  1. Пока что нет уведомлений.