全文索引:Apache Lucene(二)

  上一章我们讲述了Apache Lucene实现的核心代码,今天我们来梳理一下Lucene的相关概念以及Lucene索引。

  工欲善其事,必先利其器。Java常用的全文搜索引擎框架,通常是下面4个框架:

 

   为什么是Lucene呢?原因很简单,hibernate search、solr、elasticsearch 都是基于 lucene 拓展出来的搜索引擎。 

  Hibernate Search 是在 apache Lucene 的基础上建立的主要用于 Hibernate 的持久化模型的全文检索工具。

  Elasticsearch 也使用 Java 开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。

  Solr 它是一种开放源码的、基于 Lucene Java 的搜索服务器,易于加入到 Web 应用程序中。提供了层面搜索(就是统计)、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 等格式)。

相关概念

  既然是全文搜索工具,肯定有一定的排序结构和规则。当我们输入关键字的时候,lucene 能安装内部的层次结构快速检索出我需要的内容。这里面会涉及几个层次和概念。

  索引库(Index)

  一个目录一个索引库,同一文件夹中的所有的文件构成一个 Lucene 索引库。类似数据库的表的概念。

  

  段(Segment)

  Lucene 索引可能由多个子索引组成,这些子索引称为段。每一段都是完整独立的索引,能被搜索。

  文档(Document)

  一个索引可以包含多个段,段与段之间是独立的,添加新文档可以生成新的段,不同的段可以合并。段是索引数据存储的单元。类似数据库内的行或者文档数据库内的文档的概念。

  域(Field)

  一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等。类似于数据库表中的字段

  词(Term)

  词是索引的最小单位,是经过词法分析和语言处理后的字符串。一个Field由一个或多个Term组成。比如标题内容是“hello lucene”,经过分词之后就是“hello”,“lucene”,这两个单词就是Term的内容信息,当关键字搜索“hello”或者“lucene”的时候这个标题就会被搜索出来。

  分词器(Analyzer)

  一段有意义的文字需要通过Analyzer来分割成一个个词语后才能按关键词搜索。StandartdAnalyzer是Lucene中常用的分析器,中文分词有CJKAnalyzer、SmartChinieseAnalyzer等。

   

  上图大概可以这样理解,索引内部由多个段组成,当新文档添加进来时候会生成新的段,不同的段之间可以合并(Segment-0、Segment-1、Segment-2合并成Segment-4),段内含有文档号与文档的索引信息。而每个文档内有多个域可以进行索引,每个域可以指定不同类型(StringField,TextField)。

  所以,从图中可以看出,lucene的层次结构依次如下:索引(Index) –> 段(segment) –> 文档(Document) –> 域(Field) –> 词(Term)

  在上面我们了解了 lucene 的一些基本概念,接下来我们进入原理分析的环节。

  (为什么 lucene 搜索引擎查询这么快?)

倒排索引

  我们都知道要想提高检索速度要建立索引,重点就在这里,lucene使用了倒排索引(也叫反向索引)的结构。

  倒排索引(反向索引)自然就有正排索引(正向索引)。

  • 正排索引是指从文档检索出单词,正常查询的话我们都是从文档里面去检索有没这个关键字单词。

  • 倒排索引是指从单词检索出文档,与从正排索引是倒过来的概念,需要预先为文档准备关键字,然后查询时候直接匹配关键字得到对应的文档。

  有一句这样的总结:由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)

  

 

 

  假如现在有两个文档,内容分别是:

  • 文档1:home sales rise in July.

  • 文档2:increase in home sales in July.

  分析上图可知,首先文档经过分词器(Analyzer)分词之后,我们可以得到词(term),词和文档ID是对应起来的,接下来这些词集进行一次排序,然后合并相同的词并统计出现频率,以及记录出现的文档ID。

所以:

  实现时,lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。

  索引时,假设要查询单词 “sales”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。

构建索引与查询索引过程

  

  检索文件之前先要建立索引,所以上图得从“待检索文件”节点开始看。

  构建索引过程:

    1、为每一个待检索的文件构建Document类对象,将文件中各部分内容作为Field类对象。

    2、使用Analyzer类实现对文档中的自然语言文本进行分词处理,并使用IndexWriter类构建索引。

    3、使用FSDirectory类设定索引存储的方式和位置,实现索引的存储。

  检索索引过程:

    4、使用IndexReader类读取索引。

    5、使用Term类表示用户所查找的关键字以及关键字所在的字段,使用QueryParser类表示用户的查询条件。

    6、使用IndexSearcher类检索索引,返回符合查询条件的Document类对象

  其中虚线指向的是这个类所在的包名(packege)。如Analyzer在org.apache.lucene.analysis包下。

 

总结

  倒排序索引的原理就如同查字典。要先查目录,得到数据对应的页码,在直接翻到指定的页码。不是在文章中找词,而是从目录中找词所在的文章。

 

 

  参考链接

posted @ 2023-04-10 11:11  Nausicaä  阅读(131)  评论(0编辑  收藏  举报