赞
踩
我们在使用Elasticsearch的过程中,很多业务场景都会用到关联查询。而目前Elasticsearch支持的关联查询无非就是两种方式,一种使用嵌套(nested)和父子文档。本文主要来聊聊关于nested,Elasticsearch。
文章末尾会附上nested和父子文档的差别和使用场景。
如果大家有过一些Lucene基础的话,相信都会知道Lucene中是不支持像嵌套这种数据结构的,而Elasticsearch不过是在Lucene的基础之上,通过hack的方式做了一些修改来支持了嵌套结构,使搜索功能更佳强大,用起来更方便。那么Elasticsearch具体是如何实现的?
ElasticSearch的官方说法:
参考:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/nested.html
翻译过来大概有如下几点:
从官网的介绍中我们了解到,nested的存储是单独进行存储的,这其实也就解释了为什么我们明明写入了100条数据用CAT接口查看时数据条数时却显示要比100多很多的原因了。
那么为什么我们普通的检索并没有检索到nested文档的内容呢,Elasticsearch是如何把nested过滤掉的?
首先我们先看Elasticsearch是如何将nested进行分开存储的。
Elasticsearch有一个类org.elasticsearch.index.mapper.DocumentParser,是专门用来解析要索引的Document的。
源码如下:
我们进入nestedContext方法:
源码位置:
https://github.com/elastic/elasticsearch/blob/6a5bae184b80c8a0012158c217de340535e9f45c/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java
从源码中可以看出来,生成nested文档主要干了两件事:
看完了nested文档的生成我们知道了nested文档是和普通文档一样被储存的,但是对外确实隐藏的,我们来看看Elasticsearch是如何做到的。
源码如下:
大家看到这里应该清楚了,查询query的判断决定是否返回nested文档的依据是文档中是否包含_primary_term字段,由此可知,nested文档是不包含_primary_term字段的,而其他文档是包含这个字段的。
_primary_term:是一个整数,每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1。
我们下面来看_primary_term是如何添加到字段中的。
源码如下:
源码位置:https://github.com/elastic/elasticsearch/blob/3ac6d527a1386d19008cdd08cdbfef265da30f00/server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java
到这里相信大家都看清楚怎么回事了,那么有的同学就会说了,前面看到的type为“__”开头这个源码里没有处理逻辑呀。那是因为上面的源码是目前最新版本(7.x)的源码,大家都知道7.x版本开始已经不再需要type了。但是大家绝大多数使用的还是7.x以前的版本,笔者特意找了一下早期版本的源码,实现方式还是有些区别的。
源码如下:
/** * Creates a new non-nested docs query * @param indexVersionCreated the index version created since newer indices can identify a parent field more efficiently */ public static Query newNonNestedFilter(Version indexVersionCreated) { if (indexVersionCreated.onOrAfter(Version.V_6_1_0)) { // 6.1.0版本之后。 只保留有_primary_term这个元字段的query return new DocValuesFieldExistsQuery(SeqNoFieldMapper.PRIMARY_TERM_NAME); } else { // 6.1.0版本之前版本 return new BooleanQuery.Builder() .add(new MatchAllDocsQuery(), Occur.FILTER) //过滤掉nested query .add(newNestedFilter(), Occur.MUST_NOT) .build(); } } public static Query newNestedFilter() { // _type以“__”为前缀 return new PrefixQuery(new Term(TypeFieldMapper.NAME, new BytesRef("__"))); }
总结来说ElasticSearch对nested隐藏实现方式:
同时nested也有两个缺点:
主要区别:
使用场景:
更多文章关注公众号
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。