如何基于过滤器数据在弹性搜索中对数据进行排序

时间:2019-08-20 08:20:35

标签: elasticsearch elasticsearch-plugin

对于这种弹性搜索,我还比较陌生。因此,我以下述方式将数据存储在弹性搜索中:

[{
    "name": "user1",
    "city": [{
        "name": "city1",
        "count": 18
    },{
        "name": "city2",
        "count": 15
    },{
        "name": "city3",
        "count": 10
    },{
        "name": "city4",
        "count": 5
    }]
},{
    "name": "user2",
    "city": [{
        "name": "city2",
        "count": 2
    },{
        "name": "city5",
        "count": 5
    },{
        "name": "city6",
        "count": 8
    },{
        "name": "city8",
        "count": 15
    }]
},{
    "name": "user3",
    "city": [{
        "name": "city1",
        "count": 2
    },{
        "name": "city5",
        "count": 5
    },{
        "name": "city7",
        "count": 28
    },{
        "name": "city2",
        "count": 1
    }]
}]

因此,我想做的是,找出城市列表中具有“ city2”的用户,并根据“ city2”的“计数”对数据进行排序。

这是我查询过的内容:

{
    "sort": [{
        "city.count": {
            "order" : "desc"
        }
    }],
    "query": {
        "bool": {
            "must": [
                 {"match": {"city.name": "city2"}}
            ]
        }
    }
}

所以我无法弄清楚排序方式! 排序部分正在基于过滤器考虑所有城市的所有“计数”值,但我只希望仅基于“ city2”的“计数”来执行排序。

任何帮助将不胜感激。预先感谢。

2 个答案:

答案 0 :(得分:1)

由于字段cityobject而不是nested object,因此您无法实现的目标。这样做的原因是,当您将一个字段定义为object时,弹性将每个对象字段的值展平为一个数组。所以,

"city": [
  {
    "name": "city1",
    "count": 18
  },
  {
    "name": "city2",
    "count": 15
  },
  {
    "name": "city3",
    "count": 10
  },
  {
    "name": "city4",
    "count": 5
  }
]

的索引为:

"city.name" : ["city1", "city2", "city3", "city4"]
"city.count": [18, 15, 10, 5]

如您所见,由于对象的弹性索引方式丢失了每个城市与其城市数量之间的关系。

因此,每当要保留关系时,都应将字段定义为nested类型。

{
  "city": {
    "type": "nested",
    "properties": {
      "name": {
        "type": "text"
      },
      "count": {
        "type": "long"
      }
    }
  }
}

然后可以使用此nested field进行排序。

{
  "sort": [
    {
      "city.count": {
        "order": "desc",
        "mode": "avg",
        "nested": {
          "path": "city",
          "filter": {
            "match": {
              "city.name": "city2"
            }
          }
        }
      }
    }
  ],
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "city.name": "city2"
          }
        }
      ]
    }
  }
}

答案 1 :(得分:0)

达到目标会有些复杂。

首先,您的查询说您要获取其中带有“ city2”的文档。由于数组“ city”中的至少一个元素匹配,因此将返回整个文档。

问题是您只想返回city2的计数,而不是全部返回。这就是复杂的部分来了。

您可以遵循很多方法:

  1. 更改索引设计。与其拥有一系列用户,不如让每个用户拥有一个包含所有信息(包括访问过的城市)的文档。但是,“我只想要数组中的1个元素”问题仍然存在,但是您一次只能处理一个数组,而不是n。

  2. 您可以使用Painless仅带回该特定城市的数量,但这将意味着大量脚本编写。不要相信这个名字。无痛是非常痛苦的。

  3. 您可以带回所有元素,并在代码中进行过滤。例如,如果使用Python Elasticsearch Client,则可以执行查询,返回所有对象,并仅使用Python选择所需的元素。

不要考虑使用Terms aggregation。它将带回所有城市的总数,而无需与每个用户保持联系。这不是您想要做的。

希望这是有帮助的,很抱歉,我们无法直接解决问题:(