一文了解Lucene创建索引原理

背景

全文搜索技术的发展,经历了以下五个阶段的发展,由最初的Ftp文件检索阶段,到现在的网页链接分析阶段以及用户意图识别阶段,已经发展到比较成熟的地步了。

全文搜索的发展历程.png

如上图可知,五个阶段的发展顺序,以下简要对每个阶段进行说明:

  1. FTP文件检索阶段:将文件存储到FTP服务器中,用户输入精确的文件名去搜索文件,可以得到文件的FTP地址,用户再根据此地址进行文件下载。

  2. 分类目录导航阶段:将网页分类目保存并展示给用户,用户可以根据所需到具体分类下获取网页的URL,随后根据URL重定向。

  3. 文件相关性阶段:随着互联网内容的不断丰富,单纯依靠分类来定位一个网页,显得不再那么准确了。为了解决这个问题,搜索引擎引入了全文搜索技术,以此来保证搜索的主题与网页内容具有强相关性。

  4. 网页链接分析阶段:此阶段主要是利用了外部链接来统计每个网站的重要性和流行性,在用户进行搜索性,结合网站的重要性和流行性进行数据过滤,以此改善搜索信息的质量。

  5. 用户意图识别阶段:此阶段主要是以用户为中心,力求根据最短的搜索关键字,返回与用户搜索意图最匹配的网页内容,做到千人千面。

其中,网页链接分析阶段的代表作就是谷歌搜索了,而用户意图搜索阶段的代表作就是百度搜索了。但此类的搜索都是属于站外搜索。除了站外搜索,还有站内搜索,比如一些管理后台的全文搜索、电商内的商品搜索等。

现在成熟的全文搜索引擎ElasticSearch、Solr都是基于Lucene搜索引擎的进一步封装,对于了解Lucene的基本原理也是很重要的。

基础使用

创建索引

创建索引需要进行以下操作:

  • 创建索引目录:用于存放创建后的索引文件。
  • 使用分词器:对内容进行分词处理。
  • 创建IndexWriter: 用于索引的创建。
  • 创建Document: 使用Document来保存需要添加到索引中的内容。

demo代码如下:

class LuceneServiceImplTest {

    @Test
    void createIndex() throws IOException {

        final String indexPath = "lucene/indexDir/";

        //创建索引目录
        Path path = Paths.get(indexPath);
        File file = path.toFile();
        if (!file.exists()) {
            //如果文件夹不存在,则创建
            file.mkdirs();
        }
        FSDirectory directory = FSDirectory.open(path);

        //使用标准分词器
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();

        //创建indexWriter
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(standardAnalyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        //创建document
        Document document = new Document();
        //document添加域
        document.add(new TextField("goodsName", "goods", Field.Store.YES));
        document.add(new TextField("goodsPrice", "100", Field.Store.YES));

        //创建索引
        indexWriter.addDocuments(Collections.singletonList(document));
        //提交
        indexWriter.commit();
    }
}
复制代码

以上代码的作用,就是将goodsName以及goodsPrice作为document的两个Field, 并添加进索引中。运行以上结果,可以从lucene/indexDir目录下有以下文件:
image.png

基础概念

在了解Lucene原理前,我们需要对以下概念进行了解。

  • Document: 类似数据库内的行或者文档数据库内的文档的概念,一个Index内会包含多个Document。写入Index的Document会被分配一个唯一的ID,即Sequence Number(更多被叫做DocId)。
  • Field: 一个Document会由一个或多个Field组成(如下图,从源码可以看出它们之间的关系),Field是Lucene中数据索引的最小定义单位。Lucene提供多种不同类型的Field,例如StringField、TextField、LongFiled。

image.png

  • Term:Lucene中索引和搜索的最小单位,一个Field会由一个或多个Term组成,Term是由Field经过Analyzer(分词)产生。
  • Term Dictionary:Term词典,是根据条件查找Term的基本索引。
  • Segment:用段来对索引进行拆分,可以拆分为多个段,段之间也可以合并,以此来避免索引文件膨胀。

根据以上概念,我们整理它们之间的关系图:

Lucene关系图.png

创建索引原理

在开始了解创建索引流程前,我们先来看下整体流程:

创建索引流程泳道图.png
Lucenef负责的模块图:

1532239078.png

由以上两图可以得知,Lucene不负责帮我们创建Docuemnt以及Field, 它仅仅提供了相关功能的,我们还是需要自己去读取文档的内容、创建Document以及Field。
由以上流程图,我们可以看出来,Lucene会使用分词器对文档Field进行相关的分词处理,直到输出Term。以下对分词处理的几个重要的阶段进行说明,如下:

  1. 去除停词:停词(Stop word)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。英语中停词(Stop word)如:“the”,“a”,“this”等。
  2. 将单词缩减为词根形式:如“cars ”到“car ”等。
  3. 将单词转变为词根形式:如“drove ”到“drive ”等。

分词后,得到Term,下一步就是提交给索引组件,索引组件负责创建到排索引来存储Term。其中,Lucene利用了FST数据结构来保存词典,利用跳表来存储倒排表,关系图如下:

image.png

最后

关于Lucene是如何保证线程安全的,将会在下一篇进行说明。

参考资料

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享