1.1. ES-嵌套查询

ES索引结构本身存储是扁平化存储,如下例子

1.1.1. 背景

  1. 看如下示例,一个订单信息,对应多个费用项数据
{
  "orderNumber": "YY2201-12345678",
  "remark": "这里是备注",
  "waybillNumbers": ["YD2201-12345678", "YD2201-12345679"],
  "creationDate": 1663658432000,
  "costItemInfos": [
    {
      "name": "扣款1",
      "amount": 34,
      "fromSource": 8,
      "comment": "因为啥扣款"
    },
    {
      "name": "扣款2",
      "amount": 38,
      "fromSource": 9,
      "comment": "因为啥扣款2"
    },
    {
      "name": "补贴1",
      "amount": 33,
      "fromSource": 7,
      "comment": "因为啥扣款3"
    }
  ]
}
  1. 问题 如果我们现在想查询{"name": "扣款2","amount":34}的订单,发现依然可以把上面的数据查询出来,然而实际上,我们并不存在扣款2 金额34的费用项。
GET /order/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "costItemInfos.name": "扣款2"
          }
        },
        {
          "match": {
            "costItemInfos.amount": 34
          }
        }
      ]
    }
  }
}
  1. 原因分析 因为ES(lucene)存储结构是扁平化存储,如示例的文档在es内存储结构实际上是这样的:
{
  "orderNumber":                    [ YY2201-12345678, YY2201-12345679 ],
  "remark":                     [ 这里是备注,这里是备注2 ],
  "waybillNumbers":                     [ "YD2201-12345678", "YD2201-12345679" ],
  "creationDate":             [ 1663658432000 ]
  "costItemInfos.name":            [ 扣款1,扣款2,扣款3 ],
  "costItemInfos.amount":             [ 33, 34, 38 ],
  "costItemInfos.fromSource":          [ 7, 8, 9 ],
  "costItemInfos.comment":    [ 因为啥扣款,因为啥扣款2,因为啥扣款3 ]
}

所以根据金额以及费用项名称来查询是可以匹配到的,然而费用项名称与金额的关系已经不存在

  1. 如何解决? 解决只需要将costItemInfos的类型指定为Nested类型即可
PUT /order_new
{
  "mappings": {
    "order": {
      "properties": {
        "orderNumber": {
          "type": "keyword"
        },
        "remark": {
          "fields": {
            "raw": {
              "null_value": "",
              "type": "keyword"
            }
          },
          "type": "text"
        },
        "waybillNumbers": {
          "type": "keyword"
        },
        "creationDate": {
          "type": "date",
                "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        },
        "costItemInfos": {
          "type": "nested",
          "properties": {
            "name": {
              "type": "text"
            },
            "amount": {
              "type": "double"
            },
            "fromSource": {
              "type": "keyword"
            },
            "comment": {
              "type": "text"
            }
          }
        }
      }
    }
  }
}

那么相对应的查询方式做一下改变,使用Nested查询

GET /blog_new/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "costItemInfos",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "costItemInfos.name": "扣款1"
                    }
                  },
                  {
                    "match": {
                      "costItemInfos.amount": 34
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}
  1. 扩展,高阶查询,nested聚合分组统计
    {
    "query": {
     "bool": {
       "must": [
         {
           "terms": {
             "userId": [
               12312312312312
             ]
           }
         }
       ]
     }
    },
    "aggs": {
     "itemNest": {
       "nested": {
         "path": "costItemInfos"
       },
       "aggs": {
         "costItemCodeGroup": {
           "terms": {
             "field": "costItemInfos.costCode"
           },
           "aggs": {
             "amount": {
               "sum": {
                 "field": "costItemInfos.amount"
               }
             },
             "orderCount": {
               "value_count": {
                 "field": "_id"
               }
             }
           }
         }
       }
     }
    }
    }
    
Copyright & copy lviter@163.com            updated 2024-02-06 09:54:56

results matching ""

    No results matching ""