背景
关系数据库不适合做全文搜索
- like '%xxx%'效率很慢,建的索引将无效,查询的时候会像翻书一样一页一页的翻
- 返回的结果没有匹配度的概念,比如在所有文章里索引一篇想要的文章,可能是希望搜索的关键词在文章中出现的次数越多越是我想要的结果
- 当搜索live的时候,也想把lives/living搜出来,但是数据库很难做到
倒排算法
了解倒排算法之后方便理解为什么搜索引擎非常适合做全文搜索。简单来说倒排算法就是通过关键词快速定位到文章,首先记录了很多的关键词,关键词里记录了该关键词在哪些文章里出现了,当用户搜索的时候先找到关键词,然后计算出最相关的头几十篇文章返回给用户。
Lucene在国外知名度很高,现在已经是Apache的顶级项目,国内也有很多应用,它使用的就是倒排文件索引结构,算法结构如下:
(0)设有两篇文章1和2
文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too
文章2的内容为:He once lived in Shanghai.
(1)全文分析:由于lucene是基于关键词索引和查询的,首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施
- a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。
- b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉
- c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。
- d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”
- e.文章中的标点符号通常不表示某种概念,也可以过滤掉
经过上面处理后
文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
文章2的所有关键词为:[he] [live] [shanghai]
(2) 倒排索引:有了关键词后,我们就可以建立倒排索引了。上面的对应关系是:“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。文章1,2经过倒排后变成
关键词 |
文章号 |
guangzhou |
1 |
he |
2 |
i |
1 |
live |
1,2 |
shanghai |
2 |
tom |
1 |
(3)通常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:a)字符位置,即记录该词是文章中第几个字符(优点是关键词亮显时定位快);b)关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记录的就是这种位置。
加上“出现频率”和“出现位置”信息后,我们的索引结构变为:
关键词 |
文章号 |
[出现频率] |
出现位置 |
guangzhou |
1 |
[2] |
3,6 |
he |
2 |
[1] |
1 |
i |
1 |
[1] |
4 |
live |
1 |
[2] |
2,5 |
|
2 |
[1] |
2 |
shanghai |
2 |
[1] |
3 |
tom |
1 |
[1] |
1 |
(4) 以live 这行为例我们说明一下该结构:live在文章1中出现了2次,文章2中出现了一次,它的出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现频率来分析,文章1中出现了2次,那么“2,5”就表示live在文章1中出现的两个位置,文章2中出现了一次,剩下的“2”就表示live是文章2中第 2个关键字。
以上就是lucene索引结构中最核心的部分。我们注意到关键字是按字符顺序排列的(lucene没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词。
结语
参考:http://www.chedong.com/tech/lucene.html
参考的这篇文章里讲得更详细,网上也有很多介绍倒排算法的文章。既然已经有了,为什么我还要写这篇文章呢?我的考虑是倒排算法是搜索引擎的核心,理解了它能更好的理解搜索引擎的其他东西,也作为后续关于搜索引擎文章的完整性。