有效搜索大型字符串数据库中的部分匹配

时间:2012-12-09 15:47:58

标签: c++ database algorithm search

我想创建一个图书馆书籍的数据库,可以有效地搜索子字符串匹配。 也就是说,如果我搜索“编程”,那么将返回包含单词编程的所有书名。 该数据库可以预处理,并将完全存储在内存中。

什么是有效的数据结构和搜索算法来解决这个问题? 我想在C ++中完全实现它,所以请不要使用第三方库。

2 个答案:

答案 0 :(得分:6)

Suffix tree是子字符串搜索的有效数据结构。

这个想法是:
创建后缀树数据结构,并从每个叶子连接到与此后缀所代表的书籍相关的条目。
在查询时间 - 使用子字符串遍历树 - 并从您到达的终点(最长匹配) - 执行一些遍历(例如DFS)并检索与所有后缀相关的所有条目query是。的前缀。


当然,如果你只想要单词而不是所有的子串,一个地图(基于树/散列)可能就足够了,并且更容易实现和使用(该类型应该是map<string,list<book> >,例如基于树的方法,它将从每个单词映射到包含标题中包含该单词的所有书籍的列表。
您也可以使用trie来实现地图。

答案 1 :(得分:2)

对于子字符串匹配,有一个简单的方案:在“块”中拆分完整标题,并按以下方式创建数据库:

  • 每本书都是唯一标识的(ID /指针)
  • 每个“块”指向一组图书标识符

当用户查询系统时,以相同的方式分割她的请求以识别匹配的书籍。

通过这个简单的方案,您可以获得2点功能定制:如何派生块以及如何对书籍进行排名;和1点技术定制:如何“合并/加入”不同匹配块的集合,这取决于你想要对书籍进行排名的方式。

  

如何推导大块?

一种简单(但有效)的方式是分割单词边界:The C++ Programming Language变为{the, c++, programming, language}

注意:经常会忽略一些单词(黑名单)。例如,The可能出现在80%的标题中,因此在大多数情况下考虑它是没有用的。

注意:搜索可能不区分大小写。

  

如何排名?

一个天真的算法是返回所有匹配。更好的方法是根据查询中与该ID匹配的块数对它们进行排名。一个更好的方法是将那些单词出现的标题排在较高的位置,而查询的顺序与查询相同(最长的子匹配)。当然,你应该考虑同义词

排名可能是系统的核心,谷歌很受欢迎,因为它的排名算法运行良好意味着如果找到你想要的东西。

  

如何实施合并/加入?

除非您只想返回与原始查询中的所有块相匹配的搜索结果(这很有用,但因为同义词而烦人),那么您应该保留有序集并为每个创建它们的交集。块:

  • chunk1{B1, B2, B7, B9, B15}
  • chunk2{B1, B7, B8, B13, B15}
  • chunk3{B1, B3, B4, B7, B9, B12, B13, B14, B15}

然后,与chunk1chunk2的集合相交,前往{B1, B7, B15}并与chunk3相交(不会改变任何内容)。

注意:从较小的集合开始,您可以保留较小的中间结果,从而加快结果。

注意:当一个较小的集合与一个更大的集合相交时,较大集合的线性行走可能比二进制搜索慢得多。

另一方面,如果您想对搜索结果进行排名,那么您可能需要将地图ID作为中间结果保留 - &gt;得分了。该映射可以是二叉搜索树或散列映射(后者对于非常大的集合来说速度更快,但对于小型集合而言则有一些开销)。

请注意,这种排名的东西通常很慢,但很容易并行化。这就是Google对MapReduce所做的事情。