четверг, 3 июня 2010 г.

Полнотекстовый поиск в 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



Related posts:

  1. Дельта индекс в Sphinx
  2. Solr — полнотекстовый поиск от Apache (на основе Lucene)
  3. Sphinxsearch — объединение индексов (index merging)

Комментариев нет:

Отправить комментарий