【问题标题】:Elastic Search Query for Multi-valued Data多值数据的弹性搜索查询
【发布时间】:2017-09-02 20:40:20
【问题描述】:

ES 数据的索引如下:

 {
  "addresses" : [
                {
                 "id" : 69,
                 "location": "New Delhi"
                },
               {
               "id" : 69,
               "location": "Mumbai"
               }
            ],
  "goods" : [
            {
            "id" : 396,
            "name" : "abc",
            "price" : 12500
            },
           {
           "id" : 167,
           "name" : "XYz",
           "price" : 12000
           },
           {
            "id" : 168,
            "name" : "XYz1",
            "price" : 11000
           },
           {
            "id" : 169,
            "name" : "XYz2",
            "price" : 13000
          }
        ]
      }

在我的查询中,我想获取至少一个地址匹配且商品价格范围在 11000 到 13000 之间且名称为 xyz 的记录。

【问题讨论】:

标签: elasticsearch elasticsearch-dsl


【解决方案1】:

当您的数据包含复杂对象的数组(例如地址列表或商品列表)时,您可能需要查看 elasticsearch 的 nested 对象,以避免在查询导致的项目多于您的项目时遇到问题期待。

这里的问题是 elasticsearch(实际上是 lucene)存储数据的方式。由于没有直接嵌套对象列表的概念,因此数据被展平并且例如之间的连接XYz12000 丢失。因此,当您查询XYz12500 时,您也会得到此文档作为结果,因为12500 的价格也在goods.price 的值列表中。为避免这种情况,您可以使用 elasticsearch 的 nested objects 功能,该功能基本上将所有内部对象提取到隐藏索引中,并允许查询出现在一个特定对象中的多个字段,而不是“在任何对象中”。有关详细信息,请查看the docs on nested objects,这也很好地解释了这一点。

在您的情况下,映射可能如下所示。我假设,您只想查询 addresses.location 文本而不提供 id,因此该列表可以保持简单对象类型,而不是嵌套类型。另外,我假设您查询完全匹配。如果不是这种情况,您需要从keyword 切换到text 并将term 查询调整为match 一个...

PUT nesting-sample
{
  "mappings": {
    "item": {
      "properties": {
        "addresses": {
          "properties": {
            "id": {"type": "integer"},
            "location": {"type": "keyword"}
          }
        },
        "goods": {
          "type": "nested",
          "properties": {
            "id": {"type": "integer"},
            "name": {"type": "keyword"},
            "price": {"type": "integer"}
          }
        }
      }
    }
  }
}

然后您可以对 location 使用布尔查询和嵌套查询来匹配您的 goods 列表的内部文档。

GET nesting-sample/item/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "addresses.location": "New Delhi"
          }
        },
        {
          "nested": {
            "path": "goods",
            "query": {
              "bool": {
                "must": [
                  {
                    "range": {
                      "goods.price": {
                        "gte": 12200,
                        "lt": 12999
                      }
                    }
                  },
                  {
                    "term": {
                      "goods.name": {
                        "value": "XYz"
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

此查询将与文档不匹配,因为价格范围与商品的确切名称不在同一个嵌套对象中。如果您将下限更改为12000,它将匹配。

请检查您的用例,并注意文档底部关于 the mapping explosion when using nested fields 的警告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    相关资源
    最近更新 更多