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

前端 未结 3 1074
挽巷
挽巷 2021-02-07 08:40

I am trying to create a script using the script_score of the function_score. I have several documents whose rankings field is type=\

相关标签:
3条回答
  • 2021-02-07 09:13

    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/_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
    
    0 讨论(0)
  • 2021-02-07 09:19

    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.

    0 讨论(0)
  • 2021-02-07 09:20

    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/_update In 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!`

    0 讨论(0)
提交回复
热议问题