lucene简介
lucene是apache顶级项目,旨在解决企业中对于文件的全文检索问题,但是他是一个解决全文检索的工具包,提供了完整的查询引擎和索引引擎,为何说他是一个工具包呢,因为对于全文检索方案的设计还关乎高并发实现即分布式高可用问题,极大数据存储问题,毕竟对于大数据量来说,一个索引文件远远不够,还需要根据业务进行路由拆分,如生活搜索类根据地域拆分索引,电商网站根据类目拆分索引等,以及索引同步分片问题,此类问题不在本文叙述中,基于lucene研发的elasticsearch为开发者和企业提供了一整套完整解决方案,后文我们将对elasticsearch进行相关介绍,我们先了解lucene相关技术为先。
lucene设计策略点简述
每个开源软件设定总会有相关的策略点作为解决方案核心,这是我们阅读源码时需要care的点,也是从普通程序员迈向CTO必经的转变思考过程,单纯的技术并不能改变什么,带有思想的技术解决方案才是推动发展的灵魂,废话不多说,我们先来阐述前辈们认为优秀搜索引擎需要具备的特性;
1.面对海量数据快速获取结果;
2.查找时能寻找匹配度最高的文档;
3.去除无效语义或者恶意语义对于文档结果的干扰;
4.文档查找结果低信息熵;
5.能灵活调整上述四点属性;
这里阐述第一点,也是很重要的第一点,其他三点会在接下来的检索流程讲解和索引建立讲解中分步描述。
面对海量数据快速获取相关结果
当数据出现时,检索的需求就一直随着计算机科学的发展一直被不断地发展,不管是图书馆完备的多级索引作为查找鼻祖,还是后来针对业务牺牲空间换时间的宏观大集群策略,总在找一种折衷且有效的算法去实现现实需求,搜索引擎业界中有一种很经典且有效的数据结构 -- 倒排表
一个简单的比喻来说明倒排表
我们存在一堆散文集,包括鲁迅文集,巴金文集,老舍文集等等;存在着不可枚举的作者、不可枚举的散文书、不可枚举的出版社;按照通常的方法,我们会:
1.将散文集按照作者归档;
2.按照作者归档的前提下再在作者归档集合中按照出版社归档;
那么有一天书店老板来提货:我需要鲁迅散文集备货,
针对此需求你可能会庆幸,我刚好按照这个要求将书进行了归类,OK,一锅端走;
第二天,又来了个书店老板,我需要机械出版社的散文集进行备货,你心里就有点犯嘀咕了,差一点翻船,我只要在每个作者中提取机械出版社的东西就可以了
第三天,来了个很文艺的老板,我需要所有封皮绿色的书,你心里:MMP,挨个找吧。
这些场景映射进入计算机中是类似的,你需要建立科学有效的归档字段,否则你就需要逐个遍历书籍,来提取满足需求的书籍,即使有归档字段你也需要挨个查询归档类别,当数据逐渐扩展时,查询归档类别也成了一种负担,那么假如建立一种这样的结构,将所有特性提取出来,不通过任何中间属性进行层级关联,直接关联相关书籍,通过作者、出版社、颜色进行提取,并且所有属性下面直接关联数据ID,当需求输入匹配的属性要求,你就可以直接通过ID获取所有相关的书籍,跳过了查找归类遍历归类的步骤,直接获取数据集,形成简单高效的查找方式。如下表所示
序号 | 书籍位置 | 书籍名称 | 出版社 | 作者 | 颜色 |
---|---|---|---|---|---|
1 | 书架3层1排第二本 | 朝花夕拾 | 机械出版社 | 鲁迅 | 白色 |
2 | 书架2层2排第三本 | 背影 | 人民出版社 | 朱自清 | 灰色 |
3 | 书架1层4排第一本 | 骆驼祥子 | 机械出版社 | 鲁迅 | 灰色 |
4 | 书架5层2排第五本 | 老舍散文集 | 人民出版社 | 老舍 | 白色 |
那么倒排表的样子是什么呢?
属性 | 序号 |
---|---|
鲁迅 | 1,3 |
朱自清 | 2 |
老舍 | 4 |
机械出版社 | 1,3 |
人民出版社 | 2,4 |
白色 | 1,4 |
灰色 | 2,3 |
当需要机械出版社书籍时,找到原始数据序号为1,3的书籍,就可以直接取货
需要白色书籍,找到原始数据序号为1,4的数据,直接根据位置取货
但是有没有缺点呢,有,你需要朱姓作者的散文时,倒排表足够大时,就不能直接查找,只能遍历倒排表表头匹配,再查找,违背了设计倒排表初衷,所以这是一种以数据粒度换取速度的做法,现实的生产环境中,只要分词算法分出来的倒排表表头合理,就可以满足大部分的需求。
lucene评分机制简析
为何在此优先介绍评分机制呢?评分相关的是检索时文档的排序,而只有清楚需要什么样的搜索使用策略了,才能去定义如何建立索引策略。
不多说,看如下的lucene评分计算公式
lucene使用的是TF/IDF(term frequency–inverse document frequency)算法,直译为短语词频-反向文档频率算法,说明主要影响搜索评分的两个宏观维度为:
1.分词出来的词频;
2.该词所出现的文档数(即反向文档频率);
下面我们来一一解释公式每一项所代表的意思。
- coord(q,d) 评分因子,基于文档中出现查询项的个数。越多的查询项在一个文档中,说明文档的匹配程度越高。
/*
* @param q 命中短语个数
* @param d 查询短语个数
*/
public Float coord(int q,int d) {
return (float)q/(float)d;
}
举例 this is my blog,查询词是Her blog,那么对应的命中短语是 blog 为 1,查询短语个数为 Her blog 为 2,则coord为0.5。
- queryNorm(q)查询归一化因子
public float queryNorm(float sumOfSquaredWeights) {
return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
}
尽管查询归一值的目的是为了使查询结果之间能够相互比较,但是它并不十分有效,因为相关度评分的目的是为了将当前查询的结果进行排序,比较不同查询结果的相关度评分没有太大意义。此公式项对所有文档都保持一致,并且不可被更改,所以可以被忽略。
PS:sumOfSquaredWeights 是查询里每个词的 IDF 的平方和。
- tf(t in d) 指项t在文档d中出现的次数frequency。具体值为次数的开根号。
public float tf(float freq) {
return (float)Math.sqrt(freq);
}
如:this blog is my blog.则blog的词频为2,tf(2) = √2=1.4142315.
- idf(t) 反转文档频率, 出现项t的文档数docFreq
public float idf(long docFreq, long numDocs) {
return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
}
惯例 解释下这个公式参数,docFreq:当前项匹配的文档数,numDocs:索引中总文档数。
假定索引中有三个文档如下
this is a blog.
this is a Technology blog.
this is a website.
搜索词为blog,则用上述公司换算为In(3/(2+1) + 1) = In(2) = 0.693147181
- t.getBoost 查询时候查询项加权
为当前分词短语的加权倍数,默认为1,当前项<1时减权重,当前项设置>1时增加权重。
- norm(t,d) 长度相关的加权因子
这个公式项是一个匹配度干扰因子,扩大长度对搜索结果排序信息熵,举个例子:
this is blog;
this is my blog;
blog搜索匹配的时候,第一句的长度较短,则计算出的权重值较高,换句话说,对于搜索短语,第一句匹配的比为三分之一,第二句匹配比为四分之一,则代表第一句更匹配搜索短语,权重值需要增大。
小结
此公式设置策略总结为:
1.coord(q,d)强调搜索短语匹配比,是否被完全匹配,norm(t,d)强调搜索短语在文档中匹配命中比,idf(t)计算文档中出现搜索短语次数,三项结合在一起就是扩大最终结果的信息熵,强调搜索词在文档中的匹配度,从命中数,匹配百分比,搜索词匹配百分比三个纬度来影响搜索权重分值;
2.反向文档频率是从搜索整体来考察搜索短语对于权重计算的轻重,简单的道理,物以稀为贵,若这个短语索引中每个文档都有,则认为价值很低,反之,则价值很高。
3.查询加权此项设立是lucene中甩出的可商业化定制的项,举个例子,百度竞价排行,解释完毕~
下文将介绍lucene索引的构建过程和文件格式,想继续了解的朋友请耐心等待,我会一直更新有关搜索技术的讲解与产品设计,推荐技术的讲解与产品设计,作为对自己前几年职业生涯的总结,未完待续,tks~