This is an automated email from the ASF dual-hosted git repository.

sergehuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/master by this push:
     new 429ea21d5 UNOMI-1022: Document IP range aggregates and how to read 
aggregate results (#927)
429ea21d5 is described below

commit 429ea21d5ae6210f51559bfa914ab9feeb960b45
Author: Serge Huber <[email protected]>
AuthorDate: Tue Oct 27 10:34:37 2026 +0100

    UNOMI-1022: Document IP range aggregates and how to read aggregate results 
(#927)
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../main/asciidoc/queries-and-aggregations.adoc    | 107 +++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/manual/src/main/asciidoc/queries-and-aggregations.adoc 
b/manual/src/main/asciidoc/queries-and-aggregations.adoc
index d2fe43fbc..d748e98c3 100644
--- a/manual/src/main/asciidoc/queries-and-aggregations.adoc
+++ b/manual/src/main/asciidoc/queries-and-aggregations.adoc
@@ -200,6 +200,25 @@ The above request will produce a similar that looks like 
this:
 
 You can see that we retrieve the count of newcomers aggregated by day.
 
+The `interval` parameter accepts the following values, in short or named form. 
It defaults to a month (`1M`).
+
+[cols="1,1"]
+|===
+| Short form | Named form
+
+| `1s` | `Second`
+| `1m` | `Minute`
+| `1h` | `Hour`
+| `1d` | `Day`
+| `1w` | `Week`
+| `1M` | `Month`
+| `1q` | `Quarter`
+| `1y` | `Year`
+|===
+
+Other values, such as `2d` or `day`, are not supported. The optional `format` 
parameter sets how the date of each
+bucket is written in the result keys, as in the `yyyy-MM-dd` keys above.
+
 ===== Date range
 
 Date ranges make it possible to "bucket" dates, for example to regroup 
profiles by their birth date as in the example
@@ -273,6 +292,9 @@ The resulting JSON response will look something like this:
 }
 ----
 
+Each range includes its `from` date and excludes its `to` date. Set `from` or 
`to` to `null` for a range that is open on
+that side. The same rules apply to numeric and IP ranges.
+
 You can find more information about the date range formats here:
 - Elasticsearch documentation: 
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html[Date
 range aggregation (Elasticsearch current)]
 - OpenSearch documentation: 
https://docs.opensearch.org/docs/latest/aggregations/bucket/date-range/[Date 
range aggregation (OpenSearch)]
@@ -352,6 +374,91 @@ This will produce an output that looks like this:
 }
 ----
 
+Ranges may overlap: a value is counted in every range it falls in.
+
+===== IP range
+
+IP ranges make it possible to "bucket" IP addresses, for example to tell 
internal visitors from external ones. IPv4 and
+IPv6 addresses are both supported. The property must be mapped as an `ip` 
field in the search engine before its data
+is indexed. No property is mapped that way by default, so add that mapping 
yourself for the property you aggregate on.
+
+Here's an example that groups sessions by a custom `properties.remoteIp` 
property:
+
+[source,shell script]
+----
+curl -X POST http://localhost:8181/cxs/query/session/properties.remoteIp \
+--user "TENANT_ID:PRIVATE_KEY" \
+-H "Content-Type: application/json" \
+-d @- <<'EOF'
+{
+  "aggregate": {
+    "property": "properties.remoteIp",
+    "type": "ipRange",
+    "ipRanges": [
+      {
+        "key": "Internal",
+        "from": "10.0.0.0",
+        "to": "11.0.0.0"
+      },
+      {
+        "key": "Loopback",
+        "from": "127.0.0.0",
+        "to": "128.0.0.0"
+      },
+      {
+        "from": "192.168.0.0",
+        "to": "192.169.0.0"
+      }
+    ]
+  },
+  "condition": {
+    "type": "matchAllCondition",
+    "parameterValues": {}
+  }
+}
+EOF
+----
+
+This will produce an output that looks like this:
+
+[source,json]
+----
+{
+    "_all":2310,
+    "_filtered":2310,
+    "Internal":1207,
+    "Loopback":12,
+    "192.168.0.0-192.169.0.0":340,
+    "_missing":64
+}
+----
+
+A range without a `key` is reported as `from-to`, as for the last range above.
+
+==== Reading the results
+
+The result of an aggregate query is a JSON object that maps each bucket key to 
the number of items in that bucket. A
+few keys starting with an underscore hold counts of their own:
+
+`_all`:: The number of items of the requested type in the current tenant. 
Counting every item takes extra time, so it
+is not returned when the `optimizedQuery=true` query parameter is set (as in
+`POST /cxs/query/profile/properties.nbOfVisits?optimizedQuery=true`), nor for 
`GET` aggregate queries.
+`_filtered`:: The number of items that match the condition. Without 
`optimizedQuery=true`, it is only returned when the
+request has a condition.
+`_missing`:: The number of matching items that have no value for the 
aggregated property. It is only returned when there
+are such items.
+
+The bucket keys depend on the aggregation type:
+
+* When the request has no `aggregate`, or one without a `type`, the keys are 
the values of the property.
+* For a date aggregation, the keys are the dates of the buckets, written with 
the `format` parameter when it is set.
+  Periods with no items between the first and the last bucket are included, 
with a count of `0`.
+* For a range aggregation, the keys are the `key` of each range. A range 
without a `key` is reported as `from-to`, with
+  `*` for an open side, for example `*-5.0` or `100.0-*`. Every range is 
reported, even with a count of `0`.
+
+A bucket whose key is `_all`, `_filtered` or `_missing` is dropped, because 
those keys are reserved for the counts
+above.
+
 === Scroll Queries
 
 Scroll queries are useful when you need to retrieve large result sets 
efficiently. Instead of retrieving all results at once,

Reply via email to