Aggregation over array

Hi,

I have a document like this

{
  "ip": [
    "192.168.1.1",
    "192.168.1.2"
  ]
}

Is it possible to make aggregation over value at zero position in the array? Something like this?

{
  "aggs": {
    "my_aggregation": {
     "cardinality": {
        "field": "ip.0"
      }
    }
  }
}

I want to use this aggregation for query in a Watcher

UPD: ip field has keyword type

Hi @ddoroshenko

not exactly like that, but you could achieve what you are looking for with Runtime fields or via ES|QL.

Runtime fields approach

In this case define a ip0 field as runtime field with something like the following in painless:

def ips = doc['ip'];
if(ips.length > 0){
    if(ips.length === 1) {
        emit(ips.value);
    } else {
        emit(ips[0]);
    }
}

Now use the ip0 field to perform your aggregations in your viz.

ES|QL

You can use the MV_FIRST function in ES|QL to extract the first value and then perform an aggregation

FROM index | STATS DISTINCT_COUNT(MV_FIRST(ip)) ...
1 Like

@Marco_Liberati thank you for your response, but I'm afraid it's not suitable for me.

I want to use this aggregation in a Watcher with another fields

Here is an example that may work :

POST test/_doc
{
  "ip": [
    "192.168.1.1",
    "192.168.1.2"
  ]
}

POST test/_search
{
    "size": 0,
  "runtime_mappings": {
    "ip0": {
      "type": "keyword",
      "script": {
        "source": """
            if (doc['ip.keyword'].size() > 0) { 
                emit(doc['ip.keyword'][0]); 
            }
        """
      }
    }
  },
  "aggs": {
    "term": {
      "terms": {
        "field": "ip0"
      }
    }
  }
}

Response :

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "term": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "192.168.1.1",
          "doc_count": 1
        }
      ]
    }
  }
}

an ingest pipeline, enriching the doc by adding a specific ip0 field ?

1 Like

I tried

aggs:
  cardinality:
    script:
      lang: painless
      source: params['_source']['ip'][0]

But i get an error

Attempting to address a non-array-like type as an array

But when I do

script_fields:
  ip0:
    script:
      lang: painless
      source: params['_source']['ip'][0]

I get

ip0: [192.168.1.1]

Well,
Actually I have multi type filed ip and ip.keyword

So this works for me

aggs:
  cardinality:
    script:
      lang: painless
      source: doc['ip.keyword'][0]