Elasticsearch进阶笔记第三十二篇

91 阅读4分钟

Elasticsearch高手进阶篇(68)

数据建模实战_对嵌套的博客评论数据进行聚合分析

nested object中的数据进行聚合分析

聚合数据分析的需求1:按照评论日期进行bucket划分,然后拿到每个月的评论的评分的平均值

  • 数据导入
 GET /waws_webblog/blogs/_search 
 {
   "size": 0, 
   "aggs": {
     "comments_path": {
       "nested": {
         "path": "comments"
       }, 
       "aggs": {
         "group_by_comments_date": {
           "date_histogram": {
             "field": "comments.date",
             "interval": "month",
             "format": "yyyy-MM"
           },
           "aggs": {
             "avg_stars": {
               "avg": {
                 "field": "comments.stars"
               }
             }
           }
         }
       }
     }
   }
 }
 
 {
   "took": 41,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 0,
     "hits": []
   },
   "aggregations": {
     "comments_path": {
       "doc_count": 2,
       "group_by_comments_date": {
         "buckets": [
           {
             "key_as_string": "2016-09",
             "key": 1472688000000,
             "doc_count": 1,
             "avg_stars": {
               "value": 4
             }
           },
           {
             "key_as_string": "2016-10",
             "key": 1475280000000,
             "doc_count": 1,
             "avg_stars": {
               "value": 5
             }
           }
         ]
       }
     }
   }
 }
  • 第二个案例:每个月的评论的评分的平均值
 GET /waws_webblog/blogs/_search 
 {
   "size": 0,
   "aggs": {
     "comments_path": {
       "nested": {
         "path": "comments"
       },
       "aggs": {
         "group_by_comments_age": {
           "histogram": {
             "field": "comments.age",
             "interval": 10
           },
           "aggs": {
             "reverse_path": {
               "reverse_nested": {}, 
               "aggs": {
                 "group_by_tags": {
                   "terms": {
                     "field": "tags.keyword"
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
 }
 
 {
   "took": 53,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 0,
     "hits": []
   },
   "aggregations": {
     "comments_path": {
       "doc_count": 2,
       "group_by_comments_age": {
         "buckets": [
           {
             "key": 20,
             "doc_count": 1,
             "reverse_path": {
               "doc_count": 1,
               "group_by_tags": {
                 "doc_count_error_upper_bound": 0,
                 "sum_other_doc_count": 0,
                 "buckets": [
                   {
                     "key": "投资",
                     "doc_count": 1
                   },
                   {
                     "key": "理财",
                     "doc_count": 1
                   }
                 ]
               }
             }
           },
           {
             "key": 30,
             "doc_count": 1,
             "reverse_path": {
               "doc_count": 1,
               "group_by_tags": {
                 "doc_count_error_upper_bound": 0,
                 "sum_other_doc_count": 0,
                 "buckets": [
                   {
                     "key": "投资",
                     "doc_count": 1
                   },
                   {
                     "key": "理财",
                     "doc_count": 1
                   }
                 ]
               }
             }
           }
         ]
       }
     }
   }
 }

Elasticsearch高手进阶篇(69)

数据建模实战_研发中心管理案例以及父子关系数据建模

父子关系数据建模

  • nested object的建模

    • 有个不好的地方,就是采取的是类似冗余数据的方式,将多个数据都放在一起了,维护成本就比较高
  • parent child建模方式

    • 采取的是类似于关系型数据库的三范式类的建模,多个实体都分割开来,每个实体之间都通过一些关联方式,进行了父子关系的关联,各种数据不需要都放在一起,父doc和子doc分别在进行更新的时候,都不会影响对方
  • 一对多关系的建模

    • 维护起来比较方便,而且我们之前说过,类似关系型数据库的建模方式,应用层join的方式,会导致性能比较差,因为做多次搜索。父子关系的数据模型,不会,性能很好因为虽然数据实体之间分割开来,但是我们在搜索的时候,由es自动为我们处理底层的关联关系,并且通过一些手段保证搜索性能。

父子关系数据模型,相对于nested数据模型来说,优点是父doc和子doc互相之间不会影响

要点:父子关系元数据映射,用于确保查询时候的高性能,但是有一个限制,就是父子数据必须存在于一个shard中

父子关系数据存在一个shard中,而且还有映射其关联关系的元数据,那么搜索父子关系数据的时候,不用跨分片,一个分片本地自己就搞定了,性能当然高咯

案例背景

  • 研发中心员工管理案例,一个IT公司有多个研发中心,每个研发中心有多个员工
 PUT /waws520_company
 {
   "mappings": {
     "rd_center": {},
     "employee": {
       "_parent": {
         "type": "rd_center" 
       }
     }
   }
 }

父子关系建模的核心,多个type之间有父子关系,用_parent指定父type

 POST /waws520_company/rd_center/_bulk
 { "index": { "_id": "1" }}
 { "name": "北京研发总部", "city": "北京", "country": "中国" }
 { "index": { "_id": "2" }}
 { "name": "上海研发中心", "city": "上海", "country": "中国" }
 { "index": { "_id": "3" }}
 { "name": "硅谷人工智能实验室", "city": "硅谷", "country": "美国" }

shard路由的时候,id=1的rd_center doc,默认会根据id进行路由,到某一个shard

 PUT /waws520_company/employee/1?parent=1 
 {
   "name":  "张三",
   "birthday":   "1970-10-24",
   "hobby": "爬山"
 }

维护父子关系的核心,parent=1,指定了这个数据的父doc的id

  • 此时,parent-child关系,就确保了说,父doc和子doc都是保存在一个shard上的。内部原理还是doc routing,employee和rd_center的数据,都会用parent id作为routing,这样就会到一个shard
    • 不会根据id=1的employee doc的id进行路由了,而是根据parent=1进行路由,会根据父doc的id进行路由,那么就可以通过底层的路由机制,保证父子数据存在于一个shard中
 POST /waws520_company/employee/_bulk
 { "index": { "_id": 2, "parent": "1" }}
 { "name": "李四", "birthday": "1982-05-16", "hobby": "游泳" }
 { "index": { "_id": 3, "parent": "2" }}
 { "name": "王二", "birthday": "1979-04-01", "hobby": "爬山" }
 { "index": { "_id": 4, "parent": "3" }}
 { "name": "赵五", "birthday": "1987-05-11", "hobby": "骑马" }