1.1 正排索引
从广义来说,doc values 本质上是一个序列化的 列式存储 。列式存储 适用于聚合、排序、脚本等操作,所有的数字、地理坐标、日期、IP 和不分词( not_analyzed )字符类型都会默认开启,不支持text
和annotated_text
类型
1.2 倒排&正排
倒排:即词项
=>包含当前词项的doc_id的列表
的映射。倒排索引的优势是可以快速查找包含某个词项的文档有哪些。如果用倒排来确定哪些文档中是否包含某个词项就很鸡肋。正排:即doc_id
=>当前文档包含的所有词项
的映射。正排索引的优势在于可以快速地查找某个文档里包含哪些词项。同理,正排不适用于查找包含某个词项的文档有哪些。
2、一张图看懂正排&倒排
2.1 图解

2.2 区别
倒排索引的优势 在于查找包含某个项的文档,即用于搜索查询;相反,正排索引的优势是确定哪些项是否存在单个文档里。
倒排索引和正排索引均是在 index-time 时创建,保存在 Lucene 文件中(序列化到磁盘)。
doc value 使用非 jvm 内存,gc友好。
不分词的 field 会在 index-time 时生成正排索引,聚合时直接使用正排索引,而分词的field在创建索引时是没有正排索引的,如果没有创建 doc value 的字段需要做聚合查询,name需要将 fielddata 打开,设置为 true。
3、一个通俗易懂的比喻
举个通俗易懂的例子
有二十个学生报名学习辅导班,每个学生可以报多个班 每个班都有一个班主任
正排索引
:相当于班主任,也就是 班主任知道TA所在班级有多少学生
倒排索引
:相当于学生,每个学生知道自己都报了哪些班

现在我们要查询音乐辅导班 和 美术辅导班都包含了哪些学生,问班主任问两次就行,如果我们问学生,就要每个学生都问一遍,问他你是否报了音乐和美术辅导班,如果你不问到最后一个学生,你永远不知道你没有问到的学生 是不是在音乐班和美术班里,也就没办法统计音乐或者美术班的总人数,所以必须问完每个学生,相当于全表扫描。这就是为什么倒排不适合做聚合。
在这个例子里,班主任相当于正排索引,每个doc就是一个班级,每个doc中包含若干词项,每个词项就好比是一个学生。班主任知道每个班级有哪些学生 也就是每个doc包含哪些词项。学生只知道自己属于哪些班,相当于哪些班级(doc)包含了这个词项。
4、正排索引的数据结构
4.1 doc values
doc values 是正排索引的基本数据结构之一,其存在是为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc values值以节省磁盘空间。
4.2 fielddata:
概念:查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建倒排索引保存到堆中。与 doc value 不同,当没有doc value的字段需要聚合时,需要打开fielddata,然后临时在内存中建立正排索引,fielddata 的构建和管理发生在 JVM Heap中。Fielddata默认是不启用的,因为text字段比较长,一般只做关键字分词和搜索,很少拿它来进行全文匹配和聚合还有排序。
语法:
PUT <index>/_mapping{"properties": {"tags": {"type": "text","fielddata": true /true:开启fielddata; false:关闭fielddata}}}
独家深层解读: doc values 是文档到词项的映射 inverted 是词项到文档id的映射从原理上讲 先说倒排索引为什么不适合聚合,你无法通过倒排索引确定doc的总数量,并且因为倒排索引默认会执行analysis,即使聚合,结果也可能不准确,所以你还要创建not_analyzed字段,徒增磁盘占用,举个最简单的例子:假如有一张商品表,每个商品都有若干标签,我们执行了以下查询
GET product/_search{"query": {"match": {"tags": "性价比"}},"aggs": {"tag_terms": {"terms": {"field": "tags.keyword"}}}}
这段聚合查询的意思 查询包含“性价比”这个标签商品的所有标签,在执行agg的时候 我们使用倒排索引,那么语义将是这样的:在倒排索引中扫描逐个 term,看看这个 term 对应的倒排表中对应的 doc 的标签是否包含“性价比”,如果包含,则记录,由于我们不确定下面一个term是否符合条件,所以我们就要一个一个的判断,所以就造成了扫表。如果使用正排索引,而正排索引的指的是,doc中包含了哪些词项,也就是当前doc_id=>当前字段所包含的所有词项的映射,我们要查找的是符合条件的doc中所有的标签,那么我们直接根据key(doc_id)去拿values(all terms)就可以了,所以就不用扫表。所以聚合查询使用正排索引效率高本质是两种数据结构的区别 和结不结合倒排索引没有关系,结合倒排索引只是预先进行了数据筛选。以上是正排索引在原理上对聚合查询友好的原因 下面我说一下关于两种数据结构在数据压缩上的不同,doc values是一种序列化的列式存储结构,其values其中也包含了词频数据。而这种结构是非常有利于数据压缩的,参考第二版VIP课程中的FOR和RBM压缩算法,因为Lucene底层读取文件的方式是基于mmap的,原理上是从磁盘读取到OS cache里面进行解码的,使用正排索引的数据结构,由于其列式存储的数据和posting list一样可以被高效压缩,所以这种方式极大的增加了从磁盘中读取的速度,因为体积小了,然后把数据在OS Cache中进行解码
5、总结
与 doc value 不同,当没有doc value的字段需要聚合时,需要打开 fielddata,然后临时在内存中建立正排索引,fielddata 的构建和管理发生在 JVM Heap中。
Fielddata 默认是不启用的,因为 text 字段比较长,一般只做关键字分词和搜索,很少拿它来进行全文匹配和聚合还有排序。
ES 采用了 Circuit Breaker(熔断)机制避免 field data 一次性超过物理内存大小而导致内存溢出,如果触发熔断,查询会被终止并返回异常。
fielddata 使用的是 jvm 内存,doc value 在内存不足时会静静的待在磁盘中,而当内存充足时,会蹦到内存里提升性能。
国内 Elastic认证工程师 破百的社区
扫码免费加入,精彩内容不错过


分享

收藏

点赞

在看




