Transcript Lucene原理
最关心的一些问题:
1. Lucene是一个怎样的系统
2. Lucene可以干嘛
3. Lucene的原理
谭望达
Lucene具有类似于XML的文件格式
Document
Field1
Token
Field2
Token
Token
Token
<Title>
蜗居
</Title>
<Abstract>
反映了房价居高不下, 官商勾结,
与年轻人买房难的一些故事
</Abstract >
<Content>
...
</Content>
Lucene解析器的优势:
1. 扩展性好, 可以随意定制, 可以解析任意格式文档
2. Lucene自带的包中已经有很多现成的解析器了
Jode IS a dog
Analyzer
jode \ dog
Jode \ IS \ a \ dog
Tokenizer
TokenFilter
我们需要做的就是把原类继承, 实现其方法即可
Lucene的基本类型
Byte: 是最基本的类型,长8位(bit)。
UInt32:由4个Byte组成。
UInt64:由8个Byte组成。
VInt: 变长的整形
Chars: 是UTF-8编码的一系列Byte。
Strings: 一个字符串首先是一个VInt来表示此
字符串包含的字符的个数,接着便是UTF-8编
码的字符序列Chars
前缀-后缀规则(Prefix+Suffix)
差值规则
或然跟随规则(A, B?)
跳跃表规则
一个词典(比如四库全书)如果太大, 怎么办呢?
一部电视剧(比如西游记)如果太长怎么办呢?
一部游戏(魔兽世界)如果太好玩怎么办呢?
那么一个索引如果太复杂怎么办呢?
对了, 这就是段索引,所有的段索引组成
了一个完整的索引!
Fields
.Fnm文件
.Fdx文件
.Fdt文件
指针
Lucene索
引文件结
构
Postings
字典
.tis文件
频率
.frq文件
位置
.prx文件
规则化
.f(n)文件
Segments
.segments文件
指针
.tii文件
Lucene的索引合并是Lucene的一个非常经
典的内容
常见的合并索引的方式:
1. 每加入一篇文章就重新生成索引 (代价好高!)
2. 或者增量索引, 也就是每加入一篇文章就对索
引进行修改, (代价也不小!)
可以说, 评价一个搜索引擎的好坏, 可以看
看他对增加删除文档的支持程度如何
Lucene的索引宏观合并过程如下
一篇文档
一篇文档
一篇文档
………
在内存中
到达了一个阈值, Lucene默认为10
内存中生成索引
并写入磁盘(段索引)
重复这个过程…
一段索引
一段索引
一段索引
………
在磁盘中
Lucene的索引宏观合并过程如下(续)
一段索引
一段索引
一段索引
………
在磁盘中
到达了一个阈值, Lucene默认为10
启动合并过程
Lucene的索引微观合并过程如下
启动合并过程
合并前的准备
合并Field
…
tis
fnm
fdx
再Hash, 重新完成
合并Posting
归并排序, 重构跳跃表
Lucene的索引合并创新之处
大部分的搜索引擎(数
据库)都是使用B树来维
护索引结构.
索引的更新会导致大
量的IO操作
Lucene使用内存与
磁盘作为缓存, 进行批量
和增量的索引操作, 把小
的索引合并到大的索引
中
在不影响检索效率的
前提下, 提高了索引的效
率
查询模型
向量模型
Lucene在评估查询语句与Document之间的符合程度时用了向
量模型.
布尔模型
Lucene在词汇的逻辑设置中使用了布尔模型.
评分方式
协调函数, 当某个Document中包含的query数量多, 就返回较高的
权重数值
是query的规范化函数, 这个函数不影响document的评价, 因为所有
的document都会乘上这个规格化因子的数值, 这个函数只是对
query起作用.
是查询的时候增加的权重, 完全凭个人喜好添加
是文档的标准化因子, 参见后面的内容
获得索引文件名前缀
获得Field名称及特性
读取字典文件到内存中
得到频率和位置信息
Lucene的查询分析器为我们提供了丰富的
查询语法, 整合了JavaCC的词法分析器
项查询: let it be “hello world”
域查询: title:”The A” And Text:go
词条查询: te?t te*t
模糊查询: roam~ roam~0.8
间距查询: “jakarta apache” ~10
范围查询: title : {Aida TO Carmen}
权重查询: jakarta^4 apache
布尔查询: jakarta OR apache
布尔
词条
模糊
Query
对文档的
相似度计算(见下页)
Scorer
对应的打分器
打分, 获取Top K
的文档指针
取得搜索结果
假设有这样的一个查询:
魔兽 dota 英雄
有下面几篇文档:
(doc 1) dota里面的英雄都是来自魔兽
(doc 2)黄继光是一个英雄
(doc 3)我最爱的魔兽 英雄是恶魔猎手
整理出一个倒排表(仅保留查询关键字):
Doc ID
魔兽
Dota
英雄
1
1
1
1
2
NULL
NULL
1
3
1
NULL
1
计算:
DocFreq(单词在所有文档中的出现次数), 全局
TF(单词在某篇文档中的出现次数), 局部(需要重新计算)
IDF, 单词的稀有程度, 局部
把表格补充完整:
Doc ID
魔兽
Dota
英雄
1
1
1
1
2
NULL
NULL
1
3
1
NULL
1
DocFreq
2
1
3
IDF
0.18
0.47
0
第一种方法:
遍历每一篇文档, 然后把得分加起来, 保留Top K
时间复杂度 --- O(文档总数)
空间复杂度 --- O(1), 文档不读入内存, 在磁盘中
读取
第二种方法:
遍历查询单词, 然后遍历倒排表中该单词对应的全部文
档,完成这个步骤后再对文档排序
时间复杂度 --- O(文档总数(最坏情况))
空间复杂度 --- O(文档总数(最坏情况))
并发合并
块处理
标准化因子部分(1):
不同的文档重要性不同。有的文档重要些,有的文档相对不重要,
比如对于做软件的,在索引书籍的时候,我想让计算机方面的书
更容易搜到,而文学方面的书籍搜索时排名靠后。
不同的域重要性不同。有的域重要一些,如关键字,如标题,有
的域不重要一些,如附件等。同样一个词(Term),出现在关键字
中应该比出现在附件中打分要高。
根据词(Term)在文档中出现的绝对次数来决定此词对文档的重要
性,有不合理的地方。比如长的文档词在文档中出现的次数相对
较多,这样短的文档比较吃亏。比如一个词在一本砖头书中出现
了10次,在另外一篇不足100字的文章中出现了9次,就说明砖头
书应该排在前面码?不应该,显然此词在不足100字的文章中能出
现9次,可见其对此文章的重要性。
标准化因子部分(2):
由于以上原因,Lucene在计算Term Weight时,都会乘上
一个标准化因子(Normalization Factor),来减少上面三个
问题的影响。
标准化因子(Normalization Factor)是会影响随后打分
(score)的计算的,Lucene的打分计算一部分发生在索引
过程中,一般是与查询语句无关的参数如标准化因子.
标准化因子部分(3):
Hadoop + Lucene构建分布式引擎
参考资料: http://lucene.apache.org/hadoop/
Nutch – 基于Lucene的开源搜索引擎
参考资料: lucene.apache.org/nutch/
Lucene是一个面向对象程序设计的典范, 所
有问题都是通过一个额外的抽象层来方便
以后的扩展和重用(Strategy模式)
简单的应用入口来调用一系列底层代码
(example代码非常简单)
除了灵活的接口设计, 还提供了一系列可以
直接使用的Analyzer, 方便使用
车东的Lucene站点
http://www.chedong.com/tech/lucene.html
Lucene学习总结
http://forfuture1978.javaeye.com/blog/54682
4
<Lucene分析与应用>
机械工业出版社, 吴众欣 等