【问题标题】:ElasticSearch - Filtering data returned from nested queryElasticSearch - 过滤从嵌套查询返回的数据
【发布时间】:2020-08-05 19:35:36
【问题描述】:

我有一组数据结构如下:

[
    {
        "productId": "ProductId1",
        "customerNumbers": [
            "customer": {
                "name": "Prod1Cust1",
                "totalOrders": 23
            },
            "customer": {
                "name": "Prod2Cust1",
                "totalOrders": 5
            },
            "customer": {
                "name": "Prod3Cust1",
                "totalOrders": 5
            }
        ]
    },
    {
        "productId": "ProductId2",
        "customerNumbers": [
            "customer": {
                "name": "Prod2Cust1",
                "totalOrders": 23
            },
            "customer": {
                "name": "Prod2Cust1",
                "totalOrders": 5
            }
        ]
    }
]

我需要在 name 字段中获取所有 prefix 为“Prod1”的记录(在示例中避免,只应返回第一条记录,即 ProductId1 ). 另外,当数据返回时,我只需要获取前缀为 Prod1 的客户编号,即:

正确的输出:

{
        "productId": "ProductId1",
        "customerNumbers": [
            "customer": {
                "name": "Prod1Cust1",
                "totalOrders": 23
            }
        ]
    }

代替:

{
        "productId": "ProductId1",
        "customerNumbers": [
            "customer": {
                "name": "Prod1Cust1",
                "totalOrders": 23
            },
            "customer": {
                "name": "Prod2Cust1",
                "totalOrders": 5
            },
            "customer": {
                "name": "Prod3Cust1",
                "totalOrders": 5
            }
        ]
    }

我可以使用嵌套查询和 MatchPhrasePrefixQuery 来获取 Name 前缀为“Prod1”的记录(这会返回包含所有客户编号的结果)。如何进一步过滤数据以获取 Name 前缀为“Prod1”的客户编号。

以下是我当前的查询:

{
    "from": 0,
    "size": 10,
    "sort": [
        {
            "name.keyword": {
                "missing": "_first",
                "order": "asc"
            }
        }
    ],
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "must": [
                            {
                                "nested": {
                                    "query": {
                                        "bool": {
                                            "must": [
                                                {
                                                    "match": {
                                                        "customerNumbers.name": {
                                                            "query": "Prod1",
                                                            "type": "phrase_prefix"
                                                        }
                                                    }
                                                }
                                            ]
                                        }
                                    },
                                    "path": "customerNumbers"
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

P.S:我正在使用 ElasticSearch 5.x 和 Nest。

【问题讨论】:

    标签: elasticsearch nest elasticsearch-query


    【解决方案1】:

    尝试使用inner_hits

    PUT products
    {"mappings":{"_doc":{"properties":{"customerNumbers":{"type":"nested"}}}}}
    
    POST products/_doc
    {"productId":"ProductId1","customerNumbers":[{"name":"Prod1Cust1","totalOrders":23},{"name":"Prod2Cust1","totalOrders":5},{"name":"Prod3Cust1","totalOrders":5}]}
    
    POST products/_doc
    {"productId":"ProductId2","customerNumbers":[{"name":"Prod2Cust1","totalOrders":23},{"name":"Prod2Cust1","totalOrders":5}]}
    
    GET products/_search
    {
      "_source": "inner_hits", 
      "from": 0,
      "size": 10,
      "query": {
        "bool": {
          "must": [
            {
              "bool": {
                "must": [
                  {
                    "nested": {
                      "path": "customerNumbers",
                      "query": {
                        "bool": {
                          "must": [
                            {
                              "match_phrase_prefix": {
                                "customerNumbers.name": {
                                  "query": "Prod1"
                                }
                              }
                            }
                          ]
                        }
                      },
                      "inner_hits": {}
                    }
    
                  }
                ]
              }
            }
          ]
        }
      }
    }
    

    产生以下点击量

    [
      {
        "_index":"products",
        "_type":"_doc",
        "_id":"tyQGo3EBdiyDG0RsTa0N",
        "_score":0.9808292,
        "_source":{
    
        },
        "inner_hits":{
          "customerNumbers":{
            "hits":{
              "total":1,
              "max_score":0.9808292,
              "hits":[
                {
                  "_index":"products",
                  "_type":"_doc",
                  "_id":"tyQGo3EBdiyDG0RsTa0N",
                  "_nested":{
                    "field":"customerNumbers",
                    "offset":0
                  },
                  "_score":0.9808292,
                  "_source":{
                    "name":"Prod1Cust1",         <-----
                    "totalOrders":23
                  }
                }
              ]
            }
          }
        }
      }
    ]
    

    【讨论】:

    • 感谢@jzzfs 的回复。我确实按照您的描述实现了逻辑;我能够获取内部命中,但它只包含总结果的一个子集(我已将 inner_hits 的 Size 属性设置为最大值)。有什么想法,为什么?
    • 这不是你想要的吗?来自大量不相关客户的单个客户?
    • 是的,但是,在我正在执行的测试用例中,大约有 70 个客户满足前缀条件,但内部命中数约为 50。我不确定,为什么其他 20 条记录不属于内部热门。
    • 你在内部点击中设置了什么限制?你的max value 是什么?
    • 我正在使用 C#(NEST NuGet 包)并将限制设置为 Int32.MaxValue。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-05
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 2018-05-10
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多