如何在脚本plainess elasticsearch中正确使用for循环?

k7fdbhmy  于 2023-11-17  发布在  ElasticSearch
关注(0)|答案(1)|浏览(161)

我使用elasticsearch版本8.10。我写了一个脚本来检查输入字段'资历'有足够的条件搜索结果。
下面是我的demo index:

PUT target_index
{
  "mappings": {
    "properties": {
      "targetoperator": { "type": "keyword" },
      "targetvalue": { 
        "type": "float"
      }
    }
  }
}

字符串
然后,我在上面创建一个文档:

PUT target_index/_doc/1
{
  "targetoperator": [">"],
  "targetvalue": [4]
}


我在上面运行脚本:

GET target_index/_search
{
  "query": {
    "script": {
      "script": { 
        "lang": "painless",
        "source": """
          double userCriteria = params.userTarget.seniority;
          if (doc['targetoperator'].length > 0) {
            for (int i = 0; i < doc['targetoperator'].length; ++i) {
              if (doc['targetoperator'][i] == "<=") {
                if (!(userCriteria <= doc['targetvalue'][i])) {
                  return false;
                }
              } else if (doc['targetoperator'][i] == ">") {
                if (!(userCriteria > doc['targetvalue'][i])) {
                  return false;
                }
              } else if (doc['targetoperator'][i] == "==") {
                if (!(userCriteria == doc['targetvalue'][i])) {
                  return false;
                }
              }
            }
          }
          return true;
        """, 
        "params": {
          "userTarget": {
            "gender": "male",
            "seniority": 5
          }
        }
      }
    }
  },
  "_source": [
    "targetoperator",
    "targetvalue"
  ]
}


运行查询后,我发现返回的结果是document = 1。但我再次更新document = 1:

PUT target_index/_doc/1
{
  "targetoperator": [">", "<="],
  "targetvalue": [4, 8]
}


我再次运行脚本查询。没有找到匹配的结果。
如果这是正确的,它将返回document = 1,因为资历= 5 > 4,5 <= 8

xj3cbfub

xj3cbfub1#

这里有几个问题。
由于所有条件之间都需要AND逻辑,因此需要更改脚本,使其不立即返回true/false,而是将其存储到变量(例如result)中,如下所示:

GET target_index/_search
{
  "query": {
    "script": {
      "script": { 
        "lang": "painless",
        "source": """
          double userCriteria = params.userTarget.seniority;
          boolean result = true;
          if (doc['targetoperator'].length > 0) {
            for (int i = 0; i < doc['targetoperator'].length; ++i) {
              if (doc['targetoperator'][i] == "<=") {
                if (!(userCriteria <= doc['targetvalue'][i])) {
                  result = result && false;
                }
              } else if (doc['targetoperator'][i] == ">") {
                if (!(userCriteria > doc['targetvalue'][i])) {
                  result = result && false;
                }
              } else if (doc['targetoperator'][i] == "==") {
                if (!(userCriteria == doc['targetvalue'][i])) {
                  result = result && false;
                }
              }
            }
          }
          return result;
        """, 
        "params": {
          "userTarget": {
            "gender": "male",
            "seniority": 5
          }
        }
      }
    }
  },
  "_source": [
    "targetoperator",
    "targetvalue"
  ]
}

字符串
然而,我们还没有完成,因为您的目标 * doc值数组并没有按照您指定的方式存储,而是按照字典顺序存储。
运行以下查询显示:

GET target_index/_search
{
  "docvalue_fields": ["targetoperator", "targetvalue"]
}


返回

"fields": {
      "targetvalue": [
        4,
        8
      ],
      "targetoperator": [
        "<=",
        ">"
      ]
    }


正如你所看到的,运算符的顺序不同,即<=>之前。因此,即使修改了逻辑,它也不会工作。
你需要以不同的方式存储你的条件,使用object数组会遇到同样的问题,因为对象字段是扁平的。使用nested会有所帮助,但脚本将在每个嵌套条件的上下文中进行评估,你需要一些后处理逻辑来确保所有条件匹配,即在这种情况下,您需要在应用程序代码中验证嵌套匹配的doc_count是否为2。
由于性能问题,不鼓励使用脚本,除此之外,我强烈建议您修改应用条件的方式。我可以建议使用search templates,它可以帮助您构建非常强大的查询。

相关问题