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


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

    建立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元。

    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设置为true

    nested对象聚合

    如果想查看赞赏的平均金额,需要用nested aggregation

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

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

    {
      "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如下

    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
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    【自动化测试不求人】python自动化测试对xml文件操作
    【自动化测试不求人】python自动化测试对json操作大全
    【自动测试不求人】每日1例无人值守自动化测试异常处理
    自动化测试不求人系列selenium自动化测试键盘事件ActionChains
    【自动化测试不求人】selenium ddt数据驱动模块
    国内常用NTP服务器地址及IP
    Centos语言问题
    linux下创建用户并设置密码
    CCNA Day1
    虚拟光驱导致无法安装光驱驱动的解决方法
  • 原文地址:https://www.cnblogs.com/ExMan/p/11386108.html
Copyright © 2020-2023  润新知