Как искать фрагменты текста в базе данных

Связанные списки предпочтительны по массивам когда:

  1. Вам нужны постоянно-разовые вставки/удаления из списка (такие как в режиме реального времени вычисление, где предсказуемость времени абсолютно очень важна)

  2. , Вы не знаете, сколькими объекты будут в списке. С массивами Вы, возможно, должны повторно объявить и скопировать память, если массив становится слишком большим

  3. , Вам не нужен произвольный доступ ни к каким элементам

  4. , Вы хотите быть в состоянии вставить объекты посреди списка (такие как приоритетная очередь)

, Массивы предпочтительны когда:

  1. Вам нужен индексируемый / произвольный доступ к элементам

  2. , Вы знаете число элементов в массиве загодя так, чтобы можно было выделить корректный объем памяти для массива

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

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

Списки массива (как те в.Net) приносят Вам пользу массивов, но динамично выделяют ресурсы для Вас так, чтобы Вы не должны были волноваться слишком много о размере списка, и можно удалить объекты в любом индексе без любого усилия или перестановки элементов вокруг. Мудрый производительностью, arraylists медленнее, чем необработанные массивы.

6
задан Daniel Schneller 9 December 2009 в 20:15
поделиться

10 ответов

У меня лично не было этого конкретного требования, но мой опыт подсказывает, что Lucene может справиться с этой задачей, хотя, возможно, и не автономно. Я бы определенно использовал его через Solr, как описано в первом ответе Майкла Делла Битта. Ссылка, которую он дал, была точной - прочтите ее, чтобы узнать больше.

Вкратце, Solr позволяет вам определять пользовательские типы полей. Они состоят из анализатора времени индекса и анализатора времени запроса. Анализаторы выясняют, что делать с текстом, и каждый состоит из Tokenizer и от нуля до многих TokenFilters. Tokenizer разбивает ваш текст на части, а затем каждый TokenFilter может добавлять, вычитать или изменять токены.

Таким образом, поле может индексировать что-то совершенно отличное от исходного текста, включая, если необходимо, несколько токенов. Итак, вам нужна копия исходного текста с несколькими токенами, который вы запрашиваете, отправляя Lucene что-то вроде "my_ngram_field: sledge". Никаких подстановочных знаков: -)

Затем вы следуете модели, аналогичной поиску по префиксу, предложенному в файле solrconfig.xml:

<fieldType name="prefix_token" class="solr.TextField" positionIncrementGap="1">
    <analyzer type="index">
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="20"/>
    </analyzer>
    <analyzer type="query">
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <filter class="solr.LowerCaseFilterFactory" />
    </analyzer>
</fieldType>

EdgeNGramFilterFactory - это то, как они реализуют сопоставление префиксов для автозаполнения поля поиска. Он принимает токены, поступающие с предыдущих этапов (отдельные слова, разделенные пробелами, преобразованные в нижний регистр), и распределяет их по каждой подстроке на переднем крае. sledgehammer = s, sl, sle, сани, сани, сани, сани и т. д.

Вам нужно следовать этому шаблону, но заменить EdgeNGramFilterFactory своим собственным, который выполняет все NGrams в поле. Стандартный org.apache.solr.analysis.NGramFilterFactory - хорошее начало, но он выполняет транспонирование букв для проверки орфографии. Вы можете скопировать это и удалить это - это sa довольно простой класс для реализации.

Если у вас есть собственный FieldType (назовите его ngram_text) с использованием вашего собственного MyNGramFilterFactory, просто создайте свое исходное поле и поле ngram следующим образом:

    <field name="title" type="text" indexed="true" stored="true"/>
    <field name="title_ngrams" type="ngram_text" indexed="true" stored="false"/>

Затем скажите ему скопировать исходное поле в причудливый:

<copyField source="title" dest="title_ngrams"/>

Хорошо, теперь при поиске "title_ngrams: sledge" вы должны получить список документов, которые это содержат. Затем в вашем списке полей для запроса вы просто указываете ему получить поле с названием title, а не поле title_ngrams.

Этого должно быть достаточно, чтобы вы могли соединить все вместе и довольно легко настроить его на удивительные уровни производительности. . На старой работе у нас была база данных с более чем десятью миллионами продуктов с большими HTML-описаниями, и нам удалось заставить Lucene выполнять как стандартный запрос, так и проверку орфографии менее чем за 200 мс на сервере среднего размера, обрабатывающем несколько десятков одновременных запросов. Когда у вас много пользователей, кеширование срабатывает и заставляет кричать!

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

Удачи!

4
ответ дан 8 December 2019 в 03:53
поделиться

Я бы использовал Apache Solr. Стратегия индексирования полностью настраивается (см. http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters ), может постепенно считывать данные непосредственно из вашей базы данных для заполнения индекса (см. DataImportHandler в той же вики) и можно запрашивать практически с любого языка, который поддерживает HTTP, XML или что-то вроде JSON.

3
ответ дан 8 December 2019 в 03:53
поделиться

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

Если бы вы работали в магазине Microsoft, большая часть того, что вы ищете, встроено в SQL Server, и можно включить подстановочные знаки, что даст вам возможность делать частичные совпадения слов.

В Lucene и Lucene.Net вы можете использовать совпадения с подстановочными знаками , если хотите. Однако использование подстановочных знаков в качестве первого символа при поиске не поддерживается. Если вам нужна возможность использовать подстановочные знаки первого символа, вам, вероятно, потребуется реализовать какой-то индекс на основе дерева самостоятельно, поскольку он ' - во многих случаях дорогостоящая операция по фильтрации набора терминов до чего-то разумного для типа индекса, наиболее часто необходимого для приложений полнотекстового поиска, где выделение суффиксов обычно более ценно.

Очевидно, вы можете изменить экземпляр Query Parser в Lucene, чтобы переопределить это правило, установив для setAllowLeadingWildcard значение true.

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

Существуют и другие решения проблемы, связанные с вы описываете, где может встречаться одно слово, как два, или наоборот. Например, в Lucene поддерживаются нечеткие запросы. Орфографические и морфологические варианты можно обрабатывать с помощью либо предоставления фильтра, который предлагает предложения, основанные на каком-то байесовском механизме, либо с помощью уловок индексации, а именно, взятия корпуса частых вариантов и заполнения указателя этими терминами. Я даже видел знания из структурированных данных, вставленных в полнотекстовый механизм (например, добавление названия города и слова «отель» в записи из таблицы отелей, чтобы повысить вероятность того, что «Парижские отели» будут включать запись о пенсии -house Caisse des Dépôts.) Хотя это не совсем тривиальная проблема, с ней можно справиться, не разрушая преимуществ поиска по словам.

взять корпус частых вариантов и заполнить индекс этими терминами. Я даже видел знания из структурированных данных, вставленных в полнотекстовый движок (например, добавление названия города и слова «отель» в записи из таблицы отелей, чтобы повысить вероятность того, что «Парижские отели» будут включать запись о пенсии -house Caisse des Dépôts.) Хотя это не совсем тривиальная проблема, с ней можно справиться, не уничтожая преимуществ поиска по словам.

взять корпус частых вариантов и заполнить индекс этими терминами. Я даже видел знания из структурированных данных, вставленных в полнотекстовый движок (например, добавление названия города и слова «отель» в записи из таблицы отелей, чтобы повысить вероятность того, что «Парижские отели» будут включать запись о пенсии -house Caisse des Dépôts.) Хотя это не совсем тривиальная проблема, с ней можно справиться, не уничтожая преимуществ поиска по словам.

10
ответ дан 8 December 2019 в 03:53
поделиться

как насчет использования таких инструментов, как предложенные выше (lucene и т. Д.) Для полнотекстового индексирования и поиска LIKE для случаев, когда ничего не было найдено? (т.е. запускать LIKE только после того, как поиск с полнотекстовым индексом дал нулевые результаты)

2
ответ дан 8 December 2019 в 03:53
поделиться

Если ваша таблица - MyISAM, вы можете использовать возможности полнотекстового поиска MySQL: http://dev.mysql.com/doc/refman/5.0/en/fulltext-search. html

В противном случае "отраслевым стандартом" является http://www.sphinxsearch.com/

Некоторые идеи о том, что делать, если вы используете InnoDB: http: // www. mysqlperformanceblog.com/2009/09/10/what-to-do-with-mysql-full-text-search- while-migrating-to-innodb/

Также хорошая презентация, которая знакомит с Sphinx и объясняет архитектуру + использование http://www.scribd.com/doc/2670976/Sphinx-High-Performance-Full-Text-Search-for-MySQL-Presentation

Обновление
Прочитав ваше разъяснение по вопросу - Sphinx может подбирать подстроки. Вам нужно установить «enable-star» и создать инфиксный индекс с соответствующей min_infix_length (1 предоставит вам все возможные подстроки, но, очевидно, чем выше он установлен, тем меньше будет ваш индекс и тем быстрее будет ваш поиск). Подробнее см. http://sphinxsearch.com/docs/current.html .

3
ответ дан 8 December 2019 в 03:53
поделиться

То, что вы пытаетесь сделать, вряд ли когда-либо будет намного быстрее, чем LIKE '% searchterm%' без особого кода. Однако эквивалент LIKE 'searchterm%' должен быть тривиальным. Вы можете сделать то, о чем просите, построив индекс всех возможных частичных слов, которые не охвачены завершающим шаблоном, но это приведет к невероятно большому размеру индекса, и это было бы необычно медленно для обновлений. Длинные жетоны приводят к плохим вещам ™. Могу я спросить , зачем вам это нужно? Re: Spotlight ... Вы ведь понимаете, что Spotlight этого не делает, верно? Он основан на токенах, как и любой другой полнотекстовый индексатор. Обычно расширение запроса является подходящим методом получения неточных совпадений, если это ваша цель.

Изменить:

В какой-то момент у меня был проект точно такой же; артикулы для всевозможных вещей. В конце концов мы остановились на searchterm * в Xapian, но я считаю, что у Lucene также есть эквивалент. Вы не найдете хорошего решения, которое обрабатывает поиск с использованием подстановочных знаков по обе стороны от токена, но конечный подстановочный знак обычно более чем достаточно для того, что вы хотите, и я подозреваю, что вы ' Я обнаружу, что пользователи довольно быстро адаптируются к вашей системе, если у них есть какой-либо контроль над очисткой данных. Объедините это с расширением запроса (или даже ограниченным расширением токена), и вы должны быть довольно хорошо настроены. Расширение запроса преобразовало бы запрос «кувалда» в «кувалда * ИЛИ (кувалда * молот *)» или что-то подобное. Не каждый запрос будет работать, но люди уже достаточно хорошо обучены пробовать связанные запросы, когда что-то не работает, и пока хотя бы один или два очевидных запроса дают ожидаемые результаты, все должно быть в порядке. Лучше всего очистить данные и лучше их организовать. Вы будете удивлены, насколько легко это окажется, если вы все версируете и реализуете эгалитарную политику редактирования. Может быть, пусть люди добавляют ключевые слова к записи и обязательно их индексируют, но установите ограничения на то, сколько можно установить. Если слишком много, результаты поиска могут ухудшиться.

2
ответ дан 8 December 2019 в 03:53
поделиться

Я почти уверен, что Mysql предлагает полнотекстовый вариант, и, вероятно, также можно использовать Lucene.

См. Здесь соответствующие комментарии

Лучший эффективный способ сделать полнотекстовый поиск в MySQL

0
ответ дан 8 December 2019 в 03:53
поделиться

Поиск по черепице может помочь.

http://en.wikipedia.org/wiki/W-shingling

Например, если вы используете трехсимвольную черепицу, вы может разделить "Roisonic" на "roi", "son", "ic" и сохранить все три значения, связав их с исходной записью. При поиске «oison» вы сначала будете искать «ois», «iso», «son». Сначала вы нечетко сопоставляете все записи с помощью черепицы (поиск той, у которой есть "сын"), а затем вы можете уточнить поиск, используя точное сопоставление строк.

Обратите внимание, что трехсимвольная черепица требует, чтобы фрагмент в запросе был как минимум Длина 5-символьной черепицы из 4 символов требует запроса из 7 символов и т. Д.

2
ответ дан 8 December 2019 в 03:53
поделиться

Точный ответ на ваш вопрос: прямо здесь Будет ли он работать достаточно хорошо для размера ваших данных - это другой вопрос.

1
ответ дан 8 December 2019 в 03:53
поделиться

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

Вы только надеетесь, что есть какой-то шаблон для допущенных "ошибок". Вы можете применить набор правил типа "AI" к входящему тексту и создать каноническую форму текста, к которой затем примените полнотекстовый указатель к. Примером правила может быть разделение слова, оканчивающегося на молот, на два слова s / (\ w?) (молот) / \ 1 \ 2 / g или изменение "sledg", "sled" и "schledge" на "сани". Вам нужно будет применить тот же набор правил к тексту запроса. Так же, как продукт, описанный как "кувалда", может быть сопоставлен с поиском "санный молот".

0
ответ дан 8 December 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: