ElasticSearch Painless script: How to iterate in an array of Nested Objects ElasticSearch Painless script: How to iterate in an array of Nested Objects elasticsearch elasticsearch

ElasticSearch Painless script: How to iterate in an array of Nested Objects


You can access _source via params._source. This one will work:

PUT /rankings/result/1?refresh{  "rankings": [    {      "rank1": 1051,      "rank2": 78.5,      "subject": "s1"    },    {      "rank1": 45,      "rank2": 34.7,      "subject": "s2"    }  ]}POST rankings/_searchPOST 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


Unfortunately, ElasticSearch scripting in general does not support the ability to access nested documents in this way (including Painless). Perhaps, consider a different structure to your mappings where rankings are stored in multi-valued fields if you need to be able to iterate across them in such a way. Ultimately, the nested data will need to de-normalized and put into the parent documents to be able to gets scores in the way described here.


For Nested objects in an array, iterated over the items and it worked.Following is my sample data in 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  }}

Here is the "Painless" script to iterate over nested objects:

{  "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              }          }  }}

Used above script for update: /activity_index/log/AVjx0UTvgHp45Y_tQP6z/_updateIn the script, created a function called 'contains' with two arguments. Called the function.The old groovy style: ctx._source.task_log.contains() will not work since ES 5.X stores nested objects in a separate document. Hope this helps!`