版权声明:本文为CSDN博主「代码狂魔v」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xvktdmjg/article/details/113040699
一.lucene优势:
1.可扩展,高性能的索引过程
在现代化的硬件上面索引超过150G/小时
只需要1M的堆
增量索引和批量索引一样快
索引大小大约是文本索引大小的20-30%
强大,准确和高效的搜索算法
2.排名搜索——最好的结果优先返回
许多强大的查询类型:短语查询,通配符查询,接近查询,范围查询等
针对不同的域搜索(例如标题、作者、内容)
对任何域进行排序
具有合并结果的多索引搜索
允许同步更新和搜索
插拔式的排名模型, 包括 Vector Space Model 和 Okapi BM25
可配置的存储引擎
二.Lucene底层使用的倒排索引理解:
1.假设文档集合包含五个文档,每个文档内容如图3所示,在图中最左端一栏是每个文档对应的文档编号。我们的任务就是对这个文档集合建立倒排索引。
2.中文和英文等语言不同,单词之间没有明确分隔符号,所以首先要用分词系统将文档自动切分成单词序列。这样每个文档就转换为由单词序列构成的数据流,为了系统后续处理方便,需要对每个不同的单词赋予唯一的单词编号,同时记录下哪些文档包含这个单词,在如此处理结束后,我们可以得到最简单的倒排索引。在下图中,“单词ID”一栏记录了每个单词的单词编号,第二栏是对应的单词,第三栏即每个单词对应的倒排列表。比如单词“谷歌”,其单词编号为1,倒排列表为{1,2,3,4,5},说明文档集合中每个文档都包含了这个单词。
3.之所以说上图所示倒排索引是最简单的,是因为这个索引系统只记载了哪些文档包含某个单词,而事实上,索引系统还可以记录除此之外的更多信息。下图是一个相对复杂些的倒排索引,与上图的基本索引系统比,在单词对应的倒排列表中不仅记录了文档编号,还记载了单词频率信息(TF),即这个单词在某个文档中的出现次数,之所以要记录这个信息,是因为词频信息在搜索结果排序时,计算查询和文档相似度是很重要的一个计算因子,所以将其记录在倒排列表中,以方便后续排序时进行分值计算。单词“创始人”的单词编号为7,对应的倒排列表内容为:(3:1),其中的3代表文档编号为3的文档包含这个单词,数字1代表词频信息,即这个单词在3号文档中只出现过1次,其它单词对应的倒排列表所代表含义与此相同。
三.数据分段
Lucene在搜索中引入了段(Segment)的概念(将一个索引文件拆分为多个子文件,每个子文件叫作段),每个段都是一个独立的可被搜索的数据集,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。
1.在分段的思想下,对数据写操作的过程如下。
新增
:当有新的数据需要创建索引时,由于段的不变性,所以选择新建一个段来存储新增的数据。
删除
:当需要删除数据时,由于数据所在的段只可读,不可写,所以Lucene在索引文件下新增了一个.del的文件,用来专门存储被删除的数据id。当查询时,被删除的数据还是可以被查到的,只是在进行文档链表合并时,才把已经删除的数据过滤掉。被删除的数据在进行段合并时才会真正被移除。
更新
:更新的操作其实就是删除和新增的组合,先在.del文件中记录旧数据,再在新段中添加一条更新后的数据。
2.段不变性的优点如下
:
①不需要锁。因为数据不会更新,所以不用考虑多线程下的读写不一致情况。
②可以常驻内存。段在被加载到内存后,由于具有不变性,所以只要内存的空间足够大,就可以长时间驻存,大部分查询请求会直接访问内存,而不需要访问磁盘,使得查询的性能有很大的提升。
缓存友好。在段的生命周期内始终有效,不需要在每次数据更新时被重建。
③增量创建。分段可以做到增量创建索引,可以轻量级地对数据进行更新,由于每次创建的成本很低,所以可以频繁地更新数据,使系统接近实时更新。
3.段不可变的缺点:
①删除:旧数据不会被马上删除,而是在.del文件中被标记为删除。而旧数据只能等到段更新时才能真正被移除,这样会有大量的空间浪费。
②更新:更新数据由删除和新增这两个动作组成。若有一条数据频繁更新,则会有大量的空间浪费。
③新增:由于索引具有不变性,所以每次新增数据时,都需要新增一个段来存储数据。当段的数量太多时,对服务器的资源(如文件句柄)的消耗会非常大,查询的性能也会受到影响。
④查询:在查询后需要对已经删除的旧数据进行过滤,这增加了查询的负担。
三.延迟写策略
1.为了提升写的性能,Lucene并没有每新增一条数据就增加一个段,而是采用延迟写的策略,每当有新增的数据时,就将其先写入内存中,然后批量写入磁盘中。若有一个段被写到硬盘,就会生成一个提交点,提交点就是一个用来记录所有提交后的段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限
2.相反,当段在内存中时,就只有写数据的权限,而不具备读数据的权限,所以也就不能被检索了。从严格意义上来说,Lucene或者Elasticsearch并不能被称为实时的搜索引擎,只能被称为准实时的搜索引擎。
3.写索引的流程如下:
新数据被写入时,并没有被直接写到硬盘中,而是被暂时写到内存中。Lucene默认是一秒钟,或者当内存中的数据量达到一定阶段时,再批量提交到磁盘中,当然,默认的时间和数据量的大小是可以通过参数控制的。通过延时写的策略,可以减少数据往磁盘上写的次数,从而提升整体的写入性能。
四.分段合并
合并原因:虽然分段比每次都全量创建索引有更高的效率,但由于在每次新增数据时都会新增一个段,所以经过长时间的积累,会导致在索引中存在大量的段,当索引中段的数量太多时,不仅会严重消耗服务器的资源,还会影响检索的性能。
因为索引检索的过程是:查询所有段中满足查询条件的数据,然后对每个段里查询的结果集进行合并,所以为了控制索引里段的数量,我们必须定期进行段合并操作。但是如果每次合并全部的段,则将造成很大的资源浪费,特别是”大段”的合并。
所以Lucene现在的段合并思路是:根据段的大小先将段进行分组,再将属于同一组的段进行合并。但是由于对超级大的段的合并需要消耗更多的资源,所以Lucene会在段的大小达到一定规模,或者段里面的数据量达到一定条数时,不会再进行合并。所以Lucene的段合并主要集中在对中小段的合并上,这样既可以避免对大段进行合并时消耗过多的服务器资源,也可以很好地控制索引中段的数量。
五.总结
反向索引
:Lucene 采用了基于反向索引的设计原理,可以非常高效地实现文本查找
数据分段
:在底层采用了数据分段的存储模式,分段是只读的,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。
延迟写
:写入性能非常高,因为是先写入内存中,但是内存中的数据不可读,所以是准实时的搜索引擎.