Внедрение схемы сравнения ключевых слов (обратный поиск)

У меня постоянно растущая база ключевых слов. Мне нужно проанализировать входящие текстовые вводы (статьи, каналы и т. Д.) И найти, какие ключевые слова из базы данных присутствуют в тексте. База ключевых слов намного больше текста.

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

Самой наивной реализацией было бы создание простого запроса SELECT к таблице ключевых слов с гигантским предложением IN, перечисляющим все найденные ключевые слова.

SELECT user_id,keyword FROM keywords WHERE keyword IN ('keyword1','keyword2',...,'keywordN');

Другой подход - создать хеш-таблицу в памяти (используя что-то вроде memcache) и таким же образом проверить ее.

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


person Eran Galperin    schedule 02.01.2009    source источник
comment
Здесь много вопросов. Сколько уникальных ключевых слов существует (у каждого пользователя есть похожие ключевые слова)? Сколько у тебя памяти? Вам нужно, чтобы данные были актуальными или их можно обрабатывать через определенные промежутки времени?   -  person David Raznick    schedule 03.01.2009
comment
Как сказано в первом абзаце, размер базы данных ключевых слов намного больше, чем слов в тексте. Статьи обрабатываются по мере их получения, а оповещения отправляются пользователям, зарегистрированным по определенным ключевым словам. Память сейчас не проблема.   -  person Eran Galperin    schedule 03.01.2009
comment
Я не понимаю, как вы собираетесь работать намного быстрее, чем иметь копию вашей таблицы ключевых слов в памяти (куча) и проиндексировать и делать то, что вы сделали выше, или присоединиться к созданной в памяти таблице ключевых слов для каждой статьи. (Разделение пользователей поможет слишком). Однако репликация должна быть в вашем приложении.   -  person David Raznick    schedule 03.01.2009
comment
это тоже может быть полезно - я наблюдаю аналогичную проблему: stackoverflow.com/questions/47762/how-to-ranking-search-results   -  person warren    schedule 04.03.2009


Ответы (6)


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

Вы можете найти реализацию в fgrep. Более того, Престон Бриггс написал довольно красивую реализацию на C, которая выполняет именно тот поиск по ключевым словам, о котором вы говорите. (Он ищет в программах вхождения «интересных» идентификаторов.) Реализация Preston распространяется как часть Инструмент грамотного программирования Noweb. Вы можете найти способ вызвать этот код из PHP или переписать его на PHP - само распознавание составляет около 220 строк C, а основная программа - еще 135 строк.

Все предлагаемые решения, включая Aho-Corasick, имеют следующие общие свойства:

  • Этап предварительной обработки, который занимает время и пространство, пропорциональное количеству ключевых слов в базе данных.

  • Шаг поиска, который занимает время и пространство, пропорциональное длине текста плюс количеству найденных ключевых слов.

Aho-Corasick предлагает значительно лучшие константы пропорциональности на этапе поиска, но если ваши тексты небольшие, это не имеет значения. Фактически, если ваши тексты небольшие, а ваша база данных большая, вы, вероятно, захотите минимизировать объем памяти, используемый на этапе предварительной обработки. Структура данных DAWG Эндрю Аппеля из самой быстрой в мире программы скрэббла, вероятно, подойдет Хитрость.

person Norman Ramsey    schedule 02.01.2009
comment
Я не ищу слова в тексте - я преобразовываю текст в слова, а затем сравниваю их с базой данных слов. - person Eran Galperin; 03.01.2009
comment
Код Престона делает именно то, что вы хотите. Он объединяет токенизацию и поиск за один шаг. Вы предоставляете список ключевых слов, строите автомат, а затем нажимаете на строку автоматом. - person Norman Ramsey; 03.01.2009
comment
Вы все еще не понимаете. Я не хочу искать каждое ключевое слово в базе данных по тексту - но наоборот. Разбейте текст на слова и найдите, какие из них есть в базе данных. База данных намного больше текста. - person Eran Galperin; 03.01.2009
comment
Хорошо, с добавлением этой важной информации любой простой шаг предварительной обработки в базе данных подойдет - добавит все ключевые слова в хеш-таблицу. Затем разметьте свой небольшой текст, найдите каждое слово в хеш-таблице, и все готово. Aho-Corasick тоже подойдет, но вам не нужны сложности. - person Norman Ramsey; 03.01.2009
comment
Да, меня не особо интересует этап предварительной обработки, я уже выбрал метод атаки на это. Меня беспокоит поиск большого числа ключевых слов по очень большой таблице. - person Eran Galperin; 03.01.2009
comment
Похоже, у вас уже есть подход, который работает, поэтому вам не нужна новая идея. - person Norman Ramsey; 03.01.2009
comment
Мой подход работает, но я знаю только его. Просто проверяю, знают ли люди что-нибудь получше - поскольку производительность здесь является проблемой. - person Eran Galperin; 03.01.2009
comment
Люди могли бы помочь вам лучше, если бы вы сказали нам где производительность является проблемой: в подготовке списка ключевых слов или в изучении текста? - person Norman Ramsey; 03.01.2009
comment
Как я уже сказал, я еще ничего не пробовал на практике, поэтому не могу сказать, где будет проблема с производительностью. Я просто ищу альтернативные подходы ... - person Eran Galperin; 04.01.2009

В целом,

  1. разбить текст на слова

    б. преобразовать слова обратно в каноническую корневую форму

    c. отбросить общие союзные слова

    d. удалить дубликаты

  2. вставьте слова во временную таблицу, затем выполните внутреннее соединение с таблицей ключевых слов или (как вы предложили) создайте ключевые слова в сложных критериях запроса

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

person Hugh Bothwell    schedule 02.01.2009
comment
Есть ли опыт работы с таблицей в памяти по сравнению с массивом кэша памяти? Я бы подумал, что доступ к массиву будет быстрее? - person Eran Galperin; 03.01.2009
comment
Проще выполнить JOIN с таблицей с использованием механизма хранения MEMORY, чем с memcached. - person Bill Karwin; 03.01.2009

Я не на 100% понимаю, о чем вы спрашиваете, но, возможно, вы ищете инвертированный индекс?

Обновлять:

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

Разделите новый документ на токены и вставьте токены в паре с идентификатором документа в инвертированную индексную таблицу. Таблица перевернутого индекса (скорее денормализованная):

inverted_index
-----
document_id keyword

Если вы ищете 3 ключевых слова вручную:

select document_id, count(*) from inverted_index
  where keyword in (keyword1, keyword2, keyword3)
  group by document_id 
  having count(*) = 3

Если у вас есть таблица ключевых слов, которые вам нужны, просто используйте внутреннее соединение, а не операцию in ():

keyword_table
----
keyword othercols

select keyword_table.keyword, keyword_table.othercols from inverted_index 
   inner join keyword_table on keyword_table.keyword=inverted_index.keyword
   where inverted_index.document_id=id_of_some_new_document

что-нибудь из этого ближе к тому, что вы хотите?

person ʞɔıu    schedule 02.01.2009
comment
Он пытается сделать наоборот. В этом случае для входящего огромного фрагмента теста найдите, о каких ключевых словах база данных уже знает. - person Nick Gerakines; 02.01.2009
comment
Как сказал Ник, я ищу лучший способ найти записи, соответствующие нескольким ключевым словам одновременно. - person Eran Galperin; 03.01.2009
comment
Я предложил именно такое решение вопроса. Ищу альтернативы, так как это, наверное, самое неэффективное решение. Кроме того, это не относится к таблице документов, а к таблице пользователей. В каждый момент времени существует только один документ, который токенизируется и сравнивается с ключевыми словами пользователя. - person Eran Galperin; 03.01.2009
comment
Я бы предположил, что если вы правильно проиндексируете это, это действительно будет довольно эффективно. - person ʞɔıu; 03.01.2009
comment
Возможно, я не исключаю такой вариант. Просто ищу другие способы сделать это. - person Eran Galperin; 03.01.2009

Думали ли вы о переходе на полнотекстовое решение, такое как Sphinx?

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

Вот блог об использовании Sphinx в качестве решения для полнотекстового поиска в MySQL.

person Bill Karwin    schedule 02.01.2009
comment
На самом деле у меня большой опыт работы со сфинксом, и это здорово. Но это не поиск по тексту, а точные совпадения по списку ключевых слов. - person Eran Galperin; 03.01.2009

Я бы сделал здесь 2 вещи.

Сначала (и это не имеет прямого отношения к вопросу) я бы разбил ключевые слова пользователей по пользователям. Наличие большего количества таблиц с меньшим количеством данных, в идеале на разных серверах для распределенного поиска, где срезы или диапазоны пользователей существуют на разных срезах. Ака, все данные usera существуют на первом срезе, userb - на втором и т. Д.

Во-вторых, у меня была бы какая-то хеш-таблица в памяти для определения наличия ключевых слов. Скорее всего, это тоже будет федеративным, чтобы распространять поисковые запросы. Для n серверов с существованием ключевого слова хешируйте ключевое слово и измените его на n, а затем распределите диапазоны этих ключей по всем серверам memcached. Этот быстрый способ позволяет определить, отслеживается ли ключевое слово x, хешировать его и определить, на каком сервере оно будет находиться. Затем выполните поиск и соберите / объедините отслеживаемые ключевые слова.

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

Вкратце: SQL здесь не идеальное решение.

person Nick Gerakines    schedule 02.01.2009
comment
Разделение таблицы ключевых слов по пользователям может быть не очень хорошей идеей - у каждого пользователя есть только 4-5 ключевых слов, а пользователей много - в результате получится много таблиц. Как вы сказали, я склоняюсь к решению, отличному от SQL. - person Eran Galperin; 03.01.2009
comment
Даже при высоком распределении ключевых слов между пользователями у вас все равно будут гораздо меньшие наборы данных для итерации. Разделение данных на основе пользователей в большинстве случаев довольно эффективно и не требует много работы. - person Nick Gerakines; 03.01.2009
comment
Другие предположили, что таблица в памяти или временная таблица, созданная из ключевых слов статьи, будет настолько оптимизирована, насколько это возможно. Есть ли у вас что-нибудь, подтверждающее, что SQL здесь не является идеальным решением? - person Eran Galperin; 03.01.2009

Я взломал код для сканирования нескольких ключевых слов с помощью dawg (как было предложено выше со ссылкой на статью Scrabble), хотя я написал его из первых принципов, и я не знаю, похож он на алгоритм AHO или нет.

http://www.gtoal.com/wordgames/spell/multiscan.c.html

Один друг сделал несколько хаков в моем коде после того, как я впервые разместил его в списке рассылки программистов wordgame, и его версия, вероятно, более эффективна:

http://www.gtoal.com/wordgames/spell/multidawg.c.html

Хорошо масштабируется ...

G

person Community    schedule 11.02.2009