16

How do I can run an aggregation query only on object property, but get all properties in result? e.g. I want to get [{'doc_count': 1, 'key': {'id': 1, 'name': 'tag name'}}], but got [{'doc_count': 1, 'key': '1'] instead. Aggregation on field 'tags' returns zero results.

Mapping:

{
  "test": {
    "properties" : {
      "tags" : {
        "type" : "object",
        "properties": {
          "id" : {"type": "string", "index": "not_analyzed"},
          "name" : {"type": "string", "index": "not_analyzed", "enabled": false}
        }
      }
    }
  }
}

Aggregation query: (returns only IDs as expected, but how can I get ID & name pairs in results?)

'aggregations': {
  'tags': {
    'terms': {
      'field': 'tags.id',
      'order': {'_count': 'desc'},
    },
  }
}

EDIT: Got ID & Name by aggregating on "script": "_source.tags" but still looking for faster solution.

Dmytro Sadovnychyi
  • 6,171
  • 5
  • 33
  • 60

3 Answers3

6

you can use a script if you want, e.g.

"terms":{"script":"doc['tags.id'].value + '|' + doc['tags.name'].value"}

for each created bucket you will get a key with the values of the fields that you have included in your script. To be honest though, the purpose of aggregations is not to return full docs back, but to do calculations on groups of documents (buckets) and return the results, e.g. sums and distinct values. What you actually doing with your query is that you create buckets based on the field tags.id.

Keep in mind that the key on the result will include both values separated with a '|' so you might have to manipulate its value to extract all the information that you need.

cpard
  • 330
  • 1
  • 7
  • already tried, but for some reason with `"terms":{"script":"doc['tags.id'].value"}` I got a bucket with only one tag. – Dmytro Sadovnychyi May 01 '14 at 13:36
  • yes because in your script you only use the value of tags.id. You also need to put the tags.name there, see the example i have in my post. – cpard May 01 '14 at 19:57
  • @cpard I have a very similar setup - when I try and concatenate the two doc fields, the `id` does not map to the correct `name`, and some `id`s are duped. Are you sure this method is reliable? Does this have to do with my mapping? – Benjamin Smith May 28 '14 at 18:30
  • @BenjaminSmith what do you mean that the `id` field does not map to the correct `name` ? the idea of the script is to get the value of the key `id` and merge it with the value of the key `name`, the script is quite simple. It's a bit difficult to know what might go wrong without looking at the mapping or some sample data to be honest, but in case that your document structure or mapping is complex it could help to experiment a bit with a simpler structure to see how the scripts are behaving. – cpard May 28 '14 at 23:24
  • @cpard Using the script, I get a `name` and `id` for each aggregations - but the `id` that is returned is not the id for the given `name`. I'll create a new SO question and ping you the URL here. – Benjamin Smith May 29 '14 at 15:53
  • @BenjaminSmith yep, let me know about the new question. I'm curious to see what's going wrong. – cpard May 29 '14 at 20:10
  • I believe this solution does not work when having multiple objects (array). In a similar setup, I seem to get each combination of id/name as separate bucket. – deyhle Jun 25 '19 at 07:22
6

It's also possible to nest aggregation, you could aggregate by id, then by name.

Thomas Decaux
  • 21,738
  • 2
  • 113
  • 124
1

Additional information, the answer above (cpard's one) works perfectly with nested object. Maybe the weird results that you got are from the fact that you are using object and not nested object.

The difference between these types is that nested object keeps the internal relation between the element in an object. That is why "terms":{"script":"doc['tags.id'].value + '|' + doc['tags.name'].value"} make sense. If you use object type, elasticsearch doesn't know which tags.name are with which tags.id.

For more detail: https://www.elastic.co/blog/managing-relations-inside-elasticsearch

pilo
  • 11
  • 1