Hi @prohit,
Sorry, I'm a bit confused: in the description, you are talking about 1 document, but the code you pasted is an array of 2 objects.
Does it mean you've pasted 2 documents or that the array belongs in a field inside a document?
In any case, I think you don't need a Painless script to do this. We only need to tell Elasticsearch that we want to be able to analyze Hours Worked
as a number.
I've created a test index myself to simulate your scenario. You can run the same commands in Kibana's Dev Tools if you want.
- Without setting any previous mappings, I start indexing the values:
PUT my-test-index/_doc/1
{
"Dateweeklycomments": "2020-04-09T00:00:00.000Z",
"Name": "Roger Benny",
"Role": { "id": null, "name": "Primary Analyst" },
"Hours Worked": "5"
}
PUT my-test-index/_doc/2
{
"Dateweeklycomments": "2020-04-16T00:00:00.000Z",
"Name": "Roger Benny",
"Role": { "id": null, "name": "Primary Analyst" },
"Hours Worked": "15"
}
- Elasticsearch has created the mappings dynamically for me
GET my-test-index/_mapping
returns
{
"my-test-index" : {
"mappings" : {
"properties" : {
"Dateweeklycomments" : {
"type" : "date"
},
"Hours Worked" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"Name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"Role" : {
"properties" : {
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
}
- Focusing on
Hours Worked
, you can see Elasticsearch has identified it as a text
, and it has also added the multi-field .keyword
in case we want to analyze them as such. But we want to be able to sum those values, right? Let's make use of the multi-field feature, to create a new subfield .number
, that will be analyzed as a short
(you can also use any other Numeric type as it fits your data). To do so, we can add that new multi-field in the mappings:
PUT my-test-index/_mapping
{
"properties": {
"Hours Worked": {
"type": "text",
"fields": {
"number": {"type": "short"}
}
}
}
}
- If we get the mappings again
GET my-test-index/_mapping
, we can see Hours Worked
is still type: "text"
, but it now has 2 multi-fields: the previous keyword
and the new number
.
{
"my-test-index" : {
"mappings" : {
"properties" : {
"Dateweeklycomments" : {
"type" : "date"
},
"Hours Worked" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
},
"number" : {
"type" : "short"
}
}
},
"Name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"Role" : {
"properties" : {
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
}
-
Then, we need to tell Elasticsearch to re-process all the documents, so it applies the new mapping to the previous documents. We can do that by running POST my-test-index/_update_by_query
.
-
Finally, now we can use the new field Hours Worked.number
to aggregate and sum the hours
GET my-test-index/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"names": {
"terms": {
"field": "Name.keyword",
"size": 10
},
"aggs": {
"Sum of Hours Worked": {
"sum": {
"field": "Hours Worked.number"
}
}
}
}
}
}
Note, you can also do visualizations now in Kibana with the new field.
If you still prefer the painless-scripted way, let me know. But I wouldn't recommend it because this approach is more performant and it also allows you to search by ranges.