ElasticSearch,简单的两个字段比较无痛

ElasticSearch, simple two fields comparison with painless

我正在尝试 运行 查询 SELECT * FROM indexPeople WHERE info.Age > info.AgeExpectancy

请注意,这两个字段 未嵌套 ,它们只是 json 对象

POST /indexPeople/_search
{
  "from" : 0,
  "size" : 200,
  "query" : {
    "bool" : {
      "filter" : [
        {
          "bool" : {
            "must" : [
              {
                "script" : {
                  "script" : {
                    "source" : "doc['info.Age'].value > doc['info.AgeExpectancy'].value",
                    "lang" : "painless"
                  },
                  "boost" : 1.0
                }
              }
            ],
            "adjust_pure_negative" : true,
            "boost" : 1.0
          }
        }
      ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  },
  "_source" : {
    "includes" : [
      "info"
    ],
    "excludes" : [ ]
  }
}

但是这个查询失败了

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "script_stack" : [
          "org.elasticsearch.index.fielddata.ScriptDocValues$Longs.get(ScriptDocValues.java:121)",
          "org.elasticsearch.index.fielddata.ScriptDocValues$Longs.getValue(ScriptDocValues.java:115)",
          "doc['info.Age'].value > doc['info.AgeExpectancy'].value",
          "               ^---- HERE"
        ],
        "script" : "doc['info.Age'].value > doc['info.AgeExpectancy'].value",
        "lang" : "painless",
        "position" : {
          "offset" : 22,
          "start" : 0,
          "end" : 70
        }
      }
    ],
    "type" : "search_phase_execution_exception",
    "reason" : "all shards failed",
    "phase" : "query",
    "grouped" : true,
    "failed_shards" : [
      {
        "shard" : 0,
        "index" : "indexPeople",
        "node" : "c_Dv3IrlQmyvIVpLoR9qVA",
        "reason" : {
          "type" : "script_exception",
          "reason" : "runtime error",
          "script_stack" : [
            "org.elasticsearch.index.fielddata.ScriptDocValues$Longs.get(ScriptDocValues.java:121)",
            "org.elasticsearch.index.fielddata.ScriptDocValues$Longs.getValue(ScriptDocValues.java:115)",
            "doc['info.Age'].value > doc['info.AgeExpectancy'].value",
            "               ^---- HERE"
          ],
          "script" : "doc['info.Age'].value > doc['info.AgeExpectancy'].value",
          "lang" : "painless",
          "position" : {
            "offset" : 22,
            "start" : 0,
            "end" : 70
          },
          "caused_by" : {
            "type" : "illegal_state_exception",
            "reason" : "A document doesn't have a value for a field! Use doc[<field>].size()==0 to check if a document is missing a field!"
          }
        }
      }
    ]
  },
  "status" : 400
}

有办法实现吗? 调试它的最佳方法是什么?我想打印对象或查看日志(不存在),但我无法找到两者兼顾的方法。

映射是:

{
  "mappings": {
    "_doc": {
      "properties": {
        "info": {
          "properties": {
            "Age": {
              "type": "long"
            },
            "AgeExpectancy": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}

也许您已经解决了这个问题。查询失败的原因很明确:

"caused_by" : {
            "type" : "illegal_state_exception",
            "reason" : "A document doesn't have a value for a field! Use doc[<field>].size()==0 to check if a document is missing a field!"
}

基本上有一个或多个文档没有一个查询字段。因此,您可以通过使用 if 检查字段是否确实存在来获得所需的结果。如果它们不存在,您可以简单地 return false 如下:

{
  "script": """
    if (doc['info.Age'].size() > 0 && doc['info.AgeExpectancy'].size() > 0) {
      return doc['info.Age'].value > doc['info.AgeExpectancy'].value
    }
    return false;
}
"""

我使用 Elasticsearch 7.10.2 对其进行了测试,它可以正常工作。

最好的调试方法是什么

这是一个思考问题,也许有人对此有更好的答案。我尝试列出一些选项。显然,调试需要仔细阅读错误信息。

无痛实验室 如果您有最新版本的 Kibana,您可以尝试使用无痛实验室来模拟您的文档,并在更集中的环境中更快地发现错误。

KIBANA 脚本字段 您可以尝试在名为条件的索引模式中创建一个布尔脚本字段。点击创建前记得点击“预览结果”:

最小示例 创建一个最小示例以降低复杂性。 对于这个答案,我使用了一个示例索引,其中包含四个文档以及所有可能的案例。

  1. 无信息:{ "message": "ok"}
  2. Info.Age 但不是预期年龄:{"message":"ok","info":{"Age":14}}
  3. Info.Age预期而非年龄:{"message":"ok","info":{"AgeExpectancy":12}}
  4. Info.Age 和预期年龄:{"message":"ok","info":{"Age":14, "AgeExpectancy": 12}}