ElasticSearch无痛脚本:如何迭代嵌套对象数组

时间:2017-02-02 18:33:12

标签: arrays elasticsearch

我正在尝试使用script_score的{​​{1}}创建脚本。 我有几个function_score字段为rankings的文档。 该字段的映射是:

type="nested"

示例文档是:

"rankings": {
        "type": "nested",
        "properties": {
          "rank1": {
            "type": "long"
          },
          "rank2": {
            "type": "float"
          },
          "subject": {
            "type": "text"
          }
        }
      }

我想要实现的是迭代排名的嵌套对象。实际上,我需要使用ie for循环来查找特定的"rankings": [ { "rank1": 1051, "rank2": 78.5, "subject": "s1" }, { "rank1": 45, "rank2": 34.7, "subject": "s2" }] 并使用subject来计算某些内容。 到目前为止,我使用类似的东西,但它似乎不起作用(抛出编译错误):

rank1, rank2

我也尝试了以下选项:

  1. "function_score": { "script_score": { "script": { "lang": "painless", "inline": "sum = 0;" "for (item in doc['rankings_cug']) {" "sum = sum + doc['rankings_cug.rank1'].value;" "}" } } } 循环使用for代替:in但没有成功。
  2. for (item:doc['rankings'])使用for循环,但尝试迭代对象的特定元素,即inrank1,它实际编译但似乎找不到一个零长度数组for (item in doc['rankings.rank1'].values)
  3. 我已经读过rank1元素可以返回类似JSON的对象,但据我发现它在搜索查询中不受支持。

    你能告诉我一些如何处理的想法吗?

    非常感谢。

3 个答案:

答案 0 :(得分:7)

您可以通过params._source访问_source。这个可行:

PUT /rankings/result/1?refresh
{
  "rankings": [
    {
      "rank1": 1051,
      "rank2": 78.5,
      "subject": "s1"
    },
    {
      "rank1": 45,
      "rank2": 34.7,
      "subject": "s2"
    }
  ]
}

POST rankings/_search

POST rankings/_search
{
  "query": {
    "match": {
      "_id": "1"
    }
  },
  "script_fields": {
    "script_score": {
      "script": {
        "lang": "painless",
        "inline": "double sum = 0.0; for (item in params._source.rankings) { sum += item.rank2; } return sum;"
      }
    }
  }
}

DELETE rankings

答案 1 :(得分:6)

不幸的是,ElasticSearch脚本一般不支持以这种方式访问​​嵌套文档的能力(包括Painless)。也许,考虑一种与您的映射不同的结构,如果您需要能够以这种方式迭代排序,则将排名存储在多值字段中。最终,嵌套数据需要去标准化并放入父文档中,以便能够按照此处描述的方式获得分数。

答案 2 :(得分:4)

对于数组中的嵌套对象,迭代项目并且它有效。 以下是我在elasticsearch index中的示例数据:

{
  "_index": "activity_index",
  "_type": "log",
  "_id": "AVjx0UTvgHp45Y_tQP6z",
  "_version": 4,
  "found": true,
  "_source": {
    "updated": "2016-12-11T22:56:13.548641",
    "task_log": [
      {
        "week_end_date": "2016-12-11",
        "log_hours": 16,
        "week_start_date": "2016-12-05"
      },
      {
        "week_start_date": "2016-03-21",
        "log_hours": 0,
        "week_end_date": "2016-03-27"
      },
      {
        "week_start_date": "2016-04-24",
        "log_hours": 0,
        "week_end_date": "2016-04-30"
      }
    ],
    "created": "2016-12-11T22:56:13.548635",
    "userid": 895,
    "misc": {

    },
    "current": false,
    "taskid": 1023829
  }
}

这是迭代嵌套对象的“无痛”脚本:

{
  "script": {
    "lang": "painless",
    "inline": 
        "boolean contains(def x, def y) {
          for (item in x) {
            if (item['week_start_date'] == y){
              return true
            }
          }
          return false 
         }
         if(!contains(ctx._source.task_log, params.start_time_param) {
           ctx._source.task_log.add(params.week_object)
         }",
         "params": {
            "start_time_param": "2016-04-24",
             "week_object": {
               "week_start_date": "2016-04-24",
               "week_end_date": "2016-04-30",
               "log_hours": 0
              }
          }
  }
}

上面用于更新的脚本:/ activity_index / log / AVjx0UTvgHp45Y_tQP6z / _update 在脚本中,创建了一个带有两个参数的名为“contains”的函数。称为功能。 旧的groovy样式:ctx._source.task_log.contains()将无法工作,因为ES 5.X将嵌套对象存储在单独的文档中。希望这有帮助!`