实施关键字比较方案(反向搜索)

时间:2009-01-02 20:12:43

标签: php mysql search keyword tokenize

我有一个不断增长的关键字数据库。我需要解析传入的文本输入(文章,提要等),并找出文本中存在的数据库中的关键字。关键字数据库比文本大得多。

由于数据库不断增长(用户需要添加越来越多的关键字),我认为最好的选择是将文本输入分解为单词并将其与数据库进行比较。我的主要困境是实施这种比较方案(PHP和MySQL将用于此项目)。

最天真的实现是针对关键字表创建一个简单的SELECT查询,并使用一个巨大的IN子句列出所有找到的关键字。

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

另一种方法是在内存中创建一个哈希表(使用像memcache这样的东西)并以相同的方式检查它。

有没有人有这种搜索的经验,对如何更好地实现这一点有任何建议?我还没有尝试过任何这些方法,我现在只是在收集想法。

6 个答案:

答案 0 :(得分:3)

为多个关键字搜索文本流的经典方法是Aho-Corasick finite automaton,它使用文本中的时间线性进行搜索。您需要进行微调以仅识别字边界上的字符串,或者只是检查找到的关键字并确保它们不会嵌入较大的单词中会更简单。

您可以在fgrep中找到实施。更好的是,Preston Briggs在C中编写了一个非常好的实现,完全可以实现您所谈论的关键字搜索。 (它搜索程序中是否存在“有趣的'标识符'。”Preston的实现是作为Noweb literate-programming tool的一部分进行分发的。您可以找到一种方法从PHP调用此代码,或者您可以在PHP中重写它 - 识别本身大约是220行C,主程序是另外135行。

所有提议的解决方案包括 Aho-Corasick,都具有以下共同属性:

  • 预处理步骤,其时间和空间与数据库中的关键字数量成比例。

  • 一个搜索步骤,其时间和空间与文本长度和找到的关键字数量成正比。

Aho-Corasick在搜索步骤中提供了相当大的比例常数,但如果你的文本很小,这无关紧要。实际上,如果您的文本很小且数据库很大,您可能希望最小化预处理步骤中使用的内存量。来自the world's fastest scrabble program的Andrew Appel的DAWG数据结构可能会成功。

答案 1 :(得分:1)

一般来说,

  1. 将文字分解为单词

    湾将单词转换回规范的根形式

    ℃。删除常用的连词

    d。剥离重复

  2. 将单词插入临时表,然后对关键字表进行内连接, 或(如您所建议)将关键字构建为复杂的查询条件

  3. 缓存一个3或4个字母的哈希数组可能是值得的,用于预先过滤潜在的关键字;你必须尝试找到记忆大小和效果之间的最佳权衡。

答案 2 :(得分:0)

我不是100%清楚你在问什么,但也许你正在寻找的是inverted index

更新

您可以使用倒排索引一次匹配多个关键字。

将新文档拆分为标记,并将与文档标识符配对的标记插入到反向索引表中。一个(相当非规范化的)倒排索引表:

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

这是否更接近你想要的?

答案 3 :(得分:0)

我会在这做两件事。

首先(这与问题没有直接关系)我会分手并按用户分区用户关键字。拥有更多具有更少数据的表,理想情况是在不同服务器上进行分布式查找,其中不同切片上存在切片或用户范围。 Aka,所有usera的数据都存在于第一层,用户b存在于第二层,等等。

其次,我有一些内存中的哈希表来确定关键字的存在。这可能也是联合以分发查找。对于n个关键字存在服务器,对关键字进行散列并将其修改为n,然后在所有memcached服务器上分配这些密钥的范围。通过这种快速方式,您可以说关键字x正在被观看,哈希并确定 所依赖的服务器。然后进行查找和收集/聚合关键字的跟踪。

此时,您至少会知道正在跟踪哪些关键字,您可以获取用户切片并执行后续查找,以确定哪些用户正在跟踪哪些关键字。

简而言之: SQL不是一个理想的解决方案。

答案 4 :(得分:0)

您是否考虑过毕业于全文解决方案,例如Sphinx

我在这里说话,因为我自己没有用过它。但它作为一种高速全文搜索解决方案受到了很多关注。它可能比您使用的任何关系解决方案更好地扩展。

这是关于在MySQL中使用Sphinx作为全文搜索解决方案的blog

答案 5 :(得分:0)

我使用dawg编写了一些扫描多个关键字的代码(如上面引用的Scrabble论文所述),尽管我是根据第一原理编写的,但我不知道它是否与AHO算法类似。 / p>

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

在我第一次将它发布到wordgame程序员邮件列表上之后,一位朋友对我的代码进行了一些攻击,他的版本可能更有效:

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

相当不错......