Lucene初识

Lucene是一种高性能、可伸缩的信息搜索(IR)库,在2000年开源,最初由鼎鼎大名的Doug Cutting开发,是基于Java实现的高性能的开源项目。Lucene采用了基于倒排表的设计原理,可以非常高效地实现文本查找,在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。

核心模块

Lucene的写流程和读流程如图1所示。


1. Lucene读写流程图

其中,虚线箭头(A、B、C、D)表示写索引的主要过程,实线箭头(1-9)表示查询的主要过程。
Lucene中的主要模块(见图1)及模块说明如下。

  • analysis模块:主要负责词法分析及语言处理,也就是我们常说的分词,通过该模块可最终形成存储或者搜索的最小单元Term。
  • index模块:主要负责索引的创建工作。
  • store模块:主要负责索引的读写,主要是对文件的一些操作,其主要目的是抽象出和平台文件系统无关的存储。
  • queryParser:主要负责语法分析,把我们的查询语句生成Lucene底层可以识别的条件。
  • search模块:主要负责对索引的搜索工作。
  • similarity模块:主要负责相关性打分和排序的实现。

核心术语

下面介绍Lucene中的核心术语。

  • Term:是索引里最小的存储和查询单元,对于英文来说一般指一个单词,对于中文来说一般指一个分词后的词。
  • 词典(Term Dictionary,也叫作字典):是Term的集合。词典的数据结构可以有很多种,每种都有自己的优缺点,比如:排序数组通过二分查找来检索数据;HashMap(哈希表)比排序数组的检索速度更快,但是会浪费存储空间;fst(finite-state transducer)有更高的数据压缩率和查询效率,因为词典是常驻内存的,而fst有很好的压缩率,所以fst在Lucene的新版本中有非常多的使用场景,也是默认的词典数据结构。
  • 倒排表(Posting List):一篇文章通常由多个词组成,倒排表记录的是某个词在哪些文章中出现过。
  • 正向信息:原始的文档信息,可以用来做排序、聚合、展示等。
  • 段(segment):索引中最小的独立存储单元。一个索引文件由一个或者多个段组成。在Lucene中的段有不变性,也就是说段一旦生成,在其上只能有读操作,不能有写操作。

Lucene的底层存储格式如图2所示。图2由词典和倒排表两部分组成,其中的词典就是Term的集合。词典中的Term指向的文档链表的集合,叫作倒排表。词典和倒排表是Lucene中很重要的两种数据结构,是实现快速检索的重要基石。词典和倒排表是分两部分存储的,在倒排表中不但存储了文档编号,还存储了词频等信息。

2.词典和倒排表

在图2所示的词典部分包含三个词条(Term):elasticsearch、lucene和solr。词典数据是查询的入口,所以这部分数据是以fst的形式存储在内存中的。
在倒排表中,“lucene”指向有序链表3,7,15,30,35,67,表示字符串“lucene”在文档编号为3、7、15、30、35、67的文章中出现过,elasticsearch和solr同理。

检索方式

在Lucene的查询过程中的主要检索方式有以下四种。

  1. 单个词查询
    指对一个Term进行查询。比如,若要查找包含字符串“lucene”的文档,则只需在词典中找到Term“lucene”,再获得在倒排表中对应的文档链表即可,如图3所示。


    3. 单个词查询
  2. AND
    指对多个集合求交集。比如,若要查找既包含字符串“lucene”又包含字符串“solr”的文档,则查找步骤如下。
  • 在词典中找到Term“lucene”,得到“lucene”对应的文档链表。
  • 在词典中找到Term“solr”,得到“solr”对应的文档链表。
  • 合并链表,对两个文档链表做交集运算,合并后的结果既包含“lucene”,也包含“solr”。如图4所示。


    4. AND查询
  1. OR
    指对多个集合求并集。比如,若要查找包含字符串“lucene”或者包含字符串“solr”的文档,则查找步骤如下。
  • 在词典中找到Term“lucene”,得到“lucene”对应的文档链表。
  • 在词典中找到Term“solr”,得到“solr”对应的文档链表。
  • 合并链表,对两个文档链表做并集运算,合并后的结果包含“lucene”或者包含“solr”,如图5所示。


    5. OR查询
  1. NOT
    指对多个集合求差集。比如,若要查找包含字符串“solr”但不包含字符串“lucene”的文档,则查找步骤如下。
  • 在词典中找到Term“lucene”,得到“lucene”对应的文档链表。
  • 在词典中找到Term“solr”,得到“solr”对应的文档链表。
  • 合并链表,对两个文档链表做差集运算,用包含“solr”的文档集减去包含“lucene”的文档集,运算后的结果就是包含“solr”但不包含“lucene”,如图6所示。


    6. NOT查询

通过上述四种查询方式,我们不难发现,由于Lucene是以倒排表的形式存储的,所以在Lucene的查找过程中只需在词典中找到这些Term,根据Term获得文档链表,然后根据具体的查询条件对链表进行交、并、差等操作,就可以准确地查到我们想要的结果,相对于在关系型数据库中的“like”查找要做全表扫描来说,这种思路是非常高效的。虽然在索引创建时要做很多工作,但这种一次生成、多次使用的思路也是非常高明的。

你可能感兴趣的:(Lucene初识)