TOC
fielddata vs. doc_values
ES提供了这两个作用非常相似的mapping属性,通过相关官方文档(fielddata、doc_values)的介绍,已知这两个属性均用于字段的排序、聚合、字段运算操作。不同于根据关键字(Term)搜索文档,这些操作需要不同的数据获取模式(data access pattern):
- Term搜索:采用倒排表结构,需要回答
给定的Term在哪些文档中存在
- 排序/聚合/字段运算:行存或列存均可实现,需要遍历所有文档并返回他们字段的值或是关键字(Term)
_source 和 doc_value
_source
字段默认开启,以类似行存(一个完整的json文档)的方式保存文档内的所有字段。理论上解析json得到目标字段后也可以进行排序/聚合/字段运算等操作,但是在ES中并不支持。通过
doc_value
的列存结构可以让上述操作效率更高。
Doc values是lucene4.0引入的列存结构,在文档索引的时候写入磁盘中的特定文件(.dvd、.dvm),支持几乎所有的字段类型,除了analyzed string
。
不同与Doc values把列存结构持久化到磁盘文件,fielddata
是基于内存的结构。只有当一个fileddata字段进行聚合/排序/字段计算操作时,系统会通过倒排结构先找到目标文档,取出目标字段放在JVM堆内存中进行运算。fielddata方案存在几个明显的问题:
- 堆内存占用明显,尤其是text基数庞大时,且文档有提:
Once fielddata has been loaded into the heap, it remains there for the lifetime of the segment.
使得几乎不可用。 - 从倒排结构加载fielddata性能低,延迟高。
故此,在所有text字段中默认fielddata
为false,而doc_value
因为几乎没啥副作用(除非预期不会做排序/聚合操作,浪费磁盘)在非text字段中,默认为true。
sorting/aggregate/script Text?
通过上述分析可以知道,要对text字段(analyzed=true)进行排序/聚合/字段计算,doc_value不支持,fielddata也存在明显的问题。这或许不是ES/lucene的缺陷,而是需求上,就不应该对text类型做这些操作。长字符串甚至是完整文档的排序/聚合一般的场景并无意义(对唐诗三百首进行排序的操作,不会基于全文进行,而是会抽取标题/字数/作者名称来做);字段计算则应该在索引创建前做好,或者利用ES的pipeline来实现。