之前学习过很多刘老师的lucene源码分析的课程,结果现在整的都忘了,这次重新梳理一下争取形成自己的东西。
后面就不容易忘掉了。
刘老师的课程是基于lucene2.x的源码分析的,后面lucene迭代了很多版本,也引入了新的数据结构进行优化,但是主体的模块基本上是没有变的。计划是先把之前的lunce的数据结构整理一下,因为可以查阅刘老师的课程,可以有很好的参考作用。在这个基础上再整理和对比新的lucene的优化点,基于lucene7.x在这里主要关注lucene的存储结构,因为了解了存储结构基本上就了解了大体的实现。
1. 搜索的概览
搜索主要是解决用户基于文本进行搜索的问题。比如在很多本书中搜索一些内容,或者搜索一些帖子,博客等等。
一个搜索服务架构分为两大部分:索引+搜索。
1.1 索引
索引的过程又分为数据采集,清洗,进入lucene等等,这里我们不关注数据源的问题,只关注索引在进入lucene会有哪些操作。
1.1.1. 数据处理
在往lucene进行数据存储的时候首先会进行分词,比如"我的家乡是河南","this ARE GOOD books " 在下面显示了对应的分词结果
GET user/_analyze
{
"analyzer": "ik_smart",
"text": ["我的家乡是河南"]
}
对应的分词结果是
{
"tokens" : [
{
"token" : "我",
"start_offset" : 0,
"end_offset" : 1,
"type" : "CN_CHAR",
"position" : 0
},
{
"token" : "的",
"start_offset" : 1,
"end_offset" : 2,
"type" : "CN_CHAR",
"position" : 1
},
{
"token" : "家乡",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "是",
"start_offset" : 4,
"end_offset" : 5,
"type" : "CN_CHAR",
"position" : 3
},
{
"token" : "河南",
"start_offset" : 5,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 4
}
]
}
再来一个英文的
GET user/_analyze
{
"analyzer": "ik_smart",
"text": ["this ARE GOOD books "]
}
{
"tokens" : [
{
"token" : "good",
"start_offset" : 9,
"end_offset" : 13,
"type" : "ENGLISH",
"position" : 0
},
{
"token" : "books",
"start_offset" : 14,
"end_offset" : 19,
"type" : "ENGLISH",
"position" : 1
}
]
}
对应的可以看到,一个句子被分成了多个词,同时可能会有一些转化,比如大写变小写,复数变单数等。
其实analyzer又有三个部分组成
- character_filter 对输入文档的源数据进行处理,比如将拉丁文转为数字等,也可以是删掉一些字符
- tokenizer 对character_filter 过滤后的文档进行分词,会记录词的位置信息以及字符偏移量
- token_filter 对分出来的词进行处理,比如大写转小写,词干抽取等。
词干抽取被称为stemming,方式也分为两种,基于算法的词干抽取和基于字典的词干抽取。
基于算法有可能会导致不准确的结果,但是只要index 和 query的过程都使用同样的算法,那么就可以保证搜索效果的一致性。
基于字典的词干抽取的效果则取决于字典的质量,而且大量的字典可能会占据比较大的内存。
1.1.2. 数据存储
在一个文档进行了分词,词干提取等处理之后,会交给indexer,由indexer来进行存储。
存储一般包括两个部分,索引的正向信息,和反向信息,
正向信息是指从index–>segment—>doc-field—>field-terms 的信息,这里存储的基本上是文档的正向信息,也是完整信息。
反向信息就是我们常说的倒排索引了 terms—>doc-list 通过对terms的命中可以快速的找到对应的doc信息。
1.2 查询search
query样例 用户输入语句:lucene AND learned NOT hadoop。
1.2.1. 语法分析
查询语句又会有一些语法,类似sql一样,必有有or,and,not等语法,所以先要进行这些语法分析,识别这些关键字
提取了两个关键字 AND NOT
1.2.2. 词分析
和index的时候对此的操作是一致的
上面会产生三个term lucene learned hadoop
1.2.3 搜索搜因得到文档
- 根据前面两步得到了查询的逻辑以及对应的term
- 从倒排链表中找到对应的文档集合,得到3个文档集合
- 对lucene和learned对应的两个文档集合求交集,然后和hadoop的文档集合求差集。
1.2.4 进行相关性分析,根据相关性打分进行排序,并返回结果
相关性得分计算有一些公开的比较成熟的方案,比如之前的tf/idf,现在的BM25打分公式等。
上面就是搜索是两大模块式 index,search的主体流程,后面我们逐渐深入lucene的数据结构。
·