1

目标是过滤具有多种价格的产品。

数据如下所示:

{
  "name":"a",
  "price":[
    {
      "membershipLevel":"Gold",
      "price":"5"
    },
    {
      "membershipLevel":"Silver",
      "price":"50"
    },
    {
      "membershipLevel":"Bronze",
      "price":"100"
    }
    ]
}

我想按membershipLevel和过滤price比如我是白银会员,查询价格范围0-10,产品不应该出现,但如果我是黄金会员,产品“a”应该出现。Elasticsearch 是否支持这种查询?

4

3 回答 3

2

您需要为您的用例使用nested数据类型pricenested query使用。

请参阅以下映射、示例文档、查询和响应:

映射:

PUT my_price_index
{
  "mappings": {
    "properties": {
      "name":{
        "type":"text"
      },
      "price":{
        "type":"nested",
        "properties": {
          "membershipLevel":{
            "type":"keyword"
          },
          "price":{
            "type":"double"
          }
        }
      }
    }
  }
}

样本文件:

POST my_price_index/_doc/1
{
  "name":"a",
  "price":[
    {
      "membershipLevel":"Gold",
      "price":"5"
    },
    {
      "membershipLevel":"Silver",
      "price":"50"
    },
    {
      "membershipLevel":"Bronze",
      "price":"100"
    }
    ]
}

询问:

POST my_price_index/_search
{
  "query": {
    "nested": {
      "path": "price",
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "price.membershipLevel": "Gold"
              }
            },
            {
              "range": {
                "price.price": {
                  "gte": 0,
                  "lte": 10
                }
              }
            }
          ]
        }
      },
      "inner_hits": {}           <---- Do note this. 
    }
  }
}

上面的查询意味着,我想返回price.price范围为 from0 to 10price.membershipLevelas的所有文档Gold

请注意,我使用了inner_hits. 原因是尽管是嵌套文档,但作为响应的 ES 将返回整个文档集,而不仅仅是特定于查询子句适用的文档。

为了找到已匹配的确切嵌套文档,您需要使用inner_hits.

以下是响应的返回方式。

回复:

{
  "took" : 128,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.9808291,
    "hits" : [
      {
        "_index" : "my_price_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.9808291,
        "_source" : {
          "name" : "a",
          "price" : [
            {
              "membershipLevel" : "Gold",
              "price" : "5"
            },
            {
              "membershipLevel" : "Silver",
              "price" : "50"
            },
            {
              "membershipLevel" : "Bronze",
              "price" : "100"
            }
          ]
        },
        "inner_hits" : {
          "price" : {
            "hits" : {
              "total" : {
                "value" : 1,
                "relation" : "eq"
              },
              "max_score" : 1.9808291,
              "hits" : [
                {
                  "_index" : "my_price_index",
                  "_type" : "_doc",
                  "_id" : "1",
                  "_nested" : {
                    "field" : "price",
                    "offset" : 0
                  },
                  "_score" : 1.9808291,
                  "_source" : {
                    "membershipLevel" : "Gold",
                    "price" : "5"
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

希望这可以帮助!

于 2020-03-10T16:14:51.020 回答
1

让我向您展示如何做到这一点,使用嵌套字段以及查询和过滤上下文。我将以你的例子来展示,你如何定义索引映射、索引示例文档和搜索查询。

重要的是要注意include_in_parentElasticsearch 映射中的参数,它允许我们在不使用嵌套字段的情况下使用这些嵌套字段。

请参阅有关它的 Elasticsearch 文档。

如果为 true,则嵌套对象中的所有字段也将作为标准(平面)字段添加到父文档。默认为假。

索引定义

{
    "mappings": {
        "properties": {
            "product": {
                "type": "nested",
                "include_in_parent": true
            }
        }
    }
}

索引示例文档

{
    "product": {
        "price" : 5,
        "membershipLevel" : "Gold"
    }
}
{
    "product": {
        "price" : 50,
        "membershipLevel" : "Silver"
    }
}

{
    "product": {
        "price" : 100,
        "membershipLevel" : "Bronze"
    }
}

搜索查询以显示Gold价格范围 0-10

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "product.membershipLevel": "Gold"
                    }
                }
            ],
            "filter": [
                {
                    "range": {
                        "product.price": {
                            "gte": 0,
                            "lte" : 10
                        }
                    }
                }
            ]
        }
    }
}

结果

"hits": [
            {
                "_index": "so-60620921-nested",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0296195,
                "_source": {
                    "product": {
                        "price": 5,
                        "membershipLevel": "Gold"
                    }
                }
            }
        ]

搜索要排除Silver的查询,价格范围相同

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "product.membershipLevel": "Silver"
                    }
                }
            ],
            "filter": [
                {
                    "range": {
                        "product.price": {
                            "gte": 0,
                            "lte" : 10
                        }
                    }
                }
            ]
        }
    }
}

上面的查询没有返回任何结果,因为没有任何匹配的结果。

PS :-这个SO 答案可能会帮助您了解嵌套字段并详细查询它们。

于 2020-03-10T15:58:29.573 回答
0

您必须使用嵌套字段和嵌套查询来存档:https ://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html

使用“嵌套”类型定义您的价格属性,然后您将能够按嵌套对象的每个属性进行过滤

于 2020-03-10T15:39:43.303 回答