0

Using Elasticsearch 7.9.0
My document looks like this

{
  "student": {
    "marks": [
      {
        "sub": 80
      },
      {
        "sub": 90
      },
      {
        "sub": 100
      }
    ]
  }
}

I need one more field total_marks in the response of GET API
Something like this

{
  "hits": [
    {
      "_index": "abc",
      "_type": "_doc",
      "_id": "blabla",
      "_score": null,
      "_source": {
        "student": {
          "marks": [
            {
              "sub": 80
            },
            {
              "sub": 90
            },
            {
              "sub": 100
            }
          ]
        }
      },
      "total_marks": 270
    }
  ]
}

I tried using script_fields My query is

GET sample/_search
{
  "query": {
    "match_all": {}
  },
  "script_fields": {
    "total_marks": {
      "script": {
         "source": """double sum = 0.0;
                    for( item in params._source.student.marks)
                    { sum = sum + item.sub }
                    return sum;"""
      }
    }
  }
}

I got response as

{
  "hits": [
    {
      "_index": "abc",
      "_type": "_doc",
      "_id": "blabla",
      "_score": null,
      "_source": {
        "student": {
          "marks": [
            {
              "sub": 80
            },
            {
              "sub": 90
            },
            {
              "sub": 100
            }
          ]
        }
      },
      "fields": {
        "total_marks": [
          270
        ]
      }
    }
  ]
}

Is thare any way to get as expected?
Any better/optimal solution would be helps a lot.
Thank you.

5
  • scripts are slower. You can use count aggregation instead Commented Sep 11, 2021 at 12:50
  • Okay, but aggregation is to get aggregated values for all the docs in the hits right? I need total marks for each document. Please correct me if I am wrong. and please suggest how to do using count aggregation. Commented Sep 13, 2021 at 4:33
  • sorry it should be sum aggregation. If you need it on group by basis, you can add terms aggregation Commented Sep 13, 2021 at 4:54
  • is there any unique field in each document? like student id etc. based on which a group by can be done Commented Sep 13, 2021 at 4:57
  • Yes I have a unique ID. I will try group by with that. Commented Sep 13, 2021 at 7:06

1 Answer 1

1

Terms aggregation and sum aggregation can be used to find total marks per group

{
  "aggs": {
    "students": {
      "terms": {
        "field": "student.id.keyword",
        "size": 10
      },
      "aggs": {
        "total_marks": {
          "sum": {
            "field": "student.marks.sub"
          }
        }
      }
    }
  }
}

Result

"aggregations" : {
    "students" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "1",
          "doc_count" : 1,
          "total_marks" : {
            "value" : 270.0
          }
        }
      ]
    }
  }

This will be faster than script but Pagination will be easier in query as compared to aggregation. So choose accordingly.

Best option may be to have it calculated at index time. If those fields are not changing frequently.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes pagination will be dificult if we do aggrigations. If we do sort on some fields then aggrigations will not be sorted in that order. Now I am doing calculations at index time. I guess It will reduce the redundant calculations(and cpu usage) as the marks will not be changed later.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.