IP range aggregation

edit

Just like the dedicated date range aggregation, there is also a dedicated range aggregation for IP typed fields:

Example:

resp = client.search(
    index="ip_addresses",
    size=10,
    aggs={
        "ip_ranges": {
            "ip_range": {
                "field": "ip",
                "ranges": [
                    {
                        "to": "10.0.0.5"
                    },
                    {
                        "from": "10.0.0.5"
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'ip_addresses',
  body: {
    size: 10,
    aggregations: {
      ip_ranges: {
        ip_range: {
          field: 'ip',
          ranges: [
            {
              to: '10.0.0.5'
            },
            {
              from: '10.0.0.5'
            }
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "ip_addresses",
  size: 10,
  aggs: {
    ip_ranges: {
      ip_range: {
        field: "ip",
        ranges: [
          {
            to: "10.0.0.5",
          },
          {
            from: "10.0.0.5",
          },
        ],
      },
    },
  },
});
console.log(response);
GET /ip_addresses/_search
{
  "size": 10,
  "aggs": {
    "ip_ranges": {
      "ip_range": {
        "field": "ip",
        "ranges": [
          { "to": "10.0.0.5" },
          { "from": "10.0.0.5" }
        ]
      }
    }
  }
}

Response:

{
  ...

  "aggregations": {
    "ip_ranges": {
      "buckets": [
        {
          "key": "*-10.0.0.5",
          "to": "10.0.0.5",
          "doc_count": 10
        },
        {
          "key": "10.0.0.5-*",
          "from": "10.0.0.5",
          "doc_count": 260
        }
      ]
    }
  }
}

IP ranges can also be defined as CIDR masks:

resp = client.search(
    index="ip_addresses",
    size=0,
    aggs={
        "ip_ranges": {
            "ip_range": {
                "field": "ip",
                "ranges": [
                    {
                        "mask": "10.0.0.0/25"
                    },
                    {
                        "mask": "10.0.0.127/25"
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'ip_addresses',
  body: {
    size: 0,
    aggregations: {
      ip_ranges: {
        ip_range: {
          field: 'ip',
          ranges: [
            {
              mask: '10.0.0.0/25'
            },
            {
              mask: '10.0.0.127/25'
            }
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "ip_addresses",
  size: 0,
  aggs: {
    ip_ranges: {
      ip_range: {
        field: "ip",
        ranges: [
          {
            mask: "10.0.0.0/25",
          },
          {
            mask: "10.0.0.127/25",
          },
        ],
      },
    },
  },
});
console.log(response);
GET /ip_addresses/_search
{
  "size": 0,
  "aggs": {
    "ip_ranges": {
      "ip_range": {
        "field": "ip",
        "ranges": [
          { "mask": "10.0.0.0/25" },
          { "mask": "10.0.0.127/25" }
        ]
      }
    }
  }
}

Response:

{
  ...

  "aggregations": {
    "ip_ranges": {
      "buckets": [
        {
          "key": "10.0.0.0/25",
          "from": "10.0.0.0",
          "to": "10.0.0.128",
          "doc_count": 128
        },
        {
          "key": "10.0.0.127/25",
          "from": "10.0.0.0",
          "to": "10.0.0.128",
          "doc_count": 128
        }
      ]
    }
  }
}

Keyed Response

edit

Setting the keyed flag to true will associate a unique string key with each bucket and return the ranges as a hash rather than an array:

resp = client.search(
    index="ip_addresses",
    size=0,
    aggs={
        "ip_ranges": {
            "ip_range": {
                "field": "ip",
                "ranges": [
                    {
                        "to": "10.0.0.5"
                    },
                    {
                        "from": "10.0.0.5"
                    }
                ],
                "keyed": True
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'ip_addresses',
  body: {
    size: 0,
    aggregations: {
      ip_ranges: {
        ip_range: {
          field: 'ip',
          ranges: [
            {
              to: '10.0.0.5'
            },
            {
              from: '10.0.0.5'
            }
          ],
          keyed: true
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "ip_addresses",
  size: 0,
  aggs: {
    ip_ranges: {
      ip_range: {
        field: "ip",
        ranges: [
          {
            to: "10.0.0.5",
          },
          {
            from: "10.0.0.5",
          },
        ],
        keyed: true,
      },
    },
  },
});
console.log(response);
GET /ip_addresses/_search
{
  "size": 0,
  "aggs": {
    "ip_ranges": {
      "ip_range": {
        "field": "ip",
        "ranges": [
          { "to": "10.0.0.5" },
          { "from": "10.0.0.5" }
        ],
        "keyed": true
      }
    }
  }
}

Response:

{
  ...

  "aggregations": {
    "ip_ranges": {
      "buckets": {
        "*-10.0.0.5": {
          "to": "10.0.0.5",
          "doc_count": 10
        },
        "10.0.0.5-*": {
          "from": "10.0.0.5",
          "doc_count": 260
        }
      }
    }
  }
}

It is also possible to customize the key for each range:

resp = client.search(
    index="ip_addresses",
    size=0,
    aggs={
        "ip_ranges": {
            "ip_range": {
                "field": "ip",
                "ranges": [
                    {
                        "key": "infinity",
                        "to": "10.0.0.5"
                    },
                    {
                        "key": "and-beyond",
                        "from": "10.0.0.5"
                    }
                ],
                "keyed": True
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'ip_addresses',
  body: {
    size: 0,
    aggregations: {
      ip_ranges: {
        ip_range: {
          field: 'ip',
          ranges: [
            {
              key: 'infinity',
              to: '10.0.0.5'
            },
            {
              key: 'and-beyond',
              from: '10.0.0.5'
            }
          ],
          keyed: true
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "ip_addresses",
  size: 0,
  aggs: {
    ip_ranges: {
      ip_range: {
        field: "ip",
        ranges: [
          {
            key: "infinity",
            to: "10.0.0.5",
          },
          {
            key: "and-beyond",
            from: "10.0.0.5",
          },
        ],
        keyed: true,
      },
    },
  },
});
console.log(response);
GET /ip_addresses/_search
{
  "size": 0,
  "aggs": {
    "ip_ranges": {
      "ip_range": {
        "field": "ip",
        "ranges": [
          { "key": "infinity", "to": "10.0.0.5" },
          { "key": "and-beyond", "from": "10.0.0.5" }
        ],
        "keyed": true
      }
    }
  }
}

Response:

{
  ...

  "aggregations": {
    "ip_ranges": {
      "buckets": {
        "infinity": {
          "to": "10.0.0.5",
          "doc_count": 10
        },
        "and-beyond": {
          "from": "10.0.0.5",
          "doc_count": 260
        }
      }
    }
  }
}