diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/delta.md b/docs/reference/query-languages/esql/_snippets/functions/description/delta.md new file mode 100644 index 0000000000000..3f671ca39a6b4 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/description/delta.md @@ -0,0 +1,11 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Description** + +Calculates the absolute change of a gauge field in a time window. + +::::{note} +Available with the [TS](/reference/query-languages/esql/commands/source-commands.md#esql-ts) command +:::: + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/idelta.md b/docs/reference/query-languages/esql/_snippets/functions/description/idelta.md new file mode 100644 index 0000000000000..d688ba38f3530 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/description/idelta.md @@ -0,0 +1,6 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Description** + +Calculates the idelta of a gauge. idelta is the absolute change between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to delta, but is more responsive to recent changes. + diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/increase.md b/docs/reference/query-languages/esql/_snippets/functions/description/increase.md new file mode 100644 index 0000000000000..8d9e5bf61575c --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/description/increase.md @@ -0,0 +1,6 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Description** + +Calculates the absolute increase of a counter field in a time window. + diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/irate.md b/docs/reference/query-languages/esql/_snippets/functions/description/irate.md new file mode 100644 index 0000000000000..2b89845926c89 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/description/irate.md @@ -0,0 +1,6 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Description** + +Calculates the irate of a counter field. irate is the per-second rate of increase between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to rate, but is more responsive to recent changes in the rate of increase. + diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/delta.md b/docs/reference/query-languages/esql/_snippets/functions/examples/delta.md new file mode 100644 index 0000000000000..2ce7829aa9ea5 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/delta.md @@ -0,0 +1,18 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Example** + +```esql +TS k8s +| WHERE pod == "one" +| STATS tx = sum(delta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` + +| tx:double | cluster:keyword | time_bucket:datetime | +| --- | --- | --- | +| -351.0 | prod | 2024-05-10T00:00:00.000Z | +| 552.0 | qa | 2024-05-10T00:00:00.000Z | +| 127.0 | staging | 2024-05-10T00:00:00.000Z | +| 280.0 | prod | 2024-05-10T00:10:00.000Z | + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/idelta.md b/docs/reference/query-languages/esql/_snippets/functions/examples/idelta.md new file mode 100644 index 0000000000000..66de049e6b06b --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/idelta.md @@ -0,0 +1,17 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Example** + +```esql +TS k8s +| STATS events = sum(idelta(events_received)) by pod, time_bucket = bucket(@timestamp, 10minute) +``` + +| events:double | pod:keyword | time_bucket:datetime | +| --- | --- | --- | +| 9.0 | one | 2024-05-10T00:10:00.000Z | +| 7.0 | three | 2024-05-10T00:10:00.000Z | +| 3.0 | two | 2024-05-10T00:00:00.000Z | +| 0.0 | two | 2024-05-10T00:20:00.000Z | + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/increase.md b/docs/reference/query-languages/esql/_snippets/functions/examples/increase.md new file mode 100644 index 0000000000000..0c2a97f9c9de8 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/increase.md @@ -0,0 +1,17 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Example** + +```esql +TS k8s +| WHERE pod == "one" +| STATS increase_bytes_in = sum(increase(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` + +| increase_bytes_in:double | cluster:keyword | time_bucket:datetime | +| --- | --- | --- | +| 2418.8749174917493 | prod | 2024-05-10T00:00:00.000Z | +| 5973.5 | qa | 2024-05-10T00:00:00.000Z | +| 2545.467283950617 | staging | 2024-05-10T00:00:00.000Z | + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/irate.md b/docs/reference/query-languages/esql/_snippets/functions/examples/irate.md new file mode 100644 index 0000000000000..2c119934d61e0 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/irate.md @@ -0,0 +1,18 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Example** + +```esql +TS k8s | WHERE pod == "one" +| STATS irate_bytes_in = sum(irate(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` + +| irate_bytes_in:double | cluster:keyword | time_bucket:datetime | +| --- | --- | --- | +| 0.07692307692307693 | prod | 2024-05-10T00:00:00.000Z | +| 830.0 | qa | 2024-05-10T00:00:00.000Z | +| 31.375 | staging | 2024-05-10T00:00:00.000Z | +| 9.854545454545454 | prod | 2024-05-10T00:10:00.000Z | +| 18.700000000000003 | qa | 2024-05-10T00:10:00.000Z | + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/delta.md b/docs/reference/query-languages/esql/_snippets/functions/layout/delta.md new file mode 100644 index 0000000000000..47d2559be3d10 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/layout/delta.md @@ -0,0 +1,27 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +## `DELTA` [esql-delta] +```{applies_to} +stack: preview 9.2.0 +serverless: preview +``` + +**Syntax** + +:::{image} ../../../images/functions/delta.svg +:alt: Embedded +:class: text-center +::: + + +:::{include} ../parameters/delta.md +::: + +:::{include} ../description/delta.md +::: + +:::{include} ../types/delta.md +::: + +:::{include} ../examples/delta.md +::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/idelta.md b/docs/reference/query-languages/esql/_snippets/functions/layout/idelta.md new file mode 100644 index 0000000000000..04af14eae131e --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/layout/idelta.md @@ -0,0 +1,27 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +## `IDELTA` [esql-idelta] +```{applies_to} +stack: preview 9.2.0 +serverless: preview +``` + +**Syntax** + +:::{image} ../../../images/functions/idelta.svg +:alt: Embedded +:class: text-center +::: + + +:::{include} ../parameters/idelta.md +::: + +:::{include} ../description/idelta.md +::: + +:::{include} ../types/idelta.md +::: + +:::{include} ../examples/idelta.md +::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/increase.md b/docs/reference/query-languages/esql/_snippets/functions/layout/increase.md new file mode 100644 index 0000000000000..f3381ace15732 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/layout/increase.md @@ -0,0 +1,27 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +## `INCREASE` [esql-increase] +```{applies_to} +stack: preview 9.2.0 +serverless: preview +``` + +**Syntax** + +:::{image} ../../../images/functions/increase.svg +:alt: Embedded +:class: text-center +::: + + +:::{include} ../parameters/increase.md +::: + +:::{include} ../description/increase.md +::: + +:::{include} ../types/increase.md +::: + +:::{include} ../examples/increase.md +::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/irate.md b/docs/reference/query-languages/esql/_snippets/functions/layout/irate.md new file mode 100644 index 0000000000000..b2c1ae1adcc41 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/layout/irate.md @@ -0,0 +1,27 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +## `IRATE` [esql-irate] +```{applies_to} +stack: preview 9.2.0 +serverless: preview +``` + +**Syntax** + +:::{image} ../../../images/functions/irate.svg +:alt: Embedded +:class: text-center +::: + + +:::{include} ../parameters/irate.md +::: + +:::{include} ../description/irate.md +::: + +:::{include} ../types/irate.md +::: + +:::{include} ../examples/irate.md +::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/delta.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/delta.md new file mode 100644 index 0000000000000..24fedc1dde506 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/delta.md @@ -0,0 +1,7 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Parameters** + +`field` +: + diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/idelta.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/idelta.md new file mode 100644 index 0000000000000..24fedc1dde506 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/idelta.md @@ -0,0 +1,7 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Parameters** + +`field` +: + diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/increase.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/increase.md new file mode 100644 index 0000000000000..24fedc1dde506 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/increase.md @@ -0,0 +1,7 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Parameters** + +`field` +: + diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/irate.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/irate.md new file mode 100644 index 0000000000000..24fedc1dde506 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/irate.md @@ -0,0 +1,7 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Parameters** + +`field` +: + diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/delta.md b/docs/reference/query-languages/esql/_snippets/functions/types/delta.md new file mode 100644 index 0000000000000..566f6b3d786f6 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/types/delta.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Supported types** + +| field | result | +| --- | --- | +| double | double | +| integer | double | +| long | double | + diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/idelta.md b/docs/reference/query-languages/esql/_snippets/functions/types/idelta.md new file mode 100644 index 0000000000000..566f6b3d786f6 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/types/idelta.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Supported types** + +| field | result | +| --- | --- | +| double | double | +| integer | double | +| long | double | + diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/increase.md b/docs/reference/query-languages/esql/_snippets/functions/types/increase.md new file mode 100644 index 0000000000000..0def3f10bc69b --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/types/increase.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Supported types** + +| field | result | +| --- | --- | +| counter_double | double | +| counter_integer | double | +| counter_long | double | + diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/irate.md b/docs/reference/query-languages/esql/_snippets/functions/types/irate.md new file mode 100644 index 0000000000000..0def3f10bc69b --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/types/irate.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Supported types** + +| field | result | +| --- | --- | +| counter_double | double | +| counter_integer | double | +| counter_long | double | + diff --git a/docs/reference/query-languages/esql/images/functions/delta.svg b/docs/reference/query-languages/esql/images/functions/delta.svg new file mode 100644 index 0000000000000..7f6ed0e3f3282 --- /dev/null +++ b/docs/reference/query-languages/esql/images/functions/delta.svg @@ -0,0 +1 @@ +DELTA(field) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/images/functions/idelta.svg b/docs/reference/query-languages/esql/images/functions/idelta.svg new file mode 100644 index 0000000000000..72dcdfd4ac244 --- /dev/null +++ b/docs/reference/query-languages/esql/images/functions/idelta.svg @@ -0,0 +1 @@ +IDELTA(field) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/images/functions/increase.svg b/docs/reference/query-languages/esql/images/functions/increase.svg new file mode 100644 index 0000000000000..f8f4167cf8960 --- /dev/null +++ b/docs/reference/query-languages/esql/images/functions/increase.svg @@ -0,0 +1 @@ +INCREASE(field) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/images/functions/irate.svg b/docs/reference/query-languages/esql/images/functions/irate.svg new file mode 100644 index 0000000000000..30a0d568ea7a0 --- /dev/null +++ b/docs/reference/query-languages/esql/images/functions/irate.svg @@ -0,0 +1 @@ +IRATE(field) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/delta.json b/docs/reference/query-languages/esql/kibana/definition/functions/delta.json new file mode 100644 index 0000000000000..257cfd79c92e1 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/definition/functions/delta.json @@ -0,0 +1,50 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", + "type" : "time_series_agg", + "name" : "delta", + "description" : "Calculates the absolute change of a gauge field in a time window.", + "note" : "Available with the TS command", + "signatures" : [ + { + "params" : [ + { + "name" : "field", + "type" : "double", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "integer", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "long", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + } + ], + "examples" : [ + "TS k8s\n| WHERE pod == \"one\"\n| STATS tx = sum(delta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute)" + ], + "preview" : true, + "snapshot_only" : false +} diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/idelta.json b/docs/reference/query-languages/esql/kibana/definition/functions/idelta.json new file mode 100644 index 0000000000000..35e5c0d1b3a2b --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/definition/functions/idelta.json @@ -0,0 +1,49 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", + "type" : "time_series_agg", + "name" : "idelta", + "description" : "Calculates the idelta of a gauge. idelta is the absolute change between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to delta, but is more responsive to recent changes.", + "signatures" : [ + { + "params" : [ + { + "name" : "field", + "type" : "double", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "integer", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "long", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + } + ], + "examples" : [ + "TS k8s\n| STATS events = sum(idelta(events_received)) by pod, time_bucket = bucket(@timestamp, 10minute)" + ], + "preview" : true, + "snapshot_only" : false +} diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/increase.json b/docs/reference/query-languages/esql/kibana/definition/functions/increase.json new file mode 100644 index 0000000000000..392502d89e278 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/definition/functions/increase.json @@ -0,0 +1,49 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", + "type" : "time_series_agg", + "name" : "increase", + "description" : "Calculates the absolute increase of a counter field in a time window.", + "signatures" : [ + { + "params" : [ + { + "name" : "field", + "type" : "counter_double", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "counter_integer", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "counter_long", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + } + ], + "examples" : [ + "TS k8s\n| WHERE pod == \"one\"\n| STATS increase_bytes_in = sum(increase(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute)" + ], + "preview" : true, + "snapshot_only" : false +} diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/irate.json b/docs/reference/query-languages/esql/kibana/definition/functions/irate.json new file mode 100644 index 0000000000000..c164d5a4f2b96 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/definition/functions/irate.json @@ -0,0 +1,49 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", + "type" : "time_series_agg", + "name" : "irate", + "description" : "Calculates the irate of a counter field. irate is the per-second rate of increase between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to rate, but is more responsive to recent changes in the rate of increase.", + "signatures" : [ + { + "params" : [ + { + "name" : "field", + "type" : "counter_double", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "counter_integer", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + }, + { + "params" : [ + { + "name" : "field", + "type" : "counter_long", + "optional" : false, + "description" : "" + } + ], + "variadic" : false, + "returnType" : "double" + } + ], + "examples" : [ + "TS k8s | WHERE pod == \"one\"\n| STATS irate_bytes_in = sum(irate(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute)" + ], + "preview" : true, + "snapshot_only" : false +} diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/delta.md b/docs/reference/query-languages/esql/kibana/docs/functions/delta.md new file mode 100644 index 0000000000000..ccc36929a2579 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/docs/functions/delta.md @@ -0,0 +1,12 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +### DELTA +Calculates the absolute change of a gauge field in a time window. + +Note: Available with the [TS](https://www.elastic.co/docs/reference/query-languages/esql/commands/source-commands#esql-ts) command + +```esql +TS k8s +| WHERE pod == "one" +| STATS tx = sum(delta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/idelta.md b/docs/reference/query-languages/esql/kibana/docs/functions/idelta.md new file mode 100644 index 0000000000000..046984e3bf09f --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/docs/functions/idelta.md @@ -0,0 +1,9 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +### IDELTA +Calculates the idelta of a gauge. idelta is the absolute change between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to delta, but is more responsive to recent changes. + +```esql +TS k8s +| STATS events = sum(idelta(events_received)) by pod, time_bucket = bucket(@timestamp, 10minute) +``` diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/increase.md b/docs/reference/query-languages/esql/kibana/docs/functions/increase.md new file mode 100644 index 0000000000000..9aaa59619d8e2 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/docs/functions/increase.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +### INCREASE +Calculates the absolute increase of a counter field in a time window. + +```esql +TS k8s +| WHERE pod == "one" +| STATS increase_bytes_in = sum(increase(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/irate.md b/docs/reference/query-languages/esql/kibana/docs/functions/irate.md new file mode 100644 index 0000000000000..d80ec203cb999 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/docs/functions/irate.md @@ -0,0 +1,9 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +### IRATE +Calculates the irate of a counter field. irate is the per-second rate of increase between the last two data points (it ignores all but the last two data points in each time period). This function is very similar to rate, but is more responsive to recent changes in the rate of increase. + +```esql +TS k8s | WHERE pod == "one" +| STATS irate_bytes_in = sum(irate(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +``` diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateDoubleAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateDoubleAggregator.java index e6ede3a386090..ee4299e12c306 100644 --- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateDoubleAggregator.java +++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateDoubleAggregator.java @@ -45,6 +45,10 @@ public static void combine(DoubleIrateGroupingState current, int groupId, double current.append(groupId, timestamp, value); } + public static String describe() { + return "instant change of doubles"; + } + public static void combineIntermediate( DoubleIrateGroupingState current, int groupId, diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateFloatAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateFloatAggregator.java index f5f1cf9a7cbca..8f605602eea73 100644 --- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateFloatAggregator.java +++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateFloatAggregator.java @@ -45,6 +45,10 @@ public static void combine(FloatIrateGroupingState current, int groupId, float v current.append(groupId, timestamp, value); } + public static String describe() { + return "instant change of floats"; + } + public static void combineIntermediate( FloatIrateGroupingState current, int groupId, diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateIntAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateIntAggregator.java index 2266d4b353258..e7e974d768286 100644 --- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateIntAggregator.java +++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateIntAggregator.java @@ -45,6 +45,10 @@ public static void combine(IntIrateGroupingState current, int groupId, int value current.append(groupId, timestamp, value); } + public static String describe() { + return "instant change of ints"; + } + public static void combineIntermediate( IntIrateGroupingState current, int groupId, diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateLongAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateLongAggregator.java index f4077febdc8ff..8e0b5852c1feb 100644 --- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateLongAggregator.java +++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/IrateLongAggregator.java @@ -45,6 +45,10 @@ public static void combine(LongIrateGroupingState current, int groupId, long val current.append(groupId, timestamp, value); } + public static String describe() { + return "instant change of longs"; + } + public static void combineIntermediate( LongIrateGroupingState current, int groupId, diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateDoubleAggregatorFunctionSupplier.java index cbae61ec86f2f..b90c25a2948e7 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateDoubleAggregatorFunctionSupplier.java @@ -44,6 +44,6 @@ public IrateDoubleGroupingAggregatorFunction groupingAggregator(DriverContext dr @Override public String describe() { - return "irate of doubles"; + return IrateDoubleAggregator.describe(); } } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateFloatAggregatorFunctionSupplier.java index 421dc0429b8a6..53ddd8bcedcb0 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateFloatAggregatorFunctionSupplier.java @@ -44,6 +44,6 @@ public IrateFloatGroupingAggregatorFunction groupingAggregator(DriverContext dri @Override public String describe() { - return "irate of floats"; + return IrateFloatAggregator.describe(); } } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateIntAggregatorFunctionSupplier.java index 67da60d690b48..b8bf32a476b3a 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateIntAggregatorFunctionSupplier.java @@ -44,6 +44,6 @@ public IrateIntGroupingAggregatorFunction groupingAggregator(DriverContext drive @Override public String describe() { - return "irate of ints"; + return IrateIntAggregator.describe(); } } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateLongAggregatorFunctionSupplier.java index 382eb905bd964..fb2799abaeb42 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/IrateLongAggregatorFunctionSupplier.java @@ -44,6 +44,6 @@ public IrateLongGroupingAggregatorFunction groupingAggregator(DriverContext driv @Override public String describe() { - return "irate of longs"; + return IrateLongAggregator.describe(); } } diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-IrateAggregator.java.st b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-IrateAggregator.java.st index 3b94d339d0093..9c7a03c008dfc 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-IrateAggregator.java.st +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-IrateAggregator.java.st @@ -45,6 +45,10 @@ public class Irate$Type$Aggregator { current.append(groupId, timestamp, value); } + public static String describe() { + return "instant change of $type$s"; + } + public static void combineIntermediate( $Type$IrateGroupingState current, int groupId, diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-delta.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-delta.csv-spec index a289a38bb9a45..95c0ef447ede5 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-delta.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-delta.csv-spec @@ -1,16 +1,20 @@ delta_of_double_no_grouping required_capability: ts_command_v0 required_capability: delta_ts_agg +// tag::delta[] TS k8s | STATS cost_change=sum(delta(network.cost)) BY time_bucket = bucket(@timestamp,1minute) +// end::delta[] | SORT cost_change DESC, time_bucket DESC | LIMIT 10; +// tag::delta-result[] cost_change:double | time_bucket:datetime null | 2024-05-10T00:01:00.000Z 22.5701486013986 | 2024-05-10T00:20:00.000Z 13.259615384615385 | 2024-05-10T00:13:00.000Z 11.486895161290322 | 2024-05-10T00:12:00.000Z 11.066666666666666 | 2024-05-10T00:21:00.000Z +// end::delta-result[] 11.0625 | 2024-05-10T00:22:00.000Z 9.222489316239315 | 2024-05-10T00:09:00.000Z 6.991071428571427 | 2024-05-10T00:15:00.000Z @@ -62,13 +66,20 @@ null | prod | 2024-05-10T00:03:00.000Z delta_with_filtering required_capability: ts_command_v0 required_capability: delta_ts_agg -TS k8s | WHERE pod == "one" | STATS tx = sum(delta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) | SORT time_bucket, cluster | LIMIT 10; +// tag::delta[] +TS k8s +| WHERE pod == "one" +| STATS tx = sum(delta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +// end::delta[] +| SORT time_bucket, cluster | LIMIT 10; +// tag::delta-result[] tx:double | cluster:keyword | time_bucket:datetime -351.0 | prod | 2024-05-10T00:00:00.000Z 552.0 | qa | 2024-05-10T00:00:00.000Z 127.0 | staging | 2024-05-10T00:00:00.000Z 280.0 | prod | 2024-05-10T00:10:00.000Z +// end::delta-result[] 73.0 | qa | 2024-05-10T00:10:00.000Z -600.0 | staging | 2024-05-10T00:10:00.000Z -22.0 | prod | 2024-05-10T00:20:00.000Z @@ -79,7 +90,9 @@ tx:double | cluster:keyword | time_bucket:datetime delta_with_inline_filtering required_capability: ts_command_v0 required_capability: delta_ts_agg -TS k8s | STATS tx = sum(delta(network.bytes_in)) WHERE pod == "one" BY cluster, time_bucket = bucket(@timestamp, 10minute) | SORT time_bucket, cluster | LIMIT 10; +TS k8s +| STATS tx = sum(delta(network.bytes_in)) WHERE pod == "one" BY cluster, time_bucket = bucket(@timestamp, 10minute) +| SORT time_bucket, cluster | LIMIT 10; tx:double | cluster:keyword | time_bucket:datetime -351.0 | prod | 2024-05-10T00:00:00.000Z diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-idelta.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-idelta.csv-spec index f683017f1f2ea..ae2596da2461b 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-idelta.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-idelta.csv-spec @@ -54,13 +54,20 @@ null | prod | 2024-05-10T00:03:00.000Z idelta_with_filtering required_capability: ts_command_v0 -TS k8s | WHERE pod == "one" | STATS tx = sum(idelta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) | SORT time_bucket, cluster | LIMIT 10; +// tag::idelta[] +TS k8s +| WHERE pod == "one" +| STATS tx = sum(idelta(network.bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +// end::idelta[] +| SORT time_bucket, cluster | LIMIT 10; +// tag::idelta-result[] tx:double | cluster:keyword | time_bucket:datetime -224.0 | prod | 2024-05-10T00:00:00.000Z 791.0 | qa | 2024-05-10T00:00:00.000Z 534.0 | staging | 2024-05-10T00:00:00.000Z -448.0 | prod | 2024-05-10T00:10:00.000Z +// end::idelta-result[] -560.0 | qa | 2024-05-10T00:10:00.000Z -512.0 | staging | 2024-05-10T00:10:00.000Z 915.0 | prod | 2024-05-10T00:20:00.000Z @@ -70,7 +77,9 @@ tx:double | cluster:keyword | time_bucket:datetime idelta_with_inline_filtering required_capability: ts_command_v0 -TS k8s | STATS tx = sum(idelta(network.bytes_in)) WHERE pod == "one" BY cluster, time_bucket = bucket(@timestamp, 10minute) | SORT time_bucket, cluster | LIMIT 10; +TS k8s +| STATS tx = sum(idelta(network.bytes_in)) WHERE pod == "one" BY cluster, time_bucket = bucket(@timestamp, 10minute) +| SORT time_bucket, cluster | LIMIT 10; tx:double | cluster:keyword | time_bucket:datetime -224.0 | prod | 2024-05-10T00:00:00.000Z @@ -144,13 +153,19 @@ null | two | 2024-05-10T00:13:00.000Z idelta_all_value_types required_capability: ts_command_v0 required_capability: k8s_dataset_additional_fields -TS k8s | STATS events = sum(idelta(events_received)) by pod, time_bucket = bucket(@timestamp, 10minute) | SORT events desc, pod, time_bucket | LIMIT 10 ; +// tag::idelta[] +TS k8s +| STATS events = sum(idelta(events_received)) by pod, time_bucket = bucket(@timestamp, 10minute) +// end::idelta[] +| SORT events desc, pod, time_bucket | LIMIT 10 ; +// tag::idelta-result[] events:double | pod:keyword | time_bucket:datetime 9.0 | one | 2024-05-10T00:10:00.000Z 7.0 | three | 2024-05-10T00:10:00.000Z 3.0 | two | 2024-05-10T00:00:00.000Z 0.0 | two | 2024-05-10T00:20:00.000Z +// end::idelta-result[] -2.0 | three | 2024-05-10T00:20:00.000Z -2.0 | two | 2024-05-10T00:10:00.000Z -4.0 | one | 2024-05-10T00:20:00.000Z diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-increase.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-increase.csv-spec index c1a3f8af62665..4fbd1f29c9c1f 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-increase.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-increase.csv-spec @@ -2,15 +2,19 @@ increase_of_long_no_grouping required_capability: increase required_capability: ts_command_v0 +// tag::increase[] TS k8s | STATS increase_bytes_in=avg(increase(network.total_bytes_in)) BY time_bucket = bucket(@timestamp,1minute) +// end::increase[] | SORT increase_bytes_in DESC, time_bucket DESC | LIMIT 10; +// tag::increase-result[] increase_bytes_in:double | time_bucket:datetime null | 2024-05-10T00:01:00.000Z 1728.1785714285716 | 2024-05-10T00:15:00.000Z 1525.3333333333335 | 2024-05-10T00:04:00.000Z 1457.3676470588234 | 2024-05-10T00:19:00.000Z +// end::increase-result[] 1443.333333333333 | 2024-05-10T00:10:00.000Z 1352.8076923076924 | 2024-05-10T00:13:00.000Z 1262.3891797611566 | 2024-05-10T00:17:00.000Z @@ -64,14 +68,19 @@ null | 2024-05-10T00:01:00.000Z increase_with_filtering required_capability: increase required_capability: ts_command_v0 -TS k8s | WHERE pod == "one" +// tag::increase[] +TS k8s +| WHERE pod == "one" | STATS increase_bytes_in = sum(increase(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +// end::increase[] | SORT time_bucket, cluster | LIMIT 10; +// tag::increase-result[] increase_bytes_in:double | cluster:keyword | time_bucket:datetime 2418.8749174917493 | prod | 2024-05-10T00:00:00.000Z 5973.5 | qa | 2024-05-10T00:00:00.000Z 2545.467283950617 | staging | 2024-05-10T00:00:00.000Z +// end::increase-result[] 6713.028169014084 | prod | 2024-05-10T00:10:00.000Z 7333.555555555556 | qa | 2024-05-10T00:10:00.000Z 1830.2228941684662 | staging | 2024-05-10T00:10:00.000Z diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-irate.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-irate.csv-spec index 97c1b7a27ef14..697ec29bf888e 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-irate.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/k8s-timeseries-irate.csv-spec @@ -1,9 +1,12 @@ irate_of_long_no_grouping required_capability: ts_command_v0 +// tag::irate[] TS k8s | STATS irate_bytes_in=avg(irate(network.total_bytes_in)) BY time_bucket = bucket(@timestamp,1minute) +// end::irate[] | SORT irate_bytes_in DESC, time_bucket DESC | LIMIT 10; +// tag::irate-result[] irate_bytes_in:double | time_bucket:datetime null | 2024-05-10T00:01:00.000Z 140.58333333333331 | 2024-05-10T00:02:00.000Z @@ -11,6 +14,7 @@ null | 2024-05-10T00:01:00.000Z 116.41911764705883 | 2024-05-10T00:22:00.000Z 112.83333333333333 | 2024-05-10T00:00:00.000Z 93.43529411764706 | 2024-05-10T00:14:00.000Z +// end::irate-result[] 88.6875 | 2024-05-10T00:11:00.000Z 78.83333333333333 | 2024-05-10T00:13:00.000Z 71.04464285714286 | 2024-05-10T00:15:00.000Z @@ -61,16 +65,20 @@ null | 2024-05-10T00:01:00.000Z irate_with_filtering required_capability: ts_command_v0 +// tag::irate[] TS k8s | WHERE pod == "one" | STATS irate_bytes_in = sum(irate(network.total_bytes_in)) BY cluster, time_bucket = bucket(@timestamp, 10minute) +// end::irate[] | SORT time_bucket, cluster | LIMIT 10; +// tag::irate-result[] irate_bytes_in:double | cluster:keyword | time_bucket:datetime 0.07692307692307693 | prod | 2024-05-10T00:00:00.000Z 830.0 | qa | 2024-05-10T00:00:00.000Z 31.375 | staging | 2024-05-10T00:00:00.000Z 9.854545454545454 | prod | 2024-05-10T00:10:00.000Z 18.700000000000003 | qa | 2024-05-10T00:10:00.000Z +// end::irate-result[] 0.023952095808383235 | staging | 2024-05-10T00:10:00.000Z 232.75 | prod | 2024-05-10T00:20:00.000Z 3.2698412698412698 | qa | 2024-05-10T00:20:00.000Z diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Delta.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Delta.java index d6455990299a4..0b0ecda75b61d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Delta.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Delta.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; @@ -47,6 +48,7 @@ public class Delta extends TimeSeriesAggregateFunction implements OptionalArgume description = "Calculates the absolute change of a gauge field in a time window.", appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.2.0") }, preview = true, + examples = { @Example(file = "k8s-timeseries-delta", tag = "delta") }, note = "Available with the [TS](/reference/query-languages/esql/commands/source-commands.md#esql-ts) command" ) public Delta(Source source, @Param(name = "field", type = { "long", "integer", "double" }) Expression field) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Idelta.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Idelta.java index bfd70f17df693..a6950439e541f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Idelta.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Idelta.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; @@ -48,7 +49,8 @@ public class Idelta extends TimeSeriesAggregateFunction implements OptionalArgum + "it ignores all but the last two data points in each time period). " + "This function is very similar to delta, but is more responsive to recent changes.", appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.2.0") }, - preview = true + preview = true, + examples = { @Example(file = "k8s-timeseries-idelta", tag = "idelta") } ) public Idelta(Source source, @Param(name = "field", type = { "long", "integer", "double" }) Expression field) { this(source, field, new UnresolvedAttribute(source, "@timestamp")); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Increase.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Increase.java index cfdb3123685b6..eb5089b86f0fe 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Increase.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Increase.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; @@ -51,7 +52,8 @@ public class Increase extends TimeSeriesAggregateFunction implements OptionalArg returnType = { "double" }, description = "Calculates the absolute increase of a counter field in a time window.", appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.2.0") }, - preview = true + preview = true, + examples = { @Example(file = "k8s-timeseries-increase", tag = "increase") } ) public Increase( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Irate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Irate.java index 3705b3e0a496f..d75e4456f7f06 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Irate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Irate.java @@ -49,7 +49,7 @@ public class Irate extends TimeSeriesAggregateFunction implements OptionalArgume + "This function is very similar to rate, but is more responsive to recent changes in the rate of increase.", appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.2.0") }, preview = true, - examples = { @Example(file = "k8s-timeseries", tag = "irate") } + examples = { @Example(file = "k8s-timeseries-irate", tag = "irate") } ) public Irate(Source source, @Param(name = "field", type = { "counter_long", "counter_integer", "counter_double" }) Expression field) { this(source, field, new UnresolvedAttribute(source, "@timestamp")); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/DeltaTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/DeltaTests.java new file mode 100644 index 0000000000000..fb9d6fe29a0ec --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/DeltaTests.java @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.aggregate; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class DeltaTests extends AbstractAggregationTestCase { + public DeltaTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @ParametersFactory + public static Iterable parameters() { + var suppliers = new ArrayList(); + + var valuesSuppliers = List.of( + MultiRowTestCaseSupplier.longCases(1, 1000, -1000_000_000, 1000_000_000, false), + MultiRowTestCaseSupplier.intCases(1, 1000, -1000_000_000, 1000_000_000, false), + MultiRowTestCaseSupplier.doubleCases(1, 1000, -1000_000_000, 1000_000_000, false) + + ); + for (List valuesSupplier : valuesSuppliers) { + for (TestCaseSupplier.TypedDataSupplier fieldSupplier : valuesSupplier) { + TestCaseSupplier testCaseSupplier = makeSupplier(fieldSupplier); + suppliers.add(testCaseSupplier); + } + } + return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(suppliers); + } + + @Override + protected Expression build(Source source, List args) { + return new Delta(source, args.get(0), args.get(1)); + } + + @Override + public void testAggregate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateToString() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateIntermediate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + private static TestCaseSupplier makeSupplier(TestCaseSupplier.TypedDataSupplier fieldSupplier) { + DataType type = fieldSupplier.type(); + return new TestCaseSupplier(fieldSupplier.name(), List.of(type, DataType.DATETIME, DataType.INTEGER, DataType.LONG), () -> { + TestCaseSupplier.TypedData fieldTypedData = fieldSupplier.get(); + List dataRows = fieldTypedData.multiRowData(); + if (randomBoolean()) { + List withNulls = new ArrayList<>(dataRows.size()); + for (Object dataRow : dataRows) { + if (randomBoolean()) { + withNulls.add(null); + } else { + withNulls.add(dataRow); + } + } + dataRows = withNulls; + } + fieldTypedData = TestCaseSupplier.TypedData.multiRow(dataRows, type, fieldTypedData.name()); + List timestamps = new ArrayList<>(); + List slices = new ArrayList<>(); + List maxTimestamps = new ArrayList<>(); + long lastTimestamp = randomLongBetween(0, 1_000_000); + for (int row = 0; row < dataRows.size(); row++) { + lastTimestamp += randomLongBetween(1, 10_000); + timestamps.add(lastTimestamp); + slices.add(0); + maxTimestamps.add(Long.MAX_VALUE); + } + TestCaseSupplier.TypedData timestampsField = TestCaseSupplier.TypedData.multiRow( + timestamps.reversed(), + DataType.DATETIME, + "timestamps" + ); + TestCaseSupplier.TypedData sliceIndexType = TestCaseSupplier.TypedData.multiRow(slices, DataType.INTEGER, "_slice_index"); + TestCaseSupplier.TypedData nextTimestampType = TestCaseSupplier.TypedData.multiRow( + maxTimestamps, + DataType.LONG, + "_max_timestamp" + ); + + dataRows = dataRows.stream().filter(Objects::nonNull).toList(); + final Matcher matcher; + if (dataRows.size() < 2) { + matcher = Matchers.nullValue(); + } else { + var maxdelta = switch (fieldTypedData.type().widenSmallNumeric()) { + case INTEGER, COUNTER_INTEGER -> dataRows.stream().mapToInt(v -> (Integer) v).max().orElse(0); + case LONG, COUNTER_LONG -> dataRows.stream().mapToLong(v -> (Long) v).max().orElse(0L); + case DOUBLE, COUNTER_DOUBLE -> dataRows.stream().mapToDouble(v -> (Double) v).max().orElse(0.0); + default -> throw new IllegalStateException("Unexpected value: " + fieldTypedData.type()); + }; + var mindelta = switch (fieldTypedData.type().widenSmallNumeric()) { + case INTEGER, COUNTER_INTEGER -> dataRows.stream().mapToInt(v -> (Integer) v).min().orElse(0); + case LONG, COUNTER_LONG -> dataRows.stream().mapToLong(v -> (Long) v).min().orElse(0L); + case DOUBLE, COUNTER_DOUBLE -> dataRows.stream().mapToDouble(v -> (Double) v).min().orElse(0.0); + default -> throw new IllegalStateException("Unexpected value: " + fieldTypedData.type()); + }; + maxdelta = Math.max(maxdelta, maxdelta - Math.min(mindelta, 0)); + mindelta = -maxdelta; + matcher = Matchers.allOf(Matchers.greaterThanOrEqualTo(mindelta), Matchers.lessThanOrEqualTo(maxdelta)); + } + return new TestCaseSupplier.TestCase( + List.of(fieldTypedData, timestampsField, sliceIndexType, nextTimestampType), + standardAggregatorName("Delta", fieldTypedData.type()), + DataType.DOUBLE, + matcher + ); + }); + } + + public static List signatureTypes(List params) { + assertThat(params, hasSize(4)); + assertThat(params.get(1).dataType(), equalTo(DataType.DATETIME)); + assertThat(params.get(2).dataType(), equalTo(DataType.INTEGER)); + assertThat(params.get(3).dataType(), equalTo(DataType.LONG)); + return List.of(params.get(0)); + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IdeltaTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IdeltaTests.java new file mode 100644 index 0000000000000..0127864b9a32c --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IdeltaTests.java @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.aggregate; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class IdeltaTests extends AbstractAggregationTestCase { + public IdeltaTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @ParametersFactory + public static Iterable parameters() { + var suppliers = new ArrayList(); + + var valuesSuppliers = List.of( + MultiRowTestCaseSupplier.longCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.intCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.doubleCases(1, 1000, 0, 1000_000_000, true) + + ); + for (List valuesSupplier : valuesSuppliers) { + for (TestCaseSupplier.TypedDataSupplier fieldSupplier : valuesSupplier) { + TestCaseSupplier testCaseSupplier = makeSupplier(fieldSupplier); + suppliers.add(testCaseSupplier); + } + } + return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(suppliers); + } + + @Override + protected Expression build(Source source, List args) { + return new Idelta(source, args.get(0), args.get(1)); + } + + @Override + public void testAggregate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateToString() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateIntermediate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @SuppressWarnings("unchecked") + private static TestCaseSupplier makeSupplier(TestCaseSupplier.TypedDataSupplier fieldSupplier) { + DataType type = fieldSupplier.type(); + return new TestCaseSupplier(fieldSupplier.name(), List.of(type, DataType.DATETIME, DataType.INTEGER, DataType.LONG), () -> { + TestCaseSupplier.TypedData fieldTypedData = fieldSupplier.get(); + List dataRows = fieldTypedData.multiRowData(); + if (randomBoolean()) { + List withNulls = new ArrayList<>(dataRows.size()); + for (Object dataRow : dataRows) { + if (randomBoolean()) { + withNulls.add(null); + } else { + withNulls.add(dataRow); + } + } + dataRows = withNulls; + } + fieldTypedData = TestCaseSupplier.TypedData.multiRow(dataRows, type, fieldTypedData.name()); + List timestamps = new ArrayList<>(); + List slices = new ArrayList<>(); + List maxTimestamps = new ArrayList<>(); + long lastTimestamp = randomLongBetween(0, 1_000_000); + for (int row = 0; row < dataRows.size(); row++) { + lastTimestamp += randomLongBetween(1, 10_000); + timestamps.add(lastTimestamp); + slices.add(0); + maxTimestamps.add(Long.MAX_VALUE); + } + TestCaseSupplier.TypedData timestampsField = TestCaseSupplier.TypedData.multiRow( + timestamps.reversed(), + DataType.DATETIME, + "timestamps" + ); + TestCaseSupplier.TypedData sliceIndexType = TestCaseSupplier.TypedData.multiRow(slices, DataType.INTEGER, "_slice_index"); + TestCaseSupplier.TypedData nextTimestampType = TestCaseSupplier.TypedData.multiRow( + maxTimestamps, + DataType.LONG, + "_max_timestamp" + ); + List nonNullDataRows = dataRows.stream().filter(Objects::nonNull).toList(); + Object maxValue = null; + Object minValue = null; + + for (int i = dataRows.size() - 1; i >= 0; i--) { + if (dataRows.get(i) != null) { + if (maxValue == null) { + maxValue = dataRows.get(i); + } else if (((Comparable) dataRows.get(i)).compareTo(maxValue) > 0) { + maxValue = dataRows.get(i); + } + if (minValue == null) { + minValue = dataRows.get(i); + } else if (((Comparable) dataRows.get(i)).compareTo(minValue) < 0) { + minValue = dataRows.get(i); + } + } + } + + final Matcher matcher; + if (nonNullDataRows.size() < 2) { + matcher = Matchers.nullValue(); + } else { + var maxDiff = ((Number) maxValue).doubleValue() - ((Number) minValue).doubleValue(); + matcher = Matchers.allOf(Matchers.greaterThanOrEqualTo(-maxDiff), Matchers.lessThanOrEqualTo(maxDiff)); + } + return new TestCaseSupplier.TestCase( + List.of(fieldTypedData, timestampsField, sliceIndexType, nextTimestampType), + standardAggregatorName("Irate", fieldTypedData.type()), + DataType.DOUBLE, + matcher + ); + }); + } + + public static List signatureTypes(List params) { + assertThat(params, hasSize(4)); + assertThat(params.get(1).dataType(), equalTo(DataType.DATETIME)); + assertThat(params.get(2).dataType(), equalTo(DataType.INTEGER)); + assertThat(params.get(3).dataType(), equalTo(DataType.LONG)); + return List.of(params.get(0)); + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IncreaseTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IncreaseTests.java new file mode 100644 index 0000000000000..b5edb733f7fe6 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IncreaseTests.java @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.aggregate; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class IncreaseTests extends AbstractAggregationTestCase { + public IncreaseTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @ParametersFactory + public static Iterable parameters() { + var suppliers = new ArrayList(); + + var valuesSuppliers = List.of( + MultiRowTestCaseSupplier.longCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.intCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.doubleCases(1, 1000, 0, 1000_000_000, true) + + ); + for (List valuesSupplier : valuesSuppliers) { + for (TestCaseSupplier.TypedDataSupplier fieldSupplier : valuesSupplier) { + TestCaseSupplier testCaseSupplier = makeSupplier(fieldSupplier); + suppliers.add(testCaseSupplier); + } + } + return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(suppliers); + } + + @Override + protected Expression build(Source source, List args) { + return new Increase(source, args.get(0), args.get(1)); + } + + @Override + public void testAggregate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateToString() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateIntermediate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + private static DataType counterType(DataType type) { + return switch (type) { + case DOUBLE -> DataType.COUNTER_DOUBLE; + case LONG -> DataType.COUNTER_LONG; + case INTEGER -> DataType.COUNTER_INTEGER; + default -> throw new AssertionError("unknown type for counter: " + type); + }; + } + + private static TestCaseSupplier makeSupplier(TestCaseSupplier.TypedDataSupplier fieldSupplier) { + DataType type = counterType(fieldSupplier.type()); + return new TestCaseSupplier(fieldSupplier.name(), List.of(type, DataType.DATETIME, DataType.INTEGER, DataType.LONG), () -> { + TestCaseSupplier.TypedData fieldTypedData = fieldSupplier.get(); + List dataRows = fieldTypedData.multiRowData(); + if (randomBoolean()) { + List withNulls = new ArrayList<>(dataRows.size()); + for (Object dataRow : dataRows) { + if (randomBoolean()) { + withNulls.add(null); + } else { + withNulls.add(dataRow); + } + } + dataRows = withNulls; + } + fieldTypedData = TestCaseSupplier.TypedData.multiRow(dataRows, type, fieldTypedData.name()); + List timestamps = new ArrayList<>(); + List slices = new ArrayList<>(); + List maxTimestamps = new ArrayList<>(); + long lastTimestamp = randomLongBetween(0, 1_000_000); + for (int row = 0; row < dataRows.size(); row++) { + lastTimestamp += randomLongBetween(1, 10_000); + timestamps.add(lastTimestamp); + slices.add(0); + maxTimestamps.add(Long.MAX_VALUE); + } + TestCaseSupplier.TypedData timestampsField = TestCaseSupplier.TypedData.multiRow( + timestamps.reversed(), + DataType.DATETIME, + "timestamps" + ); + TestCaseSupplier.TypedData sliceIndexType = TestCaseSupplier.TypedData.multiRow(slices, DataType.INTEGER, "_slice_index"); + TestCaseSupplier.TypedData nextTimestampType = TestCaseSupplier.TypedData.multiRow( + maxTimestamps, + DataType.LONG, + "_max_timestamp" + ); + + List nonNullDataRows = dataRows.stream().filter(Objects::nonNull).toList(); + final Matcher matcher; + if (nonNullDataRows.size() < 2) { + matcher = Matchers.nullValue(); + } else { + double increase = 0.0; + for (int i = 1; i < nonNullDataRows.size(); i++) { + double previous = ((Number) nonNullDataRows.get(i - 1)).doubleValue(); + double current = ((Number) nonNullDataRows.get(i)).doubleValue(); + if (current >= previous) { + increase += current - previous; + } else { + // Counter reset + increase += current; + } + } + matcher = closeTo(increase, 0.1 * increase); + } + + return new TestCaseSupplier.TestCase( + List.of(fieldTypedData, timestampsField, sliceIndexType, nextTimestampType), + standardAggregatorName("Rate", fieldTypedData.type()), + DataType.DOUBLE, + matcher + ); + }); + } + + public static List signatureTypes(List params) { + assertThat(params, hasSize(4)); + assertThat(params.get(1).dataType(), equalTo(DataType.DATETIME)); + assertThat(params.get(2).dataType(), equalTo(DataType.INTEGER)); + assertThat(params.get(3).dataType(), equalTo(DataType.LONG)); + return List.of(params.get(0)); + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IrateTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IrateTests.java new file mode 100644 index 0000000000000..071896ee3e945 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/IrateTests.java @@ -0,0 +1,167 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.aggregate; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class IrateTests extends AbstractAggregationTestCase { + public IrateTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @ParametersFactory + public static Iterable parameters() { + var suppliers = new ArrayList(); + + var valuesSuppliers = List.of( + MultiRowTestCaseSupplier.longCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.intCases(1, 1000, 0, 1000_000_000, true), + MultiRowTestCaseSupplier.doubleCases(1, 1000, 0, 1000_000_000, true) + + ); + for (List valuesSupplier : valuesSuppliers) { + for (TestCaseSupplier.TypedDataSupplier fieldSupplier : valuesSupplier) { + TestCaseSupplier testCaseSupplier = makeSupplier(fieldSupplier); + suppliers.add(testCaseSupplier); + } + } + return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(suppliers); + } + + @Override + protected Expression build(Source source, List args) { + return new Irate(source, args.get(0), args.get(1)); + } + + @Override + public void testAggregate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateToString() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + @Override + public void testAggregateIntermediate() { + assumeTrue("time-series aggregation doesn't support ungrouped", false); + } + + private static DataType counterType(DataType type) { + return switch (type) { + case DOUBLE -> DataType.COUNTER_DOUBLE; + case LONG -> DataType.COUNTER_LONG; + case INTEGER -> DataType.COUNTER_INTEGER; + default -> throw new AssertionError("unknown type for counter: " + type); + }; + } + + @SuppressWarnings("unchecked") + private static TestCaseSupplier makeSupplier(TestCaseSupplier.TypedDataSupplier fieldSupplier) { + DataType type = counterType(fieldSupplier.type()); + return new TestCaseSupplier(fieldSupplier.name(), List.of(type, DataType.DATETIME, DataType.INTEGER, DataType.LONG), () -> { + TestCaseSupplier.TypedData fieldTypedData = fieldSupplier.get(); + List dataRows = fieldTypedData.multiRowData(); + if (randomBoolean()) { + List withNulls = new ArrayList<>(dataRows.size()); + for (Object dataRow : dataRows) { + if (randomBoolean()) { + withNulls.add(null); + } else { + withNulls.add(dataRow); + } + } + dataRows = withNulls; + } + fieldTypedData = TestCaseSupplier.TypedData.multiRow(dataRows, type, fieldTypedData.name()); + List timestamps = new ArrayList<>(); + List slices = new ArrayList<>(); + List maxTimestamps = new ArrayList<>(); + long lastTimestamp = randomLongBetween(0, 1_000_000); + for (int row = 0; row < dataRows.size(); row++) { + lastTimestamp += randomLongBetween(1, 10_000); + timestamps.add(lastTimestamp); + slices.add(0); + maxTimestamps.add(Long.MAX_VALUE); + } + TestCaseSupplier.TypedData timestampsField = TestCaseSupplier.TypedData.multiRow( + timestamps.reversed(), + DataType.DATETIME, + "timestamps" + ); + TestCaseSupplier.TypedData sliceIndexType = TestCaseSupplier.TypedData.multiRow(slices, DataType.INTEGER, "_slice_index"); + TestCaseSupplier.TypedData nextTimestampType = TestCaseSupplier.TypedData.multiRow( + maxTimestamps, + DataType.LONG, + "_max_timestamp" + ); + + List nonNullDataRows = dataRows.stream().filter(Objects::nonNull).toList(); + Object maxValue = null; + Object minValue = null; + + for (int i = dataRows.size() - 1; i >= 0; i--) { + if (dataRows.get(i) != null) { + if (maxValue == null) { + maxValue = dataRows.get(i); + } else if (((Comparable) dataRows.get(i)).compareTo(maxValue) > 0) { + maxValue = dataRows.get(i); + } + if (minValue == null) { + minValue = dataRows.get(i); + } else if (((Comparable) dataRows.get(i)).compareTo(minValue) < 0) { + minValue = dataRows.get(i); + } + } + } + + final Matcher matcher; + if (nonNullDataRows.size() < 2) { + matcher = Matchers.nullValue(); + } else { + var maxDiff = ((Number) maxValue).doubleValue() - ((Number) minValue).doubleValue(); + matcher = Matchers.allOf(Matchers.greaterThanOrEqualTo(-maxDiff), Matchers.lessThanOrEqualTo(maxDiff)); + } + + return new TestCaseSupplier.TestCase( + List.of(fieldTypedData, timestampsField, sliceIndexType, nextTimestampType), + standardAggregatorName("Irate", fieldTypedData.type()), + DataType.DOUBLE, + matcher + ); + }); + } + + public static List signatureTypes(List params) { + assertThat(params, hasSize(4)); + assertThat(params.get(1).dataType(), equalTo(DataType.DATETIME)); + assertThat(params.get(2).dataType(), equalTo(DataType.INTEGER)); + assertThat(params.get(3).dataType(), equalTo(DataType.LONG)); + return List.of(params.get(0)); + } +}