Loading... Apache Lucene是一个开源的高性能、可扩展的信息检索引擎,提供了强大的数据检索能力。 本篇是ElasticSearch的前置偏,在了解了ES的基本原理和用法后回头看看Lucene,很多疑惑点都豁然开朗 <!--more--> # 查询概念 ## 基础概念  <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-c8c44f51692445ec960d47c82f7622dc29" aria-expanded="true"><div class="accordion-toggle"><span>Index-索引</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-c8c44f51692445ec960d47c82f7622dc29" class="collapse collapse-content"><p></p> Lucene的Index可以理解为一个**文档收纳箱**,你可以往内部塞入新的文档,或者从里面拿出文档,但如果你要修改里面的某个文档,则必须先拿出来修改后再塞回去。这个收纳箱可以塞入各种类型的文档,文档里的内容可以任意定义,Lucene都能对其进行索引。 ES中Index的概念则是数据库的**表**,只能对索引中构建Mapping的字段进行索引。 <p></p></div></div></div> <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-cf18c6a8eef150e556ee726efebd782f24" aria-expanded="true"><div class="accordion-toggle"><span>Segment-段</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-cf18c6a8eef150e556ee726efebd782f24" class="collapse collapse-content"><p></p> 一个Index由一个或多个Segment构成,它在保障写入的同时,提供了近实时的查找。Lucene会先将数据(即文档)写入 `Memory Buffer`中,此时不可读。再将数据 `Refresh`到 `Filesystem Cache`中(每秒/Buffer大小超过JVM内存10%),转成段(构建每个段中都有自己独立的“索引”)并打开,此时可读。 段中的文档永远不能被更改,避免了随机写,写入都是Batch和Append,所以能达到很高的吞吐量。文档的删除是由另外一个文件保存被删文档的DocID,保证数据文件不可被修改。 Index的查询需要对多个Segment进行查询并对结果进行合并,还需要处理被删除的文档。为了对查询进行优化,Lucene会有策略对多个Segment进行合并(合并大小相近的段到新的大段中,并删除旧段,该过程不影响搜索) <p></p></div></div></div> <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-b5359f97f7ef65b0d6b390946f8d420b19" aria-expanded="true"><div class="accordion-toggle"><span>Document-文档</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-b5359f97f7ef65b0d6b390946f8d420b19" class="collapse collapse-content"><p></p> Document偏向于文档数据库中文档的概念,即关系数据库中的行。文档的唯一ID叫做Sequence Number(DocId、_id) DocId在Segment中唯一,每个段中DocId取值都是从0递增。在Index层级中则是类似分表一样保持它的唯一(Index内有两个段,每个段内分别有100个文档,他们DocId都是0-100,转换到Index级的DocId需要将第二个段的DocId范围转换为100-200)。 DocId可能会在段合并的时候改变(合大段、删除),所以是时间点上的数据唯一。 DocId采用一个从0开始底层的Int32值,是一个比较大的优化,同时体现在数据压缩和查询效率上。例如数据压缩上的Delta策略、ZigZag编码,以及倒排列表上采用的SkipList等。 <p></p></div></div></div> <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-e8442ffecf937c9190346196a797813a99" aria-expanded="true"><div class="accordion-toggle"><span>Field-字段</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-e8442ffecf937c9190346196a797813a99" class="collapse collapse-content"><p></p> 一个Document会由一个或多个Field组成,Field是Lucene中数据索引的最小定义单位。 Lucene提供多种不同类型的Field,例如StringField、TextField、LongFiled或NumericDocValuesField等,Lucene根据Field的类型(FieldType)来判断该数据要采用哪种类型的索引方式(Invert Index、Store Field、DocValues或N-dimensional等)。 <p></p></div></div></div> <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-ca88a60d562c867da1e54c025a46c06b65" aria-expanded="true"><div class="accordion-toggle"><span>Term-词 Term Dictionary-词典</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-ca88a60d562c867da1e54c025a46c06b65" class="collapse collapse-content"><p></p> Lucene中索引和搜索的最小单位,一个Field会由一个或多个Term组成,Term是由Field经过Analyzer(分词)产生。Term Dictionary即Term词典,是根据条件查找Term的基本索引。 <p></p></div></div></div> <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-6dfc985391fc63b63237db1ac454c57889" aria-expanded="true"><div class="accordion-toggle"><span>倒排索引</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-6dfc985391fc63b63237db1ac454c57889" class="collapse collapse-content"><p></p> 倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。 Lucene内最核心的倒排索引,本质上就是Term到所有包含该Term的文档的DocId列表的映射。所以Lucene内部在搜索的时候会是一个两阶段的查询,第一阶段是通过给定的Term的条件找到所有Doc的DocId列表,第二阶段是根据DocId查找Doc。Lucene提供基于Term的搜索功能,也提供基于DocId的查询功能。 <p></p></div></div></div> ### 索引结构 Lucene从4开始大量使用的数据结构是 `FST(Finite State Transducer)`。FST有两个优点: 1. 空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间。 2. 查询速度快。O(len(str))的查询时间复杂度。 FST的原理解析可以看[这里](https://www.cnblogs.com/LBSer/p/4119841.html),其本质就是用[Dijikstra](https://www.cnblogs.com/dijkstra2003/p/7222182.html)求最短路。 ### suoy Last modification:September 13, 2022 © Allow specification reprint Like 0 喵ฅฅ