Связанные списки предпочтительны по массивам когда:
Вам нужны постоянно-разовые вставки/удаления из списка (такие как в режиме реального времени вычисление, где предсказуемость времени абсолютно очень важна)
, Вы не знаете, сколькими объекты будут в списке. С массивами Вы, возможно, должны повторно объявить и скопировать память, если массив становится слишком большим
, Вам не нужен произвольный доступ ни к каким элементам
, Вы хотите быть в состоянии вставить объекты посреди списка (такие как приоритетная очередь)
, Массивы предпочтительны когда:
Вам нужен индексируемый / произвольный доступ к элементам
, Вы знаете число элементов в массиве загодя так, чтобы можно было выделить корректный объем памяти для массива
, Вам нужна скорость при итерации через все элементы в последовательности. Можно использовать математику указателя на массиве для доступа к каждому элементу, тогда как Вам нужен к поиску узел на основе указателя для каждого элемента в связанном списке, который может привести к отсутствиям страницы, которые могут привести к хитам производительности.
память является беспокойством. Заполненные массивы поднимают меньше памяти, чем связанные списки. Каждый элемент в массиве является просто данными. Каждый узел связанного списка требует данных, а также одного (или больше) указатели на другие элементы в связанном списке.
Списки массива (как те в.Net) приносят Вам пользу массивов, но динамично выделяют ресурсы для Вас так, чтобы Вы не должны были волноваться слишком много о размере списка, и можно удалить объекты в любом индексе без любого усилия или перестановки элементов вокруг. Мудрый производительностью, arraylists медленнее, чем необработанные массивы.
У меня лично не было этого конкретного требования, но мой опыт подсказывает, что 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 мс на сервере среднего размера, обрабатывающем несколько десятков одновременных запросов. Когда у вас много пользователей, кеширование срабатывает и заставляет кричать!
Да, и инкрементное (хотя и не в реальном времени) индексирование - это несложно. Он может делать это даже при высоких нагрузках, поскольку он создает и оптимизирует новый индекс в фоновом режиме и автоматически подогревает его перед заменой. Очень хорошо.
Удачи!
Я бы использовал Apache Solr. Стратегия индексирования полностью настраивается (см. http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters ), может постепенно считывать данные непосредственно из вашей базы данных для заполнения индекса (см. DataImportHandler в той же вики) и можно запрашивать практически с любого языка, который поддерживает HTTP, XML или что-то вроде JSON.
Возможно, это не то, что вы хотите услышать, потому что я предполагаю, что вы пытаетесь решить эту проблему с помощью кода 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.) Хотя это не совсем тривиальная проблема, с ней можно справиться, не уничтожая преимуществ поиска по словам.как насчет использования таких инструментов, как предложенные выше (lucene и т. Д.) Для полнотекстового индексирования и поиска LIKE для случаев, когда ничего не было найдено? (т.е. запускать LIKE только после того, как поиск с полнотекстовым индексом дал нулевые результаты)
Если ваша таблица - 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 .
То, что вы пытаетесь сделать, вряд ли когда-либо будет намного быстрее, чем LIKE '% searchterm%'
без особого кода. Однако эквивалент LIKE 'searchterm%'
должен быть тривиальным. Вы можете сделать то, о чем просите, построив индекс всех возможных частичных слов, которые не охвачены завершающим шаблоном, но это приведет к невероятно большому размеру индекса, и это было бы необычно медленно для обновлений. Длинные жетоны приводят к плохим вещам ™. Могу я спросить , зачем вам это нужно? Re: Spotlight ... Вы ведь понимаете, что Spotlight этого не делает, верно? Он основан на токенах, как и любой другой полнотекстовый индексатор. Обычно расширение запроса является подходящим методом получения неточных совпадений, если это ваша цель.
Изменить:
В какой-то момент у меня был проект точно такой же; артикулы для всевозможных вещей. В конце концов мы остановились на searchterm *
в Xapian, но я считаю, что у Lucene также есть эквивалент. Вы не найдете хорошего решения, которое обрабатывает поиск с использованием подстановочных знаков по обе стороны от токена, но конечный подстановочный знак обычно более чем достаточно для того, что вы хотите, и я подозреваю, что вы ' Я обнаружу, что пользователи довольно быстро адаптируются к вашей системе, если у них есть какой-либо контроль над очисткой данных. Объедините это с расширением запроса (или даже ограниченным расширением токена), и вы должны быть довольно хорошо настроены. Расширение запроса преобразовало бы запрос «кувалда» в «кувалда * ИЛИ (кувалда * молот *)» или что-то подобное. Не каждый запрос будет работать, но люди уже достаточно хорошо обучены пробовать связанные запросы, когда что-то не работает, и пока хотя бы один или два очевидных запроса дают ожидаемые результаты, все должно быть в порядке. Лучше всего очистить данные и лучше их организовать. Вы будете удивлены, насколько легко это окажется, если вы все версируете и реализуете эгалитарную политику редактирования. Может быть, пусть люди добавляют ключевые слова к записи и обязательно их индексируют, но установите ограничения на то, сколько можно установить. Если слишком много, результаты поиска могут ухудшиться.
Я почти уверен, что Mysql предлагает полнотекстовый вариант, и, вероятно, также можно использовать Lucene.
См. Здесь соответствующие комментарии
Лучший эффективный способ сделать полнотекстовый поиск в MySQL
Поиск по черепице может помочь.
http://en.wikipedia.org/wiki/W-shingling
Например, если вы используете трехсимвольную черепицу, вы может разделить "Roisonic" на "roi", "son", "ic" и сохранить все три значения, связав их с исходной записью. При поиске «oison» вы сначала будете искать «ois», «iso», «son». Сначала вы нечетко сопоставляете все записи с помощью черепицы (поиск той, у которой есть "сын"), а затем вы можете уточнить поиск, используя точное сопоставление строк.
Обратите внимание, что трехсимвольная черепица требует, чтобы фрагмент в запросе был как минимум Длина 5-символьной черепицы из 4 символов требует запроса из 7 символов и т. Д.
Точный ответ на ваш вопрос: прямо здесь Будет ли он работать достаточно хорошо для размера ваших данных - это другой вопрос.
«Настоящий» полнотекстовый индекс, использующий части слова, будет во много раз больше, чем исходный текст, и хотя поиск может быть быстрее, любое обновление или обработка вставки будет ужасно медленным.
Вы только надеетесь, что есть какой-то шаблон для допущенных "ошибок". Вы можете применить набор правил типа "AI" к входящему тексту и создать каноническую форму текста, к которой затем примените полнотекстовый указатель к. Примером правила может быть разделение слова, оканчивающегося на молот, на два слова s / (\ w?) (молот) / \ 1 \ 2 / g или изменение "sledg", "sled" и "schledge" на "сани". Вам нужно будет применить тот же набор правил к тексту запроса. Так же, как продукт, описанный как "кувалда", может быть сопоставлен с поиском "санный молот".