深入了解ElasticSearch的Nested数据类型

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: ElasticSearch中可以将数据以对象的方式存储并查询,但是ES底层的Lucene 没有内部对象的概念,因此如果通过默认的方式往ES中插入对象,ES会将对象层次结构扁平化为字段名称和值的简单列表。 比如下面这一段数据:

(一)ES如何存储对象


ElasticSearch中可以将数据以对象的方式存储并查询,但是ES底层的Lucene 没有内部对象的概念,因此如果通过默认的方式往ES中插入对象,ES会将对象层次结构扁平化为字段名称和值的简单列表。 比如下面这一段数据:

PUTmy_index/_doc/1{
"group" : "fans",
"user" : [ 
    {
"first" : "John",
"last" :  "Smith"    },
    {
"first" : "Alice",
"last" :  "White"    }
  ]
}

ES内部会将这份数据变成下面这个样子:

{
"group" :        "fans",
"user.first" : [ "alice", "john" ],
"user.last" :  [ "smith", "white" ]
}

缺失了first和last之间的关联性。比如这个时候想查询一个first为John,last为White的人,理论上是没有这个人的,但是实际上名为fans的这个组还是被查出来了。

GETmy_index/_search{
"query": {
"bool": {
"must": [
        { "match": { "user.first": "John" }},
        { "match": { "user.last":  "White" }}
      ]
    }
  }
}

从结果可以看到,两条数据都被查询出来了。


网络异常,图片无法展示
|


(二)Nested类型


这个时候就需要用到nested,nested类型是object数据类型的特殊版本,它允许对象数组以一种可以相互独立查询的方式进行索引。


在Nested内部,每个对象索引其实是一个单独的隐藏文档,这意味着每个嵌套对象都可以独立于其他对象进行查询。


使用Nested需要先创建索引,依旧通过上边的这个例子


DELETEmy_indexPUTmy_index{
"mappings": {
"properties": {
"user": {
"type": "nested"      }
    }
  }
}
PUTmy_index/_doc/1{
"group" : "fans",
"user" : [
    {
"first" : "John",
"last" :  "Smith",
"age" : "23"    },
    {
"first" : "Alice",
"last" :  "White",
"age":"24"    }
  ]
}

首先创建my_index索引,设置user的类型为nested,接着在查询时,需要通过es的nested查询语句查询,使用同样的方式查询first为John,last为White的用户,这次的结果是不存在。因为通过nested存储的对象是具有关联性的。

GETmy_index/_search{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
            { "match": { "user.first": "John" }},
            { "match": { "user.last":  "White" }} 
          ]
        }
      }
    }
  }
}

上边的DSL语句用Java API实现如下:

@TestpublicvoidtestNested() throwsException{
//自己封装的一个获取RestHighLevelClient的类RestHighLevelClientclient=ElasticSearchClient.getClient();
SearchRequestrequest=newSearchRequest("my_index");
SearchSourceBuildersearchSourceBuilder=newSearchSourceBuilder();
BoolQueryBuilderboolQueryBuilder=QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("user.first","John"));
boolQueryBuilder.must(QueryBuilders.matchQuery("user.last","White"));
searchSourceBuilder.query(QueryBuilders.nestedQuery("user",boolQueryBuilder, ScoreMode.None));
request.source(searchSourceBuilder);
SearchResponsesearch=client.search(request, RequestOptions.DEFAULT);
SearchHit[] hits=search.getHits().getHits();
for (inti=0; i<hits.length; i++) {
SearchHithit=hits[i];
System.out.println(hit.getSourceAsString());
    }
}

(三)使用nested进行聚合查询


除了使用nested进行普通查询外,nested也支持聚合查询,同样是上面的例子,现在做一个对年龄聚合的操作:

GETmy_index/_search{
"aggs": {
"nestedAgg": {
"nested": {
"path": "user"      },
"aggs": {
"ageAgg": {
"terms": {
"field": "user.age.keyword",
"size": 10          }
        }
      }
    }
  }
}

(五)nested中的inner_hits


查询nested对象时,只要查询条件符合这个nested对象里的某一个条件,整个nested对象都会被检索出来。比如上面这个例子中,我只想查询叫做John Smith的这个人,但是通过普通的query查询会把整条记录都查询出来,效果就是这样:如果只想要nested中里的一个对象,就可以使用inner_hits。使用比较简单,只需要在查询语句之后加上inner_hits即可。


"hits" : [
      {
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.3862942,
"_source" : {
"group" : "fans",
"user" : [
            {
"first" : "John",
"last" : "Smith",
"age" : "23"            },
            {
"first" : "Alice",
"last" : "White",
"age" : "24"            }
          ]
        }
      }
    ]

如果只想要nested中里的一个对象,就可以使用inner_hits。使用比较简单,只需要在查询语句之后加上inner_hits即可。

GETmy_index/_search{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
            { "match": { "user.first": "John" }},
            { "match": { "user.last":  "Smith" }} 
          ]
        }
      },
"inner_hits": {}
    }
  }
}

查询结果里就会多出来一块数据,里面就只会展示具体的nested对象:

"inner_hits" : {
"user" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"              },
"max_score" : 1.3862942,
"hits" : [
                {
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "user",
"offset" : 0                  },
"_score" : 1.3862942,
"_source" : {
"last" : "Smith",
"first" : "John",
"age" : "23"                  }
                }
              ]
            }
          }
        }

查询结果里就会多出来一块数据,里面就只会展示具体的nested对象:

"inner_hits" : {
"user" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"              },
"max_score" : 1.3862942,
"hits" : [
                {
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "user",
"offset" : 0                  },
"_score" : 1.3862942,
"_source" : {
"last" : "Smith",
"first" : "John",
"age" : "23"                  }
                }
              ]
            }
          }
        }

(六)nested的使用建议


nested可以很好地存储和查询对象类型数据,但是也不能滥用nested。每个nested对象都被索引为一个单独的文档,简单来讲就是如果一个索引里包含 100 个user对象,那么在实际底层将创建 101 个 Lucene 文档,是一个很大的消耗。


nested类型只应在特殊情况下使用,一个索引在创建的时候,nested类型的对象默认不能超过50个,可通过index.mapping.nested_fields.limit修改。


一个具体的文档中,nested类型中包含的嵌套对象的数量默认不能超过10000个,也就是说上面创建的user在一个文档里不能超过10000个,可通过index.mapping.nested_objects.limit修改。



相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
4月前
|
自然语言处理 关系型数据库 数据库
ElasticSearch 映射类型及数据类型区分
ElasticSearch 映射类型及数据类型区分
48 0
|
6月前
|
测试技术 定位技术 API
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
95065 140
|
6月前
|
搜索推荐 JavaScript Java
Elasticsearch 8.X 如何依据 Nested 嵌套类型的某个字段进行排序?
Elasticsearch 8.X 如何依据 Nested 嵌套类型的某个字段进行排序?
86 0
|
6月前
|
数据建模 索引
干货 | Elasticsearch Nested 数组大小求解,一网打尽!
干货 | Elasticsearch Nested 数组大小求解,一网打尽!
73 0
|
6月前
|
SQL JSON DataWorks
DataWorks产品使用合集之DataWorks 数据集成任务中,将数据同步到 Elasticsearch(ES)中,并指定 NESTED 字段中的 properties 类型如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
80 0
|
存储 JSON 数据建模
Elasticsearch数据建模实战之基于nested object实现博客与评论嵌套关系
Elasticsearch数据建模实战之基于nested object实现博客与评论嵌套关系
|
数据库 索引
|
存储 算法 定位技术
ElasticSearch 之 数据类型
ElasticSearch 之 数据类型
427 0
|
存储 搜索推荐 大数据
大数据数据存储的搜索引擎Elasticsearch的数据类型的复杂类型
在使用搜索引擎Elasticsearch存储大数据时,了解其数据类型是非常重要的。除了基础数据类型之外,Elasticsearch还支持多种复杂数据类型,这些数据类型通常用于存储结构化数据和关联数据。在本文中,我们将会介绍Elasticsearch的复杂数据类型。
93 0
|
存储 自然语言处理 搜索推荐
大数据数据存储的搜索引擎Elasticsearch的数据类型的基础类型
在使用搜索引擎Elasticsearch存储大数据时,了解其数据类型是非常重要的。Elasticsearch支持多种数据类型,包括基础类型和复合类型。在本文中,我们将会介绍Elasticsearch的基础数据类型。
167 0