首页 > 解决方案 > 如何同时按父字段和嵌套字段在 Elasticsearch 中排序?

问题描述

我需要同时按父字段和嵌套字段在 Elasticsearch 中进行排序。我的数据是这样的:

[
    {
        "id": "1",
        "rank": 8,
        "price": 12.45,
        "offers": [
            {
                "id": "777",
                "rank": 12,
                "price": 45.75
            }
        ]
    },
    {
        "id": "2",
        "rank": 35,
        "price": 5.95,
        "offers": null
    }
]

我需要以rank这样的方式对结果进行排序,当offers不是时null我应该采用嵌套offers.rank值,否则我应该采用父rank值。我试过这个脚本,但它不起作用:

    "sort": [
        {
            "_script": {
                "script": {
                    "source": "doc['offers'].size()==0 ? doc['rank'].value : doc['offers.rank'].value",
                    "lang": "painless"
                },
                "type": "number",
                "order": "asc"
            }
        }
    ]

它不起作用可能是因为它来自一个不可访问offers.rank的嵌套对象。offers但我不明白如何处理它 - 如果我为整个脚本添加一个嵌套条件,那么我的父值doc['rank'].value将无法再访问。可以同时按父字段和嵌套字段排序吗?

标签: sortingelasticsearchnested

解决方案


您假设无法访问父级是正确的。现在,你可以

  1. 创建 2 个单独的排序“对象”,一个用于父级,一个用于嵌套报价,然后使用排序模式
  2. 迭代_source而不是:
{
  "sort": [
    {
      "_script": {
        "script": {
          "source": """
          if (params._source.offers instanceof ArrayList
              && params._source.offers.length > 0) {
            return params._source['offers'][0].rank;
          }
          return params._source.rank
          """,
          "lang": "painless"
        },
        "type": "number",
        "order": "asc"
      }
    }
  ]
}

请注意,由于我们在ArrayList这里使用“报价”,因此您需要某种机制来选择排名。这取决于您——我只是访问了第一个报价的排名,您可能想要对数组列表进行排序并选择最高的...

如果您喜欢的话,这里有一个单线:

params._source.offers instanceof ArrayList && params._source.offers.length > 0 ? params._source['offers'][0].rank : params._source.rank

推荐阅读