Elastic search中使用nested类型的内嵌对象

在大数据的应用环境中,每每使用反范式设计来提升读写性能。
假设咱们有个相似简书的系统,系统里有文章,用户也能够对文章进行赞扬。在关系型数据库中,若是按照数据库范式设计,须要两张表:一张文章表和一张赞扬历史记录表,赞扬历史记录表包括了赞扬者姓名和赞扬金额。
在Elastic search中,因为都是json格式存储,则能够在一个index存储系统中的文章及其赞扬记录,这种状况下须要在elastic search中使用nested类型的内嵌对象。由于若是使用数组或者object对象的话,赞扬者姓名和赞扬金额是相互独立的进行存储,不能被正确的关联。html

创建index

PUT articles
{
  "mappings": { "doc": { "properties": { "payment": { "type": "nested", "properties": { "amount": { "type": "integer" }, "name": { "type": "keyword" } } } } } } } 

这样articles就有了payment这个nested类型的字段,payment里面的对象有amount和name,表示金额和姓名。数据库

产生数据

产生以下数据,表示jack给文章1赞扬了29元,ross给文章1赞扬30元,ross给文章2赞扬31元。json

POST articles/doc/1
{
  "payment": [ { "name": "jack", "amount": 29 }, { "name": "ross", "amount": 30 } ] } POST articles/doc/2 { "payment": [ { "name": "ross", "amount": 31 } ] } 

根据内嵌对象进行查询

如今想查询ross赞扬过的文章,须要使用nested query数组

GET articles/_search
{
  "query": { "nested": { "path": "payment", "query": { "term": { "payment.name": { "value": "ross" } } } } } } 

path表示了nested字段的名称,须要注意的是,查询语句中要指定查询字段的全名,因此赞扬者姓名要用"payment.name"
若是在多个index上进行nested查询,没有nested字段的index会报错,这时能够将ignore_unmapped设置为truebash

nested对象聚合

若是想查看赞扬的平均金额,须要用nested aggregationapp

GET articles/_search
{
  "size": 0, "aggs": { "nested": { "nested": { "path": "payment" }, "aggs": { "amount_avg": { "avg": { "field": "payment.amount" } } } } } } 

一样注意要用path指定字段名称。返回的数据中,比普通的聚合查询多了一层嵌套
返回结果为elasticsearch

{
  "took": 1, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 0, "hits": [] }, "aggregations": { "nested": { "doc_count": 3, "amount_avg": { "value": 30 } } } } 

nested对象聚合和过滤

若是想看ross赞扬过的总金额,一开始写出query以下ide

GET articles/_search
{
  "size": 0, "query": { "nested": { "path": "payment", "query": { "term": { "payment.name": { "value": "ross" } } } } }, "aggs": { "nested": { "nested": { "path": "payment" }, "aggs": { "sum": { "sum": { "field": "payment.amount" } } } } } } 

此时结果并非正确的,由于上面的query过滤的是ross赞扬过的文章,下面的聚合操做sum的是文章里全部的赞扬,包括了jack的赞扬。
因此须要在sum聚合操做以前,须要用Filter Aggregation筛选ross的赞扬。性能

GET articles/_search
{
  "size": 0, "query": { "nested": { "path": "payment", "query": { "term": { "payment.name": { "value": "ross" } } } } }, "aggs": { "payment": { "nested": { "path": "payment" }, "aggs": { "payer": { "filter": { "term": { "payment.name": { "value": "ross" } } }, "aggs": { "sum": { "sum": { "field": "payment.amount" } } } } } } } } 

最外层的query筛选出ross赞扬过的文章。
第一层的aggs表示进行内嵌聚合。
第二层的aggs用Filter Aggregation筛选出表示ross赞扬行为的nested对象。
第三层的aggs进行聚合。大数据

做者:大神带我来搬砖 连接:https://www.jianshu.com/p/d685b7b6c9d1 来源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
相关文章
相关标签/搜索