基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB级、万亿条数据记录的检索工作,这里向大家分享下Lucene底层原理研究和一些优化经验。
  从两个方面介绍:
  1. Lucene简介和索引原理
  2. Lucene优化经验总结

  1. Lucene简介和索引原理
      该部分从三方面展开:Lucene简介、索引原理、Lucene索引实现。

1.1 Lucene简介

  Lucene最初由鼎鼎大名Doug Cutting开发,2000年开源,现在也是开源全文检索方案的不二选择,它的特点概述起来就是:全Java实现、开源、高性能、功能完整、易拓展,功能完整体现在对分词的支持、各种查询方式(前缀、模糊、正则等)、打分高亮、列式存储(DocValues)等等。
  而且Lucene虽已发展10余年,但仍保持着一个活跃的开发度,以适应着日益增长的数据分析需求,最新的6.0版本里引入block k-d trees,全面提升了数字类型和地理位置信息的检索性能,另基于Lucene的Solr和ElasticSearch分布式检索分析系统也发展地如火如荼,ElasticSearch也在我们项目中有所应用。
  Lucene整体使用如图所示:
lucene角色

  结合代码说明一下四个步骤:

IndexWriter iw=new IndexWriter();//创建IndexWriter 
 Document doc=new Document( new StringField(“name”, “Donald Trump”, Field.Store.YES)); //构建索引文档 
 iw.addDocument(doc); //做索引库 
 IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(index))); 
 IndexSearcher searcher = new IndexSearcher(reader); //打开索引 
 Query query = parser.parse(“name:trump”);//解析查询TopDocs results =searcher.search(query, 100);//检索并取回前100个文档号 
 for(ScoreDoc hit:results.hits) 
 { 
 Document doc=searcher .doc(hit.doc)//真正取文档 
 }


  使用起来很简单,但只有知道这背后的原理,才能更好地用好Lucene,后面将介绍通用检索原理和Lucene的实现细节。

1.2 索引原理

  全文检索技术由来已久,绝大多数都基于倒排索引来做,曾经也有过一些其他方案如文件指纹。倒排索引,顾名思义,它相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。

这里写图片描述

  其中词典结构尤为重要,有很多种词典结构,各有各的优缺点,最简单如排序数组,通过二分查找来检索数据,更快的有哈希表,磁盘查找有B树、B+树,但一个能支持TB级数据的倒排索引结构需要在时间和空间上有个平衡,下图列了一些常见词典的优缺点:
这里写图片描述

  其中可用的有:B+树、跳跃表、FST
  B+树:
              mysql的InnoDB B+数结构
这里写图片描述

理论基础:平衡多路查找树
优点:外存索引、可更新
缺点:空间大、速度不够快


  跳跃表:
这里写图片描述

优点:结构简单、跳跃间隔、级数可控,Lucene3.0之前使用的也是跳跃表结构,后换成了FST,但跳跃表在Lucene其他地方还有应用如倒排表合并和文档号索引。
缺点:模糊查询支持不好


  FST
  Lucene现在使用的索引结构
这里写图片描述

理论基础: 《Direct construction of minimal acyclic subsequential transducers》,通过输入有序字符串构建最小有向无环图。
优点:内存占用率低,压缩率一般在3倍~20倍之间、模糊查询支持好、查询快
缺点:结构复杂、输入要求有序、更新不易
Lucene里有个FST的实现,从对外接口上看,它跟Map结构很相似,有查找,有迭代:

String inputs={“abc”,”abd”,”acf”,”acg”}; //keys 
 long outputs={1,3,5,7}; //values 
 FST fst=new FST<>(); 
 for(int i=0;i