У меня постоянно растущая база ключевых слов. Мне нужно проанализировать входящие текстовые вводы (статьи, каналы и т. д.) И найти, какие ключевые слова из базы данных присутствуют в тексте. База ключевых слов намного больше текста.
Поскольку база данных постоянно растет (пользователи добавляют все больше и больше ключевых слов, за которыми нужно следить), я считаю, что лучшим вариантом будет разбить вводимый текст на слова и сравнить их с базой данных. Моя основная дилемма - реализовать эту схему сравнения (в этом проекте будут использоваться PHP и MySQL).
Самой наивной реализацией было бы создание простого запроса SELECT к таблице ключевых слов с гигантским предложением IN, перечисляющим все найденные ключевые слова.
SELECT user_id,keyword FROM keywords WHERE keyword IN ('keyword1','keyword2',...,'keywordN');
Другой подход - создать хеш-таблицу в памяти (используя что-то вроде memcache) и таким же образом проверить ее.
Есть ли у кого-нибудь опыт работы с таким поиском и есть ли предложения о том, как это лучше реализовать? Я еще не пробовал ни один из этих подходов, я просто собираю идеи на данный момент.
Как сказано в первом абзаце, размер базы данных ключевых слов намного больше, чем слов в тексте. Статьи обрабатываются по мере их получения, а оповещения отправляются пользователям, зарегистрированным по определенным ключевым словам. Память сейчас не проблема.
Я не понимаю, как вы собираетесь работать намного быстрее, чем иметь копию вашей таблицы ключевых слов в памяти (куча) и проиндексировать и делать то, что вы сделали выше, или присоединиться к созданной в памяти таблице ключевых слов для каждой статьи. (Разделение пользователей поможет тоже). Однако репликация должна быть в вашем приложении.
это тоже может быть полезно - я наблюдаю аналогичную проблему: stackoverflow.com/questions/47762/how-to-ranking-search-resu lts






Я не на 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
это ближе к тому, что вы хотите?
Он пытается сделать наоборот. В этом случае для входящего огромного фрагмента теста найдите, о каких ключевых словах база данных уже знает.
Как сказал Ник, я ищу лучший способ найти записи, соответствующие нескольким ключевым словам одновременно.
Я предложил именно такое решение вопроса. Ищу альтернативы, так как это, наверное, самое неэффективное решение. Кроме того, это не относится к таблице документов, а к таблице пользователей. В каждый момент времени существует только один документ, который токенизируется и сравнивается с ключевыми словами пользователя.
Я бы предположил, что если вы правильно проиндексируете это, это действительно будет довольно эффективно.
Возможно, я не исключаю такой вариант. Просто ищу другие способы сделать это.
Я бы сделал здесь 2 вещи.
Во-первых (и это не имеет прямого отношения к вопросу) я бы разбил ключевые слова пользователей по пользователям. Наличие большего количества таблиц с меньшим количеством данных, в идеале на разных серверах для распределенного поиска, где срезы или диапазоны пользователей существуют на разных срезах. Ака, все данные usera существуют на первом срезе, userb - на втором и т. д.
Во-вторых, у меня была бы какая-то хеш-таблица в памяти для определения наличия ключевых слов. Скорее всего, это тоже будет федеративным, чтобы распространять поисковые запросы. Для n серверов с существованием ключевого слова хешируйте ключевое слово и измените его на n, а затем распределите диапазоны этих ключей по всем серверам memcached. Этот быстрый способ позволяет вам сказать, что ключевое слово x отслеживается, хешировать его и определить, на каком сервере находится было бы. Затем выполните поиск и соберите / объедините отслеживаемые ключевые слова.
На этом этапе вы, по крайней мере, будете знать, какие ключевые слова отслеживаются, и вы можете взять пользовательские фрагменты и выполнить последующий поиск, чтобы определить, какие пользователи отслеживают какие ключевые слова.
Вкратце: SQL здесь не идеальное решение.
Разделение таблицы ключевых слов по пользователям может быть не очень хорошей идеей - у каждого пользователя есть только 4-5 ключевых слов, а пользователей много - в результате получится много таблиц. Как вы сказали, я склоняюсь к решению, отличному от SQL.
Даже при высоком распределении ключевых слов между пользователями у вас все равно будут гораздо меньшие наборы данных для итерации. Разделение данных на основе пользователей в большинстве случаев довольно эффективно и не требует много работы.
Другие предположили, что таблица в памяти или временная таблица, созданная из ключевых слов статьи, будет настолько оптимизирована, насколько это возможно. Есть ли у вас что-нибудь, подтверждающее, что SQL здесь не является идеальным решением?
В общем,
разбить текст на слова
б. преобразовать слова обратно в каноническую корневую форму
c. отбросить общие союзные слова
d. удалить дубликаты
вставьте слова во временную таблицу, затем выполните внутреннее соединение с таблицей ключевых слов, или (как вы предложили) превратить ключевые слова в сложные критерии запроса
Может оказаться целесообразным кэшировать трех- или четырехбуквенный массив хешей для предварительной фильтрации потенциальных ключевых слов; вам придется поэкспериментировать, чтобы найти лучший компромисс между объемом памяти и эффективностью.
Есть ли опыт работы с таблицей в памяти по сравнению с массивом кэша памяти? Я бы подумал, что доступ к массиву будет быстрее?
Проще выполнить JOIN с таблицей с использованием механизма хранения MEMORY, чем с memcached.
Думали ли вы о переходе на полнотекстовое решение, такое как Сфинкс?
Я говорю здесь не из своей шляпы, потому что сам не использовал. Но он привлекает много внимания как решение для высокоскоростного полнотекстового поиска. Вероятно, оно будет масштабироваться лучше любого используемого вами реляционного решения.
Вот блог об использовании Sphinx в качестве решения для полнотекстового поиска в MySQL.
На самом деле у меня большой опыт работы со сфинксом, и это здорово. Но это не поиск по тексту, а точные совпадения по списку ключевых слов.
Классическим способом поиска в текстовом потоке нескольких ключевых слов является Конечный автомат Ахо-Корасика, который использует линейный временной интервал в тексте для поиска. Вам понадобятся незначительные изменения для распознавания строк только по границам слов, или, возможно, будет проще просто проверить найденные ключевые слова и убедиться, что они не встроены в слова большего размера.
Вы можете найти реализацию в fgrep. Более того, Престон Бриггс написал довольно хорошую реализацию на C, которая выполняет именно тот поиск по ключевым словам, о котором вы говорите. (Он ищет в программах вхождения «интересных» идентификаторов.) Реализация Preston распространяется как часть Инструмент грамотного программирования Noweb. Вы можете найти способ вызвать этот код из PHP или переписать его на PHP - само распознавание составляет около 220 строк C, а основная программа - еще 135 строк.
Все предлагаемые решения в том числе Aho-Corasick имеют следующие общие свойства:
Этап предварительной обработки, который занимает время и пространство, пропорциональное количеству ключевых слов в базе данных.
Шаг поиска, который занимает время и пространство, пропорциональное длине текста плюс количеству найденных ключевых слов.
Aho-Corasick предлагает значительно лучшие константы пропорциональности на этапе поиска, но если ваши тексты небольшие, это не имеет значения. Фактически, если ваши тексты маленькие, а ваша база данных большая, вы, вероятно, захотите минимизировать объем памяти, используемый на этапе предварительной обработки. Структура данных DAWG Эндрю Аппеля из самая быстрая программа скрэббла в мире, вероятно, поможет.
Я не ищу слова в тексте - я превращаю текст в слова, а затем сравниваю их с базой данных слов.
Код Престона делает именно то, что вы хотите. Он объединяет токенизацию и поиск за один шаг. Вы предоставляете список ключевых слов, строите автомат, а затем нажимаете на строку автоматом.
Вы все еще не понимаете. Я не хочу искать каждое ключевое слово в базе данных по тексту - но наоборот. Разбейте текст на слова и найдите, какие из них есть в базе данных. База данных намного больше текста.
Хорошо, с добавлением этой важной информации любой простой шаг предварительной обработки в базе данных подойдет - добавит все ключевые слова в хеш-таблицу. Затем разметьте свой небольшой текст, найдите каждое слово в хеш-таблице, и все готово. Aho-Corasick тоже подойдет, но вам не нужны сложности.
Да, меня не особо интересует этап предварительной обработки, я уже выбрал метод атаки на это. Меня беспокоит поиск большого числа ключевых слов по очень большой таблице.
Похоже, у вас уже есть подход, который работает, поэтому вам не нужна новая идея.
Мой подход работает, но я знаю только его. Просто проверяю, знают ли люди что-нибудь получше - поскольку здесь проблема с производительностью.
Люди могли бы лучше помочь вам, если бы вы сказали нам где, что производительность является проблемой: при подготовке списка раскладок или при изучении текста?
Как я уже сказал, я еще ничего не пробовал на практике, поэтому не могу сказать, где будет проблема с производительностью. Я просто ищу альтернативные подходы ...
Я взломал код для сканирования нескольких ключевых слов с помощью dawg (как было предложено выше со ссылкой на статью о Scrabble), хотя я написал его из первых принципов, и я не знаю, похож он на алгоритм AHO или нет.
http://www.gtoal.com/wordgames/spell/multiscan.c.html
Один друг сделал несколько хаков в моем коде после того, как я впервые разместил его в списке рассылки программистов wordgame, и его версия, вероятно, более эффективна:
http://www.gtoal.com/wordgames/spell/multidawg.c.html
Хорошо масштабируется ...
грамм
Здесь много вопросов. Сколько уникальных ключевых слов существует (у каждого пользователя есть похожие ключевые слова)? Сколько у тебя памяти? Вам нужно, чтобы данные были актуальными или их можно обрабатывать через определенные промежутки времени?