【问题标题】:How to order by two different attributes on same document in elasticsearch?如何在elasticsearch中按同一文档上的两个不同属性排序?
【发布时间】:2022-01-06 15:32:32
【问题描述】:

我有文件

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "journeys-development-latest",
        "_type" : "_doc",
        "_id" : "1399",
        "_score" : 1.0,
        "_source" : {
          "draft_recent_edit_at" : "2023-01-14T04:16:41.318Z",
          "recent_edit_at" : "2022-09-23T14:13:41.246Z"
        }
      },
      {
        "_index" : "journeys-development-latest",
        "_type" : "_doc",
        "_id" : "1394",
        "_score" : 1.0,
        "_source" : {
          "draft_recent_edit_at" : "2022-07-02T16:19:41.347Z",
          "recent_edit_at" : "2022-12-26T10:12:41.333Z"
        }
      },
      {
        "_index" : "journeys-development-latest",
        "_type" : "_doc",
        "_id" : "1392",
        "_score" : 1.0,
        "_source" : {
          "draft_recent_edit_at" : "2022-05-20T11:33:41.372Z",
          "recent_edit_at" : "2021-12-21T03:36:41.359Z"
        }
      }
    ]
  }
}

我知道如果我这样做了

{
  "size": 12,
  "from": 0,
  "query": {
    ......,
    ......
  },
  "sort": [
    {
      "recent_edit_at": {
        "order": "desc"
      }
    }
  ]
}

这将按recent_edit_atdesc 顺序订购。

类似地,将recent_edit_at 替换为draft_recent_edit_at 将按draft_recent_edit_atdesc 的顺序中排序。

我正在努力寻找一种方式,让我可以说我想通过draft_recent_edit_at, recent_edit_at 中的max 订购,然后根据这些订购文件。

============================更新================ ===========

添加 HPringles 提出的排序后,输出为

{
  "error": {
    "root_cause": [
      {
        "type": "script_exception",
        "reason": "runtime error",
        "script_stack": [
          "Math.max(doc['draft_recent_edit_at'].value.toInstant().toEpochMilli(),\n                   doc['recent_edit_at'].value.toInstance().toEpochMilli())\n          ",
          "                                                                                                                     ^---- HERE"
        ],
        "script": "\n          Math.max(doc['draft_recent_edit_at'].value.toInstant().toEpochMilli(),\n                   doc['recent_edit_at'].value.toInstance().toEpochMilli())\n          ",
        "lang": "painless"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "journeys-development-latest",
        "node": "GGAHq1ufQQmSqeLRyzka5A",
        "reason": {
          "type": "script_exception",
          "reason": "runtime error",
          "script_stack": [
            "Math.max(doc['draft_recent_edit_at'].value.toInstant().toEpochMilli(),\n                   doc['recent_edit_at'].value.toInstance().toEpochMilli())\n          ",
            "                                                                                                                     ^---- HERE"
          ],
          "script": "\n          Math.max(doc['draft_recent_edit_at'].value.toInstant().toEpochMilli(),\n                   doc['recent_edit_at'].value.toInstance().toEpochMilli())\n          ",
          "lang": "painless",
          "caused_by": {
            "type": "illegal_argument_exception",
            "reason": "dynamic method [org.elasticsearch.script.JodaCompatibleZonedDateTime, toInstance/0] not found"
          }
        }
      }
    ]
  },
  "status": 400
}

【问题讨论】:

  • 我的假设是否正确理解:您想通过两个字段的组合进行排序。这样draft_recentrecent 中最高的记录会排在最前面?
  • @HPringles 是的,这是正确的!
  • 这两个字段是否始终存在?如果任一字段有可能为空,我们可能需要添加一些错误处理
  • 两者都不存在。
  • 哦,这很奇怪,它适用于我的 Elastic 版本 - 尝试使用 .getMillis() 而不是 toInstant().toEpochMIlli() 看看是否有效

标签: ruby-on-rails elasticsearch


【解决方案1】:

如果我理解正确,您可以在运行时使用无痛脚本来执行此操作。

见下文:

"sort": {
      "_script": {
        "type": "number",
        "script": {
          "lang": "painless",
          "source": """
          Math.max(doc['draft_recent_edit_at'].value.toInstant().toEpochMilli(),
                   doc['recent_edit_at'].value.toInstance().toEpochMilli())
          """,
          "params": {
            "factor": 1.1
          }
        },
        "order": "asc"
      }
    }

这将计算出两者中的最大值,然后根据该值进行排序。

【讨论】:

    【解决方案2】:

    据我所知,您可能还想将 Epoch 值转换为 long。

    有点像 -

    "sort": {
          "_script": {
            "type": "number",
            "script": {
              "lang": "painless",
              "source": """
                 long draft_recent_edit_at = doc['draft_recent_edit_at'].value.toInstant().toEpochMilli();
                 long recent_edit_at = doc['recent_edit_at'].value.toInstant().toEpochMilli();
                 Math.max(draft_recent_edit_at, recent_edit_at);
              """
            },
            "order": "asc"
          }
        }
    

    【讨论】:

      猜你喜欢
      • 2019-09-19
      • 2019-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多