首页 > 解决方案 > 源过滤 ElasticSearch 中的对象数组

问题描述

这是 ElasticSearch 中的一个文档

"CompanyId": 5733,
"PartNumber": "W8S038",
"Name_en": "#8 Washer, M4 Compatible, Stainless Steel, Pack of 100",
"ProductId": 90023,
"CompanyName": "Washers Ltd",
"Prices": [

    {
        "BuyerId": 308,
        "Price": 2.42
    }
    ,
    {
        "BuyerId": 406,
        "Price": 2.22
    }
]
}

显然,我们不能让买家 308 知道买家 406 正在获得更好的价格。因此,当买家 308 正在搜索时,我需要删除其他买家的所有价格。

我想通过使用源过滤来做到这一点。但是怎么办?!

(我可以使用 排除Prices并添加所需的价格script_field。但是,这意味着价格不是源文档的一部分,因此 ReactiveSearch 看不到它,因此无法对其进行排序。)

更新:这是由 ReactiveSearch 生成的查询,我需要在其中附加价格限制:

   "query":{
      "bool":{
         "must":[
            {
               "bool":{
                  "must":[
                     {
                        "bool":{
                           "must":[
                              {
                                 "bool":{
                                    "should":[
                                       {
                                          "multi_match":{
                                             "query":"m4 washer",
                                             "fields":[
                                                "Name_en"
                                             ],
                                             "type":"cross_fields",
                                             "operator":"and"
                                          }
                                       },
                                       {
                                          "multi_match":{
                                             "query":"m4 washer",
                                             "fields":[
                                                "Name_en"
                                             ],
                                             "type":"phrase_prefix",
                                             "operator":"and"
                                          }
                                       }
                                    ],
                                    "minimum_should_match":"1"
                                 }
                              }
                           ]
                        }
                     }
                  ]
               }
            }
         ],
"filter": [            
        {
          "nested": {
            "path": "Prices",
            "query": {
              "term": {
                "Prices.CompanyId": 1474
              }
            },
            "inner_hits": {}
          }
        }
      ]      
      }
   },
   "size":10,
   "aggs":{
      "CompanyName.raw":{
         "terms":{
            "field":"CompanyName.raw",
            "size":1000,
            "order":{
               "_count":"desc"
            }
         }
      }
   },
   "_source":{
      "excludes":[
         "PurchasingViews",
         "ContractFilters",
         "SearchField*",
         "Keywords*",
         "Menus*"
      ]
   },
   "from":0,
   "sort":[
      {
         "Name_en.raw":{
            "order":"asc"
         }
      }
   ],
   "script_fields":{
      "price":{
         "script":{
            "lang":"painless",
            "inline":"if(params['_source']['Prices'] != null){for(p in params['_source']['Prices']){ if(p.CompanyId == 1474) return p.Price; }} return null;"
         }
      }
   }
}

(这bool, must, bool, must, bool, must, bool, should似乎相当愚蠢?)

标签: elasticsearch

解决方案


您需要使用下面的嵌套inner_hits功能。

{
  "_source": [
    "CompanyId", "PartNumber", "Name_en", "ProductId", "CompanyName"
  ],
  "query": {
    "bool": {
      "filter": [            
        {
          "nested": {
            "path": "Prices",
            "query": {
              "term": {
                "Prices.BuyerId": 308
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  }
}

在输出中,您将得到您所期望的,即所有根级字段和给定买家的匹配价格。

更新

以下是我将如何重写您的查询:

{
  "query": {
    "bool": {
      "minimum_should_match": "1",
      "should": [
        {
          "multi_match": {
            "query": "m4 washer",
            "fields": [
              "Name_en"
            ],
            "type": "cross_fields",
            "operator": "and"
          }
        },
        {
          "multi_match": {
            "query": "m4 washer",
            "fields": [
              "Name_en"
            ],
            "type": "phrase_prefix",
            "operator": "and"
          }
        }
      ],
      "filter": [
        {
          "nested": {
            "path": "Prices",
            "query": {
              "term": {
                "Prices.CompanyId": 1474
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  },
  "size": 10,
  "aggs": {
    "CompanyName.raw": {
      "terms": {
        "field": "CompanyName.raw",
        "size": 1000,
        "order": {
          "_count": "desc"
        }
      }
    }
  },
  "_source": {
    "excludes": [
      "PurchasingViews",
      "ContractFilters",
      "SearchField*",
      "Keywords*",
      "Menus*",
      "Prices"
    ]
  },
  "from": 0,
  "sort": [
    {
      "Name_en.raw": {
        "order": "asc"
      }
    }
  ],
  "script_fields": {
    "price": {
      "script": {
        "lang": "painless",
        "inline": "if(params['_source']['Prices'] != null){for(p in params['_source']['Prices']){ if(p.CompanyId == 1474) return p.Price; }} return null;"
      }
    }
  }
}

推荐阅读