Как структурировать индекс для типа вперед для чрезвычайно большого набора данных с использованием Lucene или аналогичного?

У меня есть набор данных из 200 миллионов + записей, и я хочу построить выделенный сервер, чтобы использовать решение для решения типа. Lucene представляет интерес, учитывая ее популярность и тип лицензии, но я открыт для других предложений с открытым исходным кодом. Я ищу совет, сказки из окопов или даже лучшую прямую инструкцию о том, что мне понадобится в отношении объема аппаратного обеспечения и структуры программного обеспечения. Требования:

Должно быть:

  • Возможность делать начинается с соответствия подстроки (я набираю в 'st', и он должен соответствовать "Stephen" )
  • Возможность быстро возвращать результаты, я бы сказал, что 500ms - это верхняя граница.

Приятно иметь:

  • Возможность передавать информацию релевантности в процесс индексирования, так что, например, более популярные термины будут возвращены впереди других, а не только в алфавитном порядке, а также в стиле Google.
  • Подстрока подстроки в словах, например ('st' будет соответствовать "бестселлеру" )

Примечание:

  • Этот индекс будет использоваться исключительно для типа вперед и не должен обслуживать стандартные поисковые запросы.
  • Я не беспокоюсь о получении советов о том, как настроить внешний интерфейс или AJAX, если индекс можно запросить как услугу или напрямую через Java-код.

Повысьте количество голосов за любую полезную информацию, которая позволяет мне приблизиться к решению на уровне уровня предприятия

Ответ 1

Если каждая запись относительно невелика (менее нескольких слов), вы можете попробовать структуру данных Trie:

http://en.wikipedia.org/wiki/Trie

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

Вы можете легко реализовать Trie самостоятельно, или есть реализации, которые вы можете скачать. См

Где найти стандартную реализацию карты на основе Trie в Java?

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

Ответ 2

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

B-дерево с 8kb-страницами должно содержать не менее 250 строк/страниц, что приведет к 1M листовым страницам, что даст b-дерево высотой 3. Даже с диском для ноутбука емкостью 5400 об/мин задержка ввода-вывода меньше чем 15 мс, поэтому в худшем случае вы сможете получить результаты в ~ 50 мс в худшем случае (полностью нераспакованные данные и медленный диск).

(Я создал приложение типа head, которое использует класс PersistentDictionary на основе ESENT. С 200K-записями я получаю ответ 35 мс для первого поиска, где данные вообще не кэшируются. После выполнения кучки запросов ответ время падает до ~ 5 мс).

Для поддержки множества одновременных пользователей вы можете либо добавить больше кеша или более быстрых дисков. Возможно, полностью кэшируется все данные (в наши дни доступно 8 ГБ оперативной памяти), а данные типа будут, конечно, достаточно маленькими, чтобы поместиться на SSD, что обеспечило бы смехотворное количество IOPS. Я могу пойти на SSD, потому что это даст большую производительность, даже если кэш холодный (например, после перезапуска).

Решение, основанное на базе базы данных, должно быть чрезвычайно быстрым.

Ответ 3

Вот как мы это делаем в SOLR:

Ключ к поиску, если у вас есть правильный тип данных с соответствующими фабриками фильтров.

Настройте тип данных в вашей схеме под названием textPrefix

Пример:

<!--
 This type is used for type ahead style searching and starts with searching. 
-->
−
<fieldType name="textPrefix" class="solr.TextField" positionIncrementGap="1" sortMissingLast="true">
−
<analyzer type="index">
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="ISOLatin1AccentFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<!-- Remove non alpha-numeric characters -->
<filter class="solr.PatternReplaceFilterFactory" pattern="[^a-zA-Z0-9 ]" replacement="" replace="all"/>
<filter class="solr.TrimFilterFactory"/>
<!-- Remove leading "the "-->
<filter class="solr.PatternReplaceFilterFactory" pattern="^the\s" replacement="" replace="all"/>
<filter class="solr.TrimFilterFactory"/>
<filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="6"/>
</analyzer>
−
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="ISOLatin1AccentFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<!-- Remove non alpha-numeric characters -->
<filter class="solr.PatternReplaceFilterFactory" pattern="[^a-zA-Z0-9 ]" replacement="" replace="all"/>
<filter class="solr.TrimFilterFactory"/>
<!-- Remove leading "the "-->
<filter class="solr.PatternReplaceFilterFactory" pattern="^the\s" replacement="" replace="all"/>
<filter class="solr.TrimFilterFactory"/>
</analyzer>
</fieldType>

Затем в вашем документе схемы создайте новое поле данных как таковое:

<field name="CustomerNamePrefix" type="textPrefix" indexed="true" stored="false"/>

Затем сохраните копию имени клиента в это поле CustomerNamePrefix.

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

Пример:

http://solrserver:8080/solr/select/?q=CustomerNamePrefix:jame&q.alt=*:*&start=0&rows=10&mm=1