深入了解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可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
存储 NoSQL Java
Elasticsearch Nested 选型,先看这一篇!
1、关于Nested 问题 上次讲解了Elasticsearch 数据建模之后,很多同学反馈问题: Q1:用nested做嵌套文档,对嵌套文档的字段做查询,只要主文档下一个嵌套文档符合要求,就会把主文档以及下面的所有的嵌套文档都查出来,实际我只需要符合要求的嵌套文档。这个用nested可以做吗? Q2:请教个问题 这个nested 是只要用这个字段类型就影响性能还是说当只有用这个字段类型去筛选才影响性能? Q3:Elasticsearch Nested 取一条数据 怎么搞? Q4:nested聚合查询等,导致jvm内存剧增,出现长时间的full GC,如何破? 介于此,非常有必要将
2660 0
Elasticsearch Nested 选型,先看这一篇!
|
存储 JSON Ubuntu
Elasticsearch:理解 Percolator 数据类型及 Percolate 查询
Elasticsearch 是一款功能强大且功能丰富的搜索工具。本文将介绍一种小众的数据类型 Percolator ,同时介绍Percolate query的使用。 您需要基本了解 Elasticsearch,尤其是mapping和search。
6638 0
Elasticsearch:理解 Percolator 数据类型及 Percolate 查询
|
2月前
|
测试技术 定位技术 API
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
94611 140
|
8月前
|
存储 JSON 数据建模
Elasticsearch数据建模实战之基于nested object实现博客与评论嵌套关系
Elasticsearch数据建模实战之基于nested object实现博客与评论嵌套关系
|
10月前
|
存储 算法 定位技术
ElasticSearch 之 数据类型
ElasticSearch 之 数据类型
208 0
|
10月前
|
存储 搜索推荐 大数据
大数据数据存储的搜索引擎Elasticsearch的数据类型的复杂类型
在使用搜索引擎Elasticsearch存储大数据时,了解其数据类型是非常重要的。除了基础数据类型之外,Elasticsearch还支持多种复杂数据类型,这些数据类型通常用于存储结构化数据和关联数据。在本文中,我们将会介绍Elasticsearch的复杂数据类型。
65 0
|
10月前
|
存储 自然语言处理 搜索推荐
大数据数据存储的搜索引擎Elasticsearch的数据类型的基础类型
在使用搜索引擎Elasticsearch存储大数据时,了解其数据类型是非常重要的。Elasticsearch支持多种数据类型,包括基础类型和复合类型。在本文中,我们将会介绍Elasticsearch的基础数据类型。
97 0
|
11月前
|
数据建模
白话Elasticsearch59-数据建模实战_ Nested Aggregation/ Reverse nested Aggregation对嵌套的博客评论数据进行聚合分析
白话Elasticsearch59-数据建模实战_ Nested Aggregation/ Reverse nested Aggregation对嵌套的博客评论数据进行聚合分析
51 0
|
11月前
|
存储 JSON 数据建模
白话Elasticsearch58-数据建模实战_基于nested object实现博客与评论嵌套关系
白话Elasticsearch58-数据建模实战_基于nested object实现博客与评论嵌套关系
56 0
|
数据库 索引

热门文章

最新文章