Script field along with all the other fields using Painless

I have data indexed as follows:

{"index":{"_id":1}}
{"first":"johnny","last":"gaudreau","goals":[9,27,1],"born":"1993/08/13"}
{"index":{"_id":2}}
{"first":"sean","last":"monohan","goals":[7,54,26],"born":"1994/10/12"}

What I want is to calculate the total goals for each player, so I use scripted fields as follows:

GET hockey/_search
{
  "query": {
    "match_all": {}
  },
  "script_fields": {
    "total_goals": {
      "script": {
        "lang": "painless",
        "source": """
          int total = 0;
          for (int i = 0; i < doc['goals'].length; ++i) {
            total += doc['goals'][i];
          }
          return total;
        """
      }
    }
  }
}

the result:

"hits" : [
      {
        "_index" : "hockey",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          "total_goals" : [
            37
          ]
        }
      },
      {
        "_index" : "hockey",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "fields" : {
          "total_goals" : [
            87
          ]
        }
      }

This works fine, but in the result I have "total_goals" for each player, but not the first name and last name. How do I include the first and last name in the results ?

There are two ways.

The results are completely the same but the latter is better for the frexibility that you can use the field for aggregation for example.

Add _source: true:

GET test_hockey/_search
{
  "query": {
    "match_all": {}
  },
  "_source": true, 
  "script_fields": {
    "total_goals": {
      "script": {
        "lang": "painless",
        "source": """
          int total = 0;
          for (int i = 0; i < doc['goals'].length; ++i) {
            total += doc['goals'][i];
          }
          return total;
        """
      }
    }
  }
}

Use runtime mappings (use emit instead of return) and add fields parameter:

GET test_hockey/_search
{
  "query": {
    "match_all": {}
  },
  "runtime_mappings": {
    "total_goals": {
      "type":"long",
      "script": {
        "lang": "painless",
        "source": """
          int total = 0;
          for (int i = 0; i < doc['goals'].length; ++i) {
            total += doc['goals'][i];
          }
          emit(total);
        """
      }
    }
  },
  "fields":["total_goals"]
}
1 Like

Thank you so much. both ways are useful for me. thanks again.

1 Like

I forgot to tell one thing. The latter is not always better.

Script_fields are calculated for only matched document, while runtime mappings are calculated for all documents. Though this is the very reason that runtime mappings can be used for query and aggregation, if the index is huge and you query to filter few documents, script_fields could be much faster. In this case of match_all query, there is no difference in fact.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.