参考:
嵌套对象
实际上,在Elasticsearch中,因为创建丶删除丶修改丶是原子性的,所以可以保存与文档密切相关的实体。
例如,您可以将订单及其全部内容保存到文档中,也可以保存博客文章及其全部响应。 藉由传递comments阵列。
put/my _ index/blog post/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': '令人高兴的故事White ',
' comment ' : ' morelikethisplease ',
' age': 31,
' stars': 5、
' date': '2014-10-22 '
}
]
}
view代码
1依赖动态映射时,comments字段会自动创建为object字段。
搜索时不需要连接" join "博客的文章和响应,因为所有内容都位于同一文档中,从而提高搜索结果。
问题是,上述文档可能与搜索匹配,如下所示。
GET my_index/_search
{'query': {
' bool': {
' must': [
{'match': {
' comments.age': 31
}
(,
{'match': {
' comments.name': 'John Smith '
}
}
]
}
}
}
view代码
令人高兴的故事是31岁,不是28岁!
对象之间的配对的原因是结构优美的JSON文档在索引中扁平化为下面的键值格式,如对象数组中所述。
{'title': [ eggs,nest ],
' body': [ making,money,work,your ],
' tags': [ cash,shares ],
' comments.name': [心灵美丽的枫树,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代码
令人高兴的故事和31,以及John和2014-09-01的关联已经无可挽回地消失了。 使用object类型的字段保存一个对象很有用。 从搜索的角度来看,对对象数组进行排序不需要关联。
这是嵌套对象被设计和解决的问题。 藉由映射commments字段,nested类型而不是object类型,每个嵌套对象被索引为隐藏的拆分文档。 例如:
{1}
' comments.name': [ john,smith ],
' comments.comment': [ article,great ],
' comments.age': [ 28 ],
' comments.stars': [ 4 ],
' comments.date ' : [ 2014-09-01 ]
}
{2}
' comments.name': [心灵美丽的枫树,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> 根或是父文档
藉由分别索引每个嵌套对象,对象的栏位中保持了其关联。 我们的查询可以只在同一个嵌套对象都匹配时才回应。
不仅如此,因嵌套对象都被索引了,连接嵌套对象至根文档的查询速度非常快--几乎与查询单一文档一样快。
这些额外的嵌套对象被隐藏起来,我们无法直接访问他们。 为了要新增丶修改或移除一个嵌套对象,我们必须重新索引整个文档。 要牢记搜寻要求的结果并不是只有嵌套对象,而是整个文档。
示例
包含嵌套对象的文档创建
创建映射
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
批量插入数据
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
聚合分析
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
对于嵌套对象的过滤查询
GET devicelog_22/_search
{"query": {
"nested": {
"path": "Items",
"query": {
"bool": {
"must": [
{"term": {
"Items.dd": {
"value": "k3"
}
}}
]
}
}
}
}
}
View Code
java查询
@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