1

I've been looking at aggregations, and at scripting using painless, and I am not able to figure out how to iterate/sum over all values in an object.

Example:

My mapping looks like

"field1": {
  "properties": {
    "subfield1": {
      "type": "float"
    },
    "subfield2": {
      "type": "float"
    },
    "subfield3": {
      "type": "float"
    }
  }
}

Let's assume my data looks like this:

{
  "field1" : {
    "subfield1": 50.0,
    "subfield2": 20.5,
    "subfield3": 30.5
  }
}

I want to perform a range query on 50.0 + 20.5 + 30.5, or, basically, access all the values within the field1 object in some way.

Aggregations do not allow me to use wild-cards in fields. I was looking at the code for LeafDocLookup (used internally for painless), and I see that the relevant methods are disabled.

I've managed to write the script like this:

"query": {
  "script": {
    "script": {
      "inline": "return (doc['field1.subfield1'].value + doc['field1.subfield2'].value + doc['field1.subfield3'].value > 50);",
      "lang": "painless"
    }
  }
}

but this is obviously sub-optimal, and doesn't solve the main issue of dynamic keys.

shashwat
  • 992
  • 1
  • 13
  • 27
  • Can you store the total (i.e. sum) of the sub-keys when you create or update the document? Then you just have one field to query against and don't have to worry about the dynamic keys names. – Phil May 11 '17 at 01:44
  • I can, but I'm sure there are more use-cases where I need to access all elements of a hashmap. Isn't that exactly why we have methods like `keySet()` and `values()`? – shashwat May 11 '17 at 03:59
  • 1
    Painless likely supports getting all subobjects of a field, but in general I would recommend not using scripts in ES queries. They are slow and usually there is a better way to query or to store the documents to avoid scripts. – Phil May 11 '17 at 15:52

1 Answers1

5

I finally figured it out! It isn't available in the doc object within elasticsearch, but it is available within _ctx.source.

So, I can access the object as a Java HashMap object if I use params['_source']

"query": {
  "script": {
    "script": {
      "inline": "float sum = 0.0f; for (float v: params['_source'].values()) { sum += v; } return (sum > 50);",
      "lang": "painless"
    }
  }
}
shashwat
  • 992
  • 1
  • 13
  • 27
  • Nice one, +1. I am using this to find all attributes that have more than a given number of array entries, as in `"params['_source'].keySet().size() > 990"` – mgaert Oct 23 '18 at 07:50