Lucene系列:番外篇-DocValues

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/itsoftchenfei/article/details/87948657

玩ElasticSearch或Solr的童鞋,对于DocValues这个词,时常出现高阶应用开发者的口中。它像一个熟悉的陌生人一样,很多人对于实现排序,分组和一些聚合类操作的需求信手拈来,但对它底层原理却了解不多。

DocValues在LUCENE-3518才引入新特征,初生在Lucene4.0,由Mike(Michael McCandless)提出的。从此Lucene牛逼轰轰了。

1. 为什么要用DocValues ? 

假如我们需要对一些数据做一些聚合操作,比如排序,分组该如何实现呢?

基于lucene的solr和es都是使用经典的倒排索引模式来达到快速检索的目的,简单的说就是建立 搜索词=》 文档id列表 这样的关系映射, 然后在搜索时,通过类似hash算法,来快速定位到一个搜索关键词,然后读取其的文档id集合,这就是倒排索引的核心思想,这样搜索数据是非常高效快速的。当然它也是有缺陷的,要实现上面的需求,lucene内部会遍历提取所有出现在文档集合 
的排序字段然后再次构建一个最终的排好序的文档集合list,这个步骤的过程全部维持在内存中操作,而且如果排序数据量巨大的话,非常容易就造成ES内存溢出和性能缓慢。 

基于这个原因,在lucene4.x之后出现了docvalue这个新特性,在构建索引时会对开启docvalues的字段,在构建索引时会对开启docvalues的字段,额外构建一个已经排好序的文档到字段级别的一个列式存储映射。它带来的好处是:

  • 节省内存 
  • 对排序,分组和一些聚合操作时能够大大提升性能 

2. 什么时候用DocValues? 

通过上面的剖析,总结起来主要以下几个方面: 

  • 需要聚合的字段,包括sort,agg,group,facet等 
  • 需要提供函数查询的字段
  • 需要高亮的字段,这个确实能加速,但是散仙并不建议把高亮放在服务端程序做
  • 需要参与自定义评分的字段,这个稍复杂,大多数人的场景中,不一定能用到

3. DocValues存储结构

DocValues字段是一个面向列存储的字段,所谓面向列存储,相信大家都不会陌生了,市场上也有好多成熟的列存储框架诸如:Parquet、ORC等。

  • 一个Segment只有一个DocValues
  • 被DocValues标记的字段在建索引时会额外存储文件到值的映射关系
  • 一个DocValues会生成两个文件(dvd,dvm)。dvd,存储这个映射的文件叫DocValues data。dvm,对应的元数据文件叫DocValues Metadata,这里metadata相当于Index文件,用来存储数据的索引,也就是存储数据文件每条记录起始位置以及记录的长度,同时存储数据文件的数据格式等信息(即是元信息)
  • 所有Doc Values存于内存中(堆外内存),这样就可以有超快的访问速度

Doc values通过逆置term和doc间的关系来前面提到的数据聚合的问题。当数据被逆置之后,想要收集到 Doc_1 和 Doc_2 的唯一 token 会非常容易。获得每个文档行,获取所有的词项,然后求两个集合的并集。

Doc      Terms
-----------------------------------------------------------------
Doc_1 | brown, dog, fox, jumped, lazy, over, quick, the
Doc_2 | brown, dogs, foxes, in, lazy, leap, over, quick, summer
Doc_3 | dog, dogs, fox, jumped, over, quick, the
-----------------------------------------------------------------

它也不是实时(同index一样),Writer只负责把DocValues字段按对应DocValues类型写入到内存上,最后在Segment refresh的时候,由Consumer把Writer的内容写入磁盘。

4. DocValues的种类

Lucene提供这五种类型的Writer(DocValues类型),它适配情况是这样的

NONE   不开启docvalue时的状态 
Numeric NumericDocValuesWriter 对于一般的integer/long/float/double/date
Binary BinayDocValuesWriter 对应BinaryField,并且它会被转成byte[]进行存储
Sorted SortedDocValuesWriter 对应String
Sorted Set SortedSetDocValuesWriter 对应StrField字段,但仅限于multiValue="true"的情况
Sorted Number SortedNumericDocValuesWriter 对应所有Trie*Field,包括TrieIntField和TrieDateField

注意:analyzed String字段存储docvalue是没有意义的(因为分词后会生成很多token使得Doc Values效率降低)因此docValues不支持TextField类型

5. docValuesFormat

docValues提供了四种Format,你可能会认为MemoryDocValuesFormat只会存储在内存,而不存储在磁盘,其实真不是这样的。不管是DirectDocValuesFormat还是MemoryDocValuesFormat都会存盘,后缀名分别为.dvdd.dvdm以及.mdvd.mdvm

  • Lucene54DocValuesFormat,默认的Format,存储在磁盘。跟FieldCache比较像,需要时如果没有就去磁盘里读取,不用时也能释放
  • MemoryDocValuesFormat,它绝对不是如名那些In-Memory,它其实还比较复杂。应该说,它允许你只读一定大小的DocValues驻在内存。同时它支持以FST的格式存储。
  • DirectDocValuesFormat,这个关系是Direct,直接。直接存储到磁盘;直接读取出来放在内存。以一个非常简单的结构存储在内存中——数组。它跟MemoryDocValuesFormat最大的一样就是它支持1或0,要么都存;要么都不存
  • SimpleText,Lucene4.0的试验产品

6. 如何使用

//数值存储例子  
FieldType num=new FieldType();  
num.setStored(true);//设置存储  
num.setIndexOptions(IndexOptions.DOCS);//设置索引类型  
num.setNumericType(NumericType.DOUBLE);//数值类型  
num.setDocValuesType(DocValuesType.NUMERIC);//DocValue类型  
Document doc=new Document();  
//添加string字段  
doc.add(new SortedDocValuesField("id",new BytesRef("01011")));  
//添加数值类型的字段  Float,Doule需要额外转成bit位才能存储,Interger和Long则不需要  
doc.add(new DoubleField("price", Double.doubleToRawLongBits(25.258), num)); 

//读取索引文件  
DirectoryReader reader=DirectoryReader.open(FSDirectory.open(Paths.get(indexDir)));  
//如果有多个段需要merge成一个,获取第一个进行测试,本例中仅仅就有一个段  
SortedDocValues str = DocValues.getSorted(reader.leaves().get(0).reader(), "id");  
//数值类型  
NumericDocValues db = DocValues.getNumeric(reader.leaves().get(0).reader(), "price");  
//读取字符串类型的ByteRef然后打印其内容  
System.out.println("id:"+str.get(0).utf8ToString());  
//注意此处,要与类型对应,如果是Float,则需要Float.intBitsToFloat((int)db.get(0))进行位数还原  
System.out.println("price: "+Double.longBitsToDouble(db.get(0)));  
reader.close(); 

在Solr中docvalue默认是全部关闭,比较严谨,大家可酌情开启。在ElasticSearch中,默认docvalue全部激活,比较简单暴力,大家可酌情关闭一些不需要使用docvalue的字段,以节省磁盘空间 。

猜你喜欢

转载自blog.csdn.net/itsoftchenfei/article/details/87948657
今日推荐