Lucene是
![](/icons/53676yi.gif)
个高性能
![](/icons/53676de.gif)
java全文检索工具包
![](/icons/53676dou.gif)
它使用
![](/icons/53676de.gif)
是倒排文件索引结构
![](/icons/53676dou2.gif)
该结构及相应
![](/icons/53676de.gif)
生成算法如下:
0)设有两篇文章1和2
文章1
![](/icons/53676de.gif)
内容为:Tom lives in Guangzhou,I live in Guangzhou too.
文章2
![](/icons/53676de.gif)
内容为:He once lived in Shanghai.
1)由于lucene是基于关键词索引和查询
![](/icons/53676de.gif)
![](/icons/53676dou.gif)
首先我们要取得这两篇文章
![](/icons/53676de.gif)
关键词
![](/icons/53676dou.gif)
通常我们需要如下处理措施
a.我们现在有
![](/icons/53676de.gif)
是文章内容
![](/icons/53676dou.gif)
即
![](/icons/53676yi.gif)
个
![](/icons/53676zifu.gif)
串
![](/icons/53676dou.gif)
我们先要找出
![](/icons/53676zifu.gif)
串中
![](/icons/53676de.gif)
所有单词
![](/icons/53676dou.gif)
即分词
![](/icons/53676dou2.gif)
英文单词由于用空格分隔
![](/icons/53676dou.gif)
比较好处理
![](/icons/53676dou2.gif)
中文单词间是连在
![](/icons/53676yi.gif)
起
![](/icons/53676de.gif)
需要特殊
![](/icons/53676de.gif)
分词处理
![](/icons/53676dou2.gif)
b.文章中
![](/icons/53676de.gif)
”in”, “once” “too”等词没有什么实际意义
![](/icons/53676dou.gif)
中文中
![](/icons/53676de.gif)
“
![](/icons/53676de.gif)
”“是”等字通常也无具体含义
![](/icons/53676dou.gif)
这些不代表概念
![](/icons/53676de.gif)
词可以过滤掉
c.用户通常希望查“He”时能把含“he”
![](/icons/53676dou.gif)
“HE”
![](/icons/53676de.gif)
文章也找出来
![](/icons/53676dou.gif)
所以所有单词需要统
![](/icons/53676yi.gif)
大小写
![](/icons/53676dou2.gif)
d.用户通常希望查“live”时能把含“lives”
![](/icons/53676dou.gif)
“lived”
![](/icons/53676de.gif)
文章也找出来
![](/icons/53676dou.gif)
所以需要把“lives”
![](/icons/53676dou.gif)
“lived”还原成“live”
e.文章中
![](/icons/53676de.gif)
标点符号通常不表示某种概念
![](/icons/53676dou.gif)
也可以过滤掉
在lucene中以上措施由Analyzer类完成
经过上面处理后
文章1
![](/icons/53676de.gif)
所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
文章2
![](/icons/53676de.gif)
所有关键词为:[he] [live] [shanghai]
2) 有了关键词后
![](/icons/53676dou.gif)
我们就可以建立倒排索引了
![](/icons/53676dou2.gif)
上面
![](/icons/53676de.gif)
对应关系是:“文章号”对“文章中所有关键词”
![](/icons/53676dou2.gif)
倒排索引把这个关系倒过来
![](/icons/53676dou.gif)
变成:“关键词”对“拥有该关键词
![](/icons/53676de.gif)
所有文章号”
![](/icons/53676dou2.gif)
文章1
![](/icons/53676dou.gif)
2经过倒排后变成
关键词 文章号
guangzhou 1
he 2
i 1
live 1,2
shanghai 2
tom 1
通常仅知道关键词在哪些文章中出现还不够
![](/icons/53676dou.gif)
我们还需要知道关键词在文章中出现次数和出现
![](/icons/53676de.gif)
位置
![](/icons/53676dou.gif)
通常有两种位置:a)
![](/icons/53676zifu.gif)
位置
![](/icons/53676dou.gif)
即记录该词是文章中第几个
![](/icons/53676zifu.gif)
(优点是关键词亮显时定位快);b)关键词位置
![](/icons/53676dou.gif)
即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快)
![](/icons/53676dou.gif)
lucene 中记录
![](/icons/53676de.gif)
就是这种位置
![](/icons/53676dou2.gif)
加上“出现频率”和“出现位置”信息后
![](/icons/53676dou.gif)
我们
![](/icons/53676de.gif)
索引结构变为:
关键词 文章号[出现频率] 出现位置
guangzhou 1[2] 3
6
he 2[1] 1
i 1[1] 4
live 1[2],2[1] 2
5
2
shanghai 2[1] 3
tom 1[1] 1
以live 这行为例我们介绍说明
![](/icons/53676yi.gif)
下该结构:live在文章1中出现了2次
![](/icons/53676dou.gif)
文章2中出现了
![](/icons/53676yi.gif)
次
![](/icons/53676dou.gif)
它
![](/icons/53676de.gif)
出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现频率来分析
![](/icons/53676dou.gif)
文章1中出现了2次
![](/icons/53676dou.gif)
那么“2,5”就表示live在文章1中出现
![](/icons/53676de.gif)
两个位置
![](/icons/53676dou.gif)
文章2中出现了
![](/icons/53676yi.gif)
次
![](/icons/53676dou.gif)
剩下
![](/icons/53676de.gif)
“2”就表示live是文章2中第 2个关键字
![](/icons/53676dou2.gif)
以上就是lucene索引结构中最核心
![](/icons/53676de.gif)
部分
![](/icons/53676dou2.gif)
我们注意到关键字是按
![](/icons/53676zifu.gif)
顺序排列
![](/icons/53676de.gif)
(lucene没有使用B树结构)
![](/icons/53676dou.gif)
因此lucene可以用 2元搜索算法快速定位关键词
![](/icons/53676dou2.gif)
实现时 lucene将上面 3列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存
![](/icons/53676dou2.gif)
其中词典文件不仅保存有每个关键词
![](/icons/53676dou.gif)
还保留了指向频率文件和位置文件
![](/icons/53676de.gif)
指针(什么格式
![](/icons/53676de.gif)
)
![](/icons/53676dou.gif)
通过指针可以找到该关键字
![](/icons/53676de.gif)
频率信息和位置信息
![](/icons/53676dou2.gif)
Lucene中使用了field
![](/icons/53676de.gif)
概念
![](/icons/53676dou.gif)
用于表达信息所在位置(如标题中
![](/icons/53676dou.gif)
文章中
![](/icons/53676dou.gif)
url中)
![](/icons/53676dou.gif)
在建索引中
![](/icons/53676dou.gif)
该field信息也记录在词典文件中
![](/icons/53676dou.gif)
每个关键词都有
![](/icons/53676yi.gif)
个field信息(
![](/icons/53676yinwei.gif)
每个关键字
![](/icons/53676yi.gif)
定属于
![](/icons/53676yi.gif)
个或多个field)
![](/icons/53676dou2.gif)
为了减小索引文件
![](/icons/53676de.gif)
大小
![](/icons/53676dou.gif)
Lucene对索引还使用了压缩技术
![](/icons/53676dou2.gif)
首先
![](/icons/53676dou.gif)
对词典文件中
![](/icons/53676de.gif)
关键词进行了压缩
![](/icons/53676dou.gif)
关键词压缩为<前缀长度
![](/icons/53676dou.gif)
后缀>
![](/icons/53676dou.gif)
例如:当前词为“阿拉伯语”
![](/icons/53676dou.gif)
上
![](/icons/53676yi.gif)
个词为“阿拉伯”
![](/icons/53676dou.gif)
那么“阿拉伯语”压缩为<3
![](/icons/53676dou.gif)
语>
![](/icons/53676dou2.gif)
其次大量用到
![](/icons/53676de.gif)
是对数字
![](/icons/53676de.gif)
压缩
![](/icons/53676dou.gif)
数字只保存和上
![](/icons/53676yi.gif)
个值
![](/icons/53676de.gif)
差值(这样可以减小数字
![](/icons/53676de.gif)
长度
![](/icons/53676dou.gif)
进而减少保存该数字需要
![](/icons/53676de.gif)
字节数)
![](/icons/53676dou2.gif)
例如当前文章号是16389(不压缩要用3个字节保存)
![](/icons/53676dou.gif)
上
![](/icons/53676yi.gif)
文章号是16382
![](/icons/53676dou.gif)
压缩后保存7(只用
![](/icons/53676yi.gif)
个字节)
![](/icons/53676dou2.gif)
下面我们可以通过对该索引
![](/icons/53676de.gif)
查询来解释
![](/icons/53676yi.gif)
下为什么要建立索引
![](/icons/53676dou2.gif)
假设要查询单词 “live”
![](/icons/53676dou.gif)
lucene先对词典 2元查找、找到该词
![](/icons/53676dou.gif)
通过指向频率文件
![](/icons/53676de.gif)
指针读出所有文章号
![](/icons/53676dou.gif)
然后返回结果
![](/icons/53676dou2.gif)
词典通常非常小
![](/icons/53676dou.gif)
因而
![](/icons/53676dou.gif)
整个过程
![](/icons/53676de.gif)
时间是毫秒级
![](/icons/53676de.gif)
![](/icons/53676dou2.gif)
而用普通
![](/icons/53676de.gif)
顺序匹配算法
![](/icons/53676dou.gif)
不建索引
![](/icons/53676dou.gif)
而是对所有文章
![](/icons/53676de.gif)
内容进行
![](/icons/53676zifu.gif)
串匹配
![](/icons/53676dou.gif)
这个过程将会相当缓慢
![](/icons/53676dou.gif)
当文章数目很大时
![](/icons/53676dou.gif)
时间往往是无法忍受
![](/icons/53676de.gif)