java+es+nested_Elasticsearch嵌套式对象Nested

本文详细介绍了Elasticsearch中如何使用nested类型处理嵌套对象,包括创建映射、批量插入数据、聚合分析以及Java查询。通过nested类型,可以保持对象间的关联,解决搜寻时的误匹配问题,提高查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:

嵌套对象

事实上在Elasticsearch中,创建丶删除丶修改一个文档是是原子性的,因此我们可以在一个文档中储存密切关联的实体。

举例来说,我们可以在一个文档中储存一笔订单及其所有内容,或是储存一个Blog文章及其所有回应,藉由传递一个comments阵列:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

PUT /my_index/blogpost/1{"title": "Nest eggs",

"body": "Making your money work...",

"tags": [

"cash",

"shares"

],"comments": [

{"name": "John Smith",

"comment": "Great article",

"age": 28,

"stars": 4,

"date": "2014-09-01"

},

{"name": "Alice White",

"comment": "More like this please",

"age": 31,

"stars": 5,

"date": "2014-10-22"

}

]

}

View Code

<1> 如果我们依靠动态映射,comments栏位会被自动建立为一个object栏位。

因为所有内容都在同一个文档中,使搜寻时并不需要连接(join)blog文章与回应,因此搜寻表现更加优异。

问题在於以上的文档可能会如下所示的匹配一个搜寻:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

GET my_index/_search

{"query": {

"bool": {

"must": [

{"match": {

"comments.age": 31

}

},

{"match": {

"comments.name": "John Smith"

}

}

]

}

}

}

View Code

Alice是31岁,而不是28岁!

造成跨对象配对的原因如同我们在对象阵列中所讨论到,在于我们优美结构的JSON文档在索引中被扁平化为下方的 键-值 形式:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

{"title": [ eggs, nest ],

"body": [ making, money, work, your ],

"tags": [ cash, shares ],

"comments.name": [ alice, john, smith, white ],

"comments.comment": [ article, great, like, more, please, this ],

"comments.age": [ 28, 31 ],

"comments.stars": [ 4, 5 ],

"comments.date": [ 2014-09-01, 2014-10-22 ]

}

View Code

Alice与31 以及 John与2014-09-01 之间的关联已经无法挽回的消失了。 当object类型的栏位用于储存单一对象是非常有用的。 从搜寻的角度来看,对於排序一个对象阵列来说关联是不需要的东西。

这是嵌套对象被设计来解决的问题。 藉由映射commments栏位为nested类型而不是object类型, 每个嵌套对象会被索引为一个隐藏分割文档,例如:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

{ <1>

"comments.name": [ john, smith ],

"comments.comment": [ article, great ],

"comments.age": [ 28 ],

"comments.stars": [ 4 ],

"comments.date": [ 2014-09-01 ]

}

{<2>

"comments.name": [ alice, white ],

"comments.comment": [ like, more, please, this ],

"comments.age": [ 31 ],

"comments.stars": [ 5 ],

"comments.date": [ 2014-10-22 ]

}

{<3>

"title": [ eggs, nest ],

"body": [ making, money, work, your ],

"tags": [ cash, shares ]

}

View Code

<1> 第一个嵌套对象

<2> 第二个嵌套对象

<3> 根或是父文档

藉由分别索引每个嵌套对象,对象的栏位中保持了其关联。 我们的查询可以只在同一个嵌套对象都匹配时才回应。

不仅如此,因嵌套对象都被索引了,连接嵌套对象至根文档的查询速度非常快--几乎与查询单一文档一样快。

这些额外的嵌套对象被隐藏起来,我们无法直接访问他们。 为了要新增丶修改或移除一个嵌套对象,我们必须重新索引整个文档。 要牢记搜寻要求的结果并不是只有嵌套对象,而是整个文档。

示例

包含嵌套对象的文档创建

创建映射

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

PUTdevicelog_22

{"mappings" : {

"log" : {

"properties" : {

"Items" : {

"type":"nested",

"properties" : {

"name" : {

"type" : "text",

"fields" : {

"keyword" : {

"type" : "keyword",

"ignore_above" : 256

}

}

},"unit" : {

"type" : "text",

"fields" : {

"keyword" : {

"type" : "keyword",

"ignore_above" : 256

}

}

},"value" : {

"type" : "double"

}

}

},"OperationDateTime" : {

"type" : "date",

"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis",

"ignore_malformed":false

},"systemId" : {

"type" : "text",

"fields" : {

"keyword" : {

"type" : "keyword",

"ignore_above" : 256

}

}

}

}

}

}

}

View Code

批量插入数据

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

POST /devicelog_22/log/_bulk

{"index":{"_id":1}}

{"systemId":"001","OperationDateTime":"2020-03-02 10:34:03","Items":[{"name":"k1","value": 11},{"name":"k2","value": 12},{"dd":"k3","value":33}]}

{"index":{"_id":2}}

{"systemId":"001","OperationDateTime":"2020-03-02 11:34:03","Items":[{"name":"k1","value": 22},{"name":"k2","value": 33},{"dd":"k3","value":44}]}

{"index":{"_id":3}}

{"systemId":"001","OperationDateTime":"2020-03-02 16:34:03","Items":[{"name":"k1","value": 45.3},{"name":"k2","value": 89.333},{"dd":"k3","value":18.33}]}

{"index":{"_id":4}}

{"systemId":"001","OperationDateTime":"2020-03-03 15:34:03","Items":[{"name":"k1","value": 45.3},{"name":"k2","value": 89.333},{"dd":"k3","value":18.33}]}

{"index":{"_id":5}}

{"systemId":"001","OperationDateTime":"2020-03-03 18:34:03","Items":[{"name":"k1","value": 222.3},{"name":"k2","value": 33.333},{"dd":"k3","value":55.33}]}

View Code

聚合分析

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

GET devicelog_22/_search

{"query": {

"match_all": {}

},"aggs": {

"item.name": {

"nested": {

"path": "Items"

},"aggs": {

"terms": {

"terms": {

"field": "Items.name.keyword",

"size": 10

},"aggs": {

"sum-aggs": {

"sum": {

"field": "Items.value"

}

}

}

}

}

}

}

}

View Code

对于嵌套对象的过滤查询

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

GET devicelog_22/_search

{"query": {

"nested": {

"path": "Items",

"query": {

"bool": {

"must": [

{"term": {

"Items.dd": {

"value": "k3"

}

}}

]

}

}

}

}

}

View Code

java查询

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Test

public void test2(){

try {

SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();

QueryBuilder queryBuilderHave=QueryBuilders.termQuery("Items.name","k1");

NestedQueryBuilder nestedQueryBuilder=QueryBuilders.nestedQuery("Items",queryBuilderHave, ScoreMode.None);

QueryBuilder queryBuilder=QueryBuilders.boolQuery().must(nestedQueryBuilder);

TopHitsAggregationBuilder aggregation1= AggregationBuilders.topHits("details").size(1).

sort(SortBuilders.fieldSort("OperationDateTime").order(SortOrder.DESC)).fetchSource(true);

DateHistogramAggregationBuilder aggregation= AggregationBuilders.dateHistogram("agg").

keyed(true).format("yyyy-MM-dd").field("OperationDateTime").dateHistogramInterval(DateHistogramInterval.DAY).

timeZone(DateTimeZone.forOffsetHours(8)).subAggregation(aggregation1);

searchSourceBuilder.size(0).fetchSource(false).

timeout(new TimeValue(1000, TimeUnit.SECONDS)).query(queryBuilder).aggregation(aggregation);

SearchRequest searchRequest=new SearchRequest();

searchRequest.source(searchSourceBuilder);

SearchResponse searchResponse=client.search(searchRequest, RequestOptions.DEFAULT);

if(searchResponse.status()==RestStatus.OK){

Histogram histogram= searchResponse.getAggregations().get("agg");

EsDocumentList esDocumentList=new EsDocumentList();

for (Histogram.Bucket entry : histogram.getBuckets()){

TopHits topHits=entry.getAggregations().get("details");

for (SearchHit hit : topHits.getHits().getHits()) {

Map mapResult =hit.getSourceAsMap();

esDocumentList.add(mapResult);

}

}

System.out.println("11");

}

}catch (Exception ex){

System.out.println(ex);

}

View Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值