diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/decay.md b/docs/reference/query-languages/esql/_snippets/functions/description/decay.md
new file mode 100644
index 0000000000000..9d6f305d5661f
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/description/decay.md
@@ -0,0 +1,16 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Description**
+
+Calculates a relevance score that decays based on the distance of a numeric, spatial or date type value from a target origin, using configurable decay functions.
+
+`DECAY` calculates a score between 0 and 1 based on how far a field value is from a specified origin point (called distance).
+The distance can be a numeric distance, spatial distance or temporal distance depending on the specific data type.
+
+`DECAY` can use [function named parameters](/reference/query-languages/esql/esql-syntax.md#esql-function-named-params) to specify additional `options`
+for the decay function.
+
+For spatial queries, scale and offset for geo points use distance units (e.g., "10km", "5mi"),
+while cartesian points use numeric values. For date queries, scale and offset use time_duration values.
+For numeric queries you also use numeric values.
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/decay.md b/docs/reference/query-languages/esql/_snippets/functions/examples/decay.md
new file mode 100644
index 0000000000000..b3efac50b7ae7
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/examples/decay.md
@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+null
+```
+
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/decay.md b/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/decay.md
new file mode 100644
index 0000000000000..8d72318865141
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/decay.md
@@ -0,0 +1,13 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Supported function named parameters**
+
+`offset`
+: (double, integer, long, time_duration, keyword, text) Distance from the origin where no decay occurs.
+
+`type`
+: (keyword) Decay function to use: linear, exponential or gaussian.
+
+`decay`
+: (double) Multiplier value returned at the scale distance from the origin.
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/decay.md b/docs/reference/query-languages/esql/_snippets/functions/layout/decay.md
new file mode 100644
index 0000000000000..2e43297523822
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/decay.md
@@ -0,0 +1,30 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+## `DECAY` [esql-decay]
+```{applies_to}
+stack: preview 9.2.0
+serverless: preview
+```
+
+**Syntax**
+
+:::{image} ../../../images/functions/decay.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/decay.md
+:::
+
+:::{include} ../description/decay.md
+:::
+
+:::{include} ../types/decay.md
+:::
+
+:::{include} ../functionNamedParams/decay.md
+:::
+
+:::{include} ../examples/decay.md
+:::
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/decay.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/decay.md
new file mode 100644
index 0000000000000..dae2fea0fb426
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/decay.md
@@ -0,0 +1,16 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Parameters**
+
+`value`
+: The input value to apply decay scoring to.
+
+`origin`
+: Central point from which the distances are calculated.
+
+`scale`
+: Distance from the origin where the function returns the decay value.
+
+`options`
+:
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/decay.md b/docs/reference/query-languages/esql/_snippets/functions/types/decay.md
new file mode 100644
index 0000000000000..2b64fee072ddc
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/types/decay.md
@@ -0,0 +1,15 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| value | origin | scale | options | result |
+| --- | --- | --- | --- | --- |
+| cartesian_point | cartesian_point | double | named parameters | double |
+| date | date | time_duration | named parameters | double |
+| date_nanos | date_nanos | time_duration | named parameters | double |
+| double | double | double | named parameters | double |
+| geo_point | geo_point | keyword | named parameters | double |
+| geo_point | geo_point | text | named parameters | double |
+| integer | integer | integer | named parameters | double |
+| long | long | long | named parameters | double |
+
diff --git a/docs/reference/query-languages/esql/_snippets/lists/search-functions.md b/docs/reference/query-languages/esql/_snippets/lists/search-functions.md
index 76b0929065a13..71c9ec005985c 100644
--- a/docs/reference/query-languages/esql/_snippets/lists/search-functions.md
+++ b/docs/reference/query-languages/esql/_snippets/lists/search-functions.md
@@ -2,4 +2,5 @@
* [`MATCH`](../../functions-operators/search-functions.md#esql-match)
* [`MATCH_PHRASE`](../../functions-operators/search-functions.md#esql-match_phrase)
* [`QSTR`](../../functions-operators/search-functions.md#esql-qstr)
+% * [preview] [`DECAY`](../../functions-operators/search-functions.md#esql-decay)
% * [preview] [`TERM`](../../functions-operators/search-functions.md#esql-term)
diff --git a/docs/reference/query-languages/esql/functions-operators/search-functions.md b/docs/reference/query-languages/esql/functions-operators/search-functions.md
index 597f61cfc5003..d72b30d0efdb1 100644
--- a/docs/reference/query-languages/esql/functions-operators/search-functions.md
+++ b/docs/reference/query-languages/esql/functions-operators/search-functions.md
@@ -13,7 +13,7 @@ our [hands-on tutorial](/reference/query-languages/esql/esql-search-tutorial.md)
For a high-level overview of search functionalities in {{esql}}, and to learn about relevance scoring, refer to [{{esql}} for search](docs-content://solutions/search/esql-for-search.md#esql-for-search-scoring).
:::
-{{esql}} provides a set of functions for performing searching on text fields.
+{{esql}} provides a set of functions for performing searching on text fields.
Use these functions
for [full-text search](docs-content://solutions/search/full-text.md)
@@ -36,6 +36,7 @@ for information on the limitations of full text search.
:::{include} ../_snippets/lists/search-functions.md
:::
+
:::{include} ../_snippets/functions/layout/kql.md
:::
@@ -54,3 +55,8 @@ lists/search-functions.md
% :::{include} ../_snippets/functions/layout/term.md
% :::
+% DECAY is currently a hidden feature
+% To make it visible again, uncomment this and the line in
+lists/search-functions.md
+% :::{include} ../_snippets/functions/layout/decay.md
+% :::
diff --git a/docs/reference/query-languages/esql/images/functions/decay.svg b/docs/reference/query-languages/esql/images/functions/decay.svg
new file mode 100644
index 0000000000000..176ef68b5b730
--- /dev/null
+++ b/docs/reference/query-languages/esql/images/functions/decay.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/decay.json b/docs/reference/query-languages/esql/kibana/definition/functions/decay.json
new file mode 100644
index 0000000000000..56ca96d77d071
--- /dev/null
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/decay.json
@@ -0,0 +1,261 @@
+{
+ "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.",
+ "type" : "scalar",
+ "name" : "decay",
+ "description" : "Calculates a relevance score that decays based on the distance of a numeric, spatial or date type value from a target origin, using configurable decay functions.",
+ "signatures" : [
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "cartesian_point",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "cartesian_point",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "double",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "date",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "date",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "time_duration",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "date_nanos",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "date_nanos",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "time_duration",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "double",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "double",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "double",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "geo_point",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "geo_point",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "keyword",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "geo_point",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "geo_point",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "text",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "integer",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "integer",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "integer",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ },
+ {
+ "params" : [
+ {
+ "name" : "value",
+ "type" : "long",
+ "optional" : false,
+ "description" : "The input value to apply decay scoring to."
+ },
+ {
+ "name" : "origin",
+ "type" : "long",
+ "optional" : false,
+ "description" : "Central point from which the distances are calculated."
+ },
+ {
+ "name" : "scale",
+ "type" : "long",
+ "optional" : false,
+ "description" : "Distance from the origin where the function returns the decay value."
+ },
+ {
+ "name" : "options",
+ "type" : "function_named_parameters",
+ "mapParams" : "{name='offset', values=[], description='Distance from the origin where no decay occurs.'}, {name='type', values=[], description='Decay function to use: linear, exponential or gaussian.'}, {name='decay', values=[], description='Multiplier value returned at the scale distance from the origin.'}",
+ "optional" : true,
+ "description" : ""
+ }
+ ],
+ "variadic" : false,
+ "returnType" : "double"
+ }
+ ],
+ "examples" : [
+ null
+ ],
+ "preview" : true,
+ "snapshot_only" : false
+}
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/decay.md b/docs/reference/query-languages/esql/kibana/docs/functions/decay.md
new file mode 100644
index 0000000000000..1f1550cbf1d9e
--- /dev/null
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/decay.md
@@ -0,0 +1,8 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+### DECAY
+Calculates a relevance score that decays based on the distance of a numeric, spatial or date type value from a target origin, using configurable decay functions.
+
+```esql
+null
+```
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java
index d6f74144a9717..0bccb5080ef56 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java
@@ -22,13 +22,17 @@
import org.elasticsearch.xpack.versionfield.Version;
import java.io.IOException;
+import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_POINT;
+import static org.elasticsearch.xpack.esql.core.type.DataType.DOUBLE;
import static org.elasticsearch.xpack.esql.core.type.DataType.GEO_POINT;
+import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
import static org.elasticsearch.xpack.esql.core.type.DataType.KEYWORD;
+import static org.elasticsearch.xpack.esql.core.type.DataType.LONG;
import static org.elasticsearch.xpack.esql.core.type.DataType.TEXT;
import static org.elasticsearch.xpack.esql.core.type.DataType.VERSION;
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN;
@@ -208,6 +212,26 @@ public static Literal keyword(Source source, String literal) {
return new Literal(source, BytesRefs.toBytesRef(literal), KEYWORD);
}
+ public static Literal text(Source source, String literal) {
+ return new Literal(source, BytesRefs.toBytesRef(literal), TEXT);
+ }
+
+ public static Literal timeDuration(Source source, Duration literal) {
+ return new Literal(source, literal, DataType.TIME_DURATION);
+ }
+
+ public static Literal integer(Source source, Integer literal) {
+ return new Literal(source, literal, INTEGER);
+ }
+
+ public static Literal fromDouble(Source source, Double literal) {
+ return new Literal(source, literal, DOUBLE);
+ }
+
+ public static Literal fromLong(Source source, Long literal) {
+ return new Literal(source, literal, LONG);
+ }
+
/**
* Not all literal values are currently supported in StreamInput/StreamOutput as generic values.
* This mapper allows for addition of new and interesting values without (yet) adding to StreamInput/Output.
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java
index 3c36884874454..528f9ac2f57ea 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java
@@ -521,6 +521,14 @@ public static boolean isDateTime(DataType type) {
return type == DATETIME;
}
+ public static boolean isTimeDuration(DataType t) {
+ return t == TIME_DURATION;
+ }
+
+ public static boolean isDateNanos(DataType t) {
+ return t == DATE_NANOS;
+ }
+
public static boolean isNullOrTimeDuration(DataType t) {
return t == TIME_DURATION || isNull(t);
}
@@ -580,7 +588,15 @@ public static boolean isCounter(DataType t) {
}
public static boolean isSpatialPoint(DataType t) {
- return t == GEO_POINT || t == CARTESIAN_POINT;
+ return isGeoPoint(t) || isCartesianPoint(t);
+ }
+
+ public static boolean isGeoPoint(DataType t) {
+ return t == GEO_POINT;
+ }
+
+ public static boolean isCartesianPoint(DataType t) {
+ return t == CARTESIAN_POINT;
}
public static boolean isSpatialShape(DataType t) {
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/decay.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/decay.csv-spec
new file mode 100644
index 0000000000000..313404d5a33af
--- /dev/null
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/decay.csv-spec
@@ -0,0 +1,285 @@
+###############################################
+# Tests for DecayLinear function
+#
+
+intLinear
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = decay(value, 10, 10, {"offset": 0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+intLinear2
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = decay(value, 5 + 5, 5 + 5, {"offset": 0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+intExp
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = round(decay(value, 10, 10, {"offset": 0, "decay": 0.5, "type": "exp"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.7071068
+;
+
+intGauss
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = round(decay(value, 10, 10, {"offset": 0, "decay": 0.5, "type": "gauss"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.8408964
+;
+
+intLinearWithOffset
+required_capability: decay_function
+
+ROW value = 95
+| EVAL decay_result = decay(value, 100, 50, {"offset": 10, "decay": 0.3, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+1.0
+;
+
+intExpWithOffset
+required_capability: decay_function
+
+ROW value = 120
+| EVAL decay_result = round(decay(value, 100, 50, {"offset": 5, "decay": 0.3, "type": "exp"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.6968453
+;
+
+intGaussWithOffset
+required_capability: decay_function
+
+ROW value = 120
+| EVAL decay_result = round(decay(value, 100, 50, {"offset": 5, "decay": 0.3, "type": "gauss"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.8973067
+;
+
+intWithoutOptions
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = decay(value, 10, 10)
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+intOnlyWithOffset
+required_capability: decay_function
+
+ROW value = 5
+| EVAL decay_result = decay(value, 10, 10, {"offset": 100})
+| KEEP decay_result;
+
+decay_result:double
+1.0
+;
+
+intMultipleRows
+required_capability: decay_function
+
+FROM employees
+| EVAL decay_result = decay(salary, 0, 100000, {"offset": 5, "decay": 0.5, "type": "linear"})
+| KEEP decay_result
+| SORT decay_result DESC
+| LIMIT 5;
+
+decay_result:double
+0.873405
+0.8703
+0.870145
+0.867845
+0.86395
+;
+
+intOriginReference
+required_capability: decay_function
+
+ROW value = 5, origin = 10
+| EVAL decay_result = decay(value, origin, 10, {"offset": 0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+intScaleReference
+required_capability: decay_function
+
+ROW value = 5, scale = 10
+| EVAL decay_result = decay(value, 10, scale, {"offset": 0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+intScaleAndOriginReference
+required_capability: decay_function
+
+ROW value = 5, origin = 10, scale = 10
+| EVAL decay_result = decay(value, origin, scale, {"offset": 0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+doubleLinear
+required_capability: decay_function
+
+ROW value = 5.0
+| EVAL decay_result = decay(value, 10.0, 10.0, {"offset": 0.0, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+doubleExp
+required_capability: decay_function
+
+ROW value = 5.0
+| EVAL decay_result = round(decay(value, 10.0, 10.0, {"offset": 0.0, "decay": 0.5, "type": "exp"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.7071068
+;
+
+doubleGauss
+required_capability: decay_function
+
+ROW value = 5.0
+| EVAL decay_result = round(decay(value, 10.0, 10.0, {"offset": 0.0, "decay": 0.5, "type": "gauss"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.8408964
+;
+
+longLinear
+required_capability: decay_function
+
+ROW value = 15::long
+| EVAL decay_result = decay(value, 10::long, 10::long, {"offset": 10000000000, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+1.0
+;
+
+cartesianPointLinear1
+required_capability: decay_function
+
+ROW value = TO_CARTESIANPOINT("POINT(5 5)")
+| EVAL decay_result = decay(value, TO_CARTESIANPOINT("POINT(0 0)"), 10.0, {"offset": 0.0, "decay": 0.25, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.46966991411008935
+;
+
+cartesianPointLinear2
+required_capability: decay_function
+
+ROW value = TO_CARTESIANPOINT("POINT(10 0)")
+| EVAL decay_result = ROUND(decay(value, TO_CARTESIANPOINT("POINT(0 0)"), 10.0, {"offset": 0.0, "decay": 0.25, "type": "linear"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.25
+;
+
+cartesianPointLinearWithOffset
+required_capability: decay_function
+
+ROW value = TO_CARTESIANPOINT("POINT(10 0)")
+| EVAL decay_result = ROUND(decay(value, TO_CARTESIANPOINT("POINT(0 0)"), 10.0, {"offset": 5.0, "decay": 0.25, "type": "linear"}), 7)
+| KEEP decay_result;
+
+decay_result:double
+0.625
+;
+
+
+geoPointLinear
+required_capability: decay_function
+
+ROW value = TO_GEOPOINT("POINT(0 0)")
+| EVAL decay_result = decay(value, TO_GEOPOINT("POINT(1 1)"), "200km", {"offset": "0km", "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.606876005579706
+;
+
+datetimeLinear1
+required_capability: decay_function
+
+ROW value = TO_DATETIME("2023-01-01T00:00:00Z")
+| EVAL decay_result = decay(value, TO_DATETIME("2023-01-01T00:00:00Z"), 24 hours, {"offset": 0 seconds, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+1.0
+;
+
+datetimeLinear2
+required_capability: decay_function
+
+ROW value = TO_DATETIME("2023-01-01T12:00:00Z")
+| EVAL decay_result = decay(value, TO_DATETIME("2023-01-01T00:00:00Z"), 24 hours, {"offset": 0 seconds, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
+
+dateNanosLinear1
+required_capability: decay_function
+
+ROW value = TO_DATE_NANOS("2023-01-01T00:00:00Z")
+| EVAL decay_result = decay(value, TO_DATE_NANOS("2023-01-01T00:00:00Z"), 24 hours, {"offset": 0 seconds, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+1.0
+;
+
+dateNanosLinear2
+required_capability: decay_function
+
+ROW value = TO_DATE_NANOS("2023-01-01T12:00:00Z")
+| EVAL decay_result = decay(value, TO_DATE_NANOS("2023-01-01T00:00:00Z"), 24 hours, {"offset": 0 seconds, "decay": 0.5, "type": "linear"})
+| KEEP decay_result;
+
+decay_result:double
+0.75
+;
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayCartesianPointEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayCartesianPointEvaluator.java
new file mode 100644
index 0000000000000..25c91b23ebf2f
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayCartesianPointEvaluator.java
@@ -0,0 +1,169 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.BytesRefVector;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayCartesianPointEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayCartesianPointEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final BytesRef origin;
+
+ private final double scale;
+
+ private final double offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayCartesianPointEvaluator(Source source, EvalOperator.ExpressionEvaluator value,
+ BytesRef origin, double scale, double offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (BytesRefBlock valueBlock = (BytesRefBlock) value.eval(page)) {
+ BytesRefVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector).asBlock();
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, BytesRefBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ BytesRef valueScratch = new BytesRef();
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ result.appendDouble(Decay.processCartesianPoint(valueBlock.getBytesRef(valueBlock.getFirstValueIndex(p), valueScratch), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleVector eval(int positionCount, BytesRefVector valueVector) {
+ try(DoubleVector.FixedBuilder result = driverContext.blockFactory().newDoubleVectorFixedBuilder(positionCount)) {
+ BytesRef valueScratch = new BytesRef();
+ position: for (int p = 0; p < positionCount; p++) {
+ result.appendDouble(p, Decay.processCartesianPoint(valueVector.getBytesRef(p, valueScratch), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayCartesianPointEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final BytesRef origin;
+
+ private final double scale;
+
+ private final double offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, BytesRef origin,
+ double scale, double offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayCartesianPointEvaluator get(DriverContext context) {
+ return new DecayCartesianPointEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayCartesianPointEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDateNanosEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDateNanosEvaluator.java
new file mode 100644
index 0000000000000..223e11c6150aa
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDateNanosEvaluator.java
@@ -0,0 +1,176 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.LongVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayDateNanosEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayDateNanosEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayDateNanosEvaluator(Source source, EvalOperator.ExpressionEvaluator value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (LongBlock valueBlock = (LongBlock) value.eval(page)) {
+ LongVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector);
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, LongBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ try {
+ result.appendDouble(Decay.processDateNanos(valueBlock.getLong(valueBlock.getFirstValueIndex(p)), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ } catch (InvalidArgumentException | IllegalArgumentException e) {
+ warnings().registerException(e);
+ result.appendNull();
+ }
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleBlock eval(int positionCount, LongVector valueVector) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ try {
+ result.appendDouble(Decay.processDateNanos(valueVector.getLong(p), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ } catch (InvalidArgumentException | IllegalArgumentException e) {
+ warnings().registerException(e);
+ result.appendNull();
+ }
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDateNanosEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayDateNanosEvaluator get(DriverContext context) {
+ return new DecayDateNanosEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDateNanosEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDatetimeEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDatetimeEvaluator.java
new file mode 100644
index 0000000000000..f5618ec2f95e8
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDatetimeEvaluator.java
@@ -0,0 +1,176 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.LongVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayDatetimeEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayDatetimeEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayDatetimeEvaluator(Source source, EvalOperator.ExpressionEvaluator value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (LongBlock valueBlock = (LongBlock) value.eval(page)) {
+ LongVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector);
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, LongBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ try {
+ result.appendDouble(Decay.processDatetime(valueBlock.getLong(valueBlock.getFirstValueIndex(p)), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ } catch (InvalidArgumentException | IllegalArgumentException e) {
+ warnings().registerException(e);
+ result.appendNull();
+ }
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleBlock eval(int positionCount, LongVector valueVector) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ try {
+ result.appendDouble(Decay.processDatetime(valueVector.getLong(p), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ } catch (InvalidArgumentException | IllegalArgumentException e) {
+ warnings().registerException(e);
+ result.appendNull();
+ }
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDatetimeEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayDatetimeEvaluator get(DriverContext context) {
+ return new DecayDatetimeEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDatetimeEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDoubleEvaluator.java
new file mode 100644
index 0000000000000..a9fe2cbe0c416
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayDoubleEvaluator.java
@@ -0,0 +1,164 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayDoubleEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayDoubleEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final double origin;
+
+ private final double scale;
+
+ private final double offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayDoubleEvaluator(Source source, EvalOperator.ExpressionEvaluator value, double origin,
+ double scale, double offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (DoubleBlock valueBlock = (DoubleBlock) value.eval(page)) {
+ DoubleVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector).asBlock();
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, DoubleBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ result.appendDouble(Decay.process(valueBlock.getDouble(valueBlock.getFirstValueIndex(p)), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleVector eval(int positionCount, DoubleVector valueVector) {
+ try(DoubleVector.FixedBuilder result = driverContext.blockFactory().newDoubleVectorFixedBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ result.appendDouble(p, Decay.process(valueVector.getDouble(p), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDoubleEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final double origin;
+
+ private final double scale;
+
+ private final double offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, double origin,
+ double scale, double offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayDoubleEvaluator get(DriverContext context) {
+ return new DecayDoubleEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayDoubleEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayGeoPointEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayGeoPointEvaluator.java
new file mode 100644
index 0000000000000..139d58d6d7e37
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayGeoPointEvaluator.java
@@ -0,0 +1,169 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.BytesRefVector;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayGeoPointEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayGeoPointEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final BytesRef origin;
+
+ private final BytesRef scale;
+
+ private final BytesRef offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayGeoPointEvaluator(Source source, EvalOperator.ExpressionEvaluator value,
+ BytesRef origin, BytesRef scale, BytesRef offset, double decay,
+ Decay.DecayFunction decayFunction, DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (BytesRefBlock valueBlock = (BytesRefBlock) value.eval(page)) {
+ BytesRefVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector).asBlock();
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, BytesRefBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ BytesRef valueScratch = new BytesRef();
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ result.appendDouble(Decay.process(valueBlock.getBytesRef(valueBlock.getFirstValueIndex(p), valueScratch), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleVector eval(int positionCount, BytesRefVector valueVector) {
+ try(DoubleVector.FixedBuilder result = driverContext.blockFactory().newDoubleVectorFixedBuilder(positionCount)) {
+ BytesRef valueScratch = new BytesRef();
+ position: for (int p = 0; p < positionCount; p++) {
+ result.appendDouble(p, Decay.process(valueVector.getBytesRef(p, valueScratch), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayGeoPointEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final BytesRef origin;
+
+ private final BytesRef scale;
+
+ private final BytesRef offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, BytesRef origin,
+ BytesRef scale, BytesRef offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayGeoPointEvaluator get(DriverContext context) {
+ return new DecayGeoPointEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayGeoPointEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayIntEvaluator.java
new file mode 100644
index 0000000000000..0a28fc15c0e2a
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayIntEvaluator.java
@@ -0,0 +1,166 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.IntBlock;
+import org.elasticsearch.compute.data.IntVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayIntEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayIntEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final int origin;
+
+ private final int scale;
+
+ private final int offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayIntEvaluator(Source source, EvalOperator.ExpressionEvaluator value, int origin,
+ int scale, int offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (IntBlock valueBlock = (IntBlock) value.eval(page)) {
+ IntVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector).asBlock();
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, IntBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ result.appendDouble(Decay.process(valueBlock.getInt(valueBlock.getFirstValueIndex(p)), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleVector eval(int positionCount, IntVector valueVector) {
+ try(DoubleVector.FixedBuilder result = driverContext.blockFactory().newDoubleVectorFixedBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ result.appendDouble(p, Decay.process(valueVector.getInt(p), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayIntEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final int origin;
+
+ private final int scale;
+
+ private final int offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, int origin,
+ int scale, int offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayIntEvaluator get(DriverContext context) {
+ return new DecayIntEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayIntEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayLongEvaluator.java
new file mode 100644
index 0000000000000..3cc9b4da8f7a1
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/score/DecayLongEvaluator.java
@@ -0,0 +1,166 @@
+// 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.scalar.score;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.RamUsageEstimator;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DoubleBlock;
+import org.elasticsearch.compute.data.DoubleVector;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.LongVector;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Decay}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class DecayLongEvaluator implements EvalOperator.ExpressionEvaluator {
+ private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DecayLongEvaluator.class);
+
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ private final DriverContext driverContext;
+
+ private Warnings warnings;
+
+ public DecayLongEvaluator(Source source, EvalOperator.ExpressionEvaluator value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction,
+ DriverContext driverContext) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ this.driverContext = driverContext;
+ }
+
+ @Override
+ public Block eval(Page page) {
+ try (LongBlock valueBlock = (LongBlock) value.eval(page)) {
+ LongVector valueVector = valueBlock.asVector();
+ if (valueVector == null) {
+ return eval(page.getPositionCount(), valueBlock);
+ }
+ return eval(page.getPositionCount(), valueVector).asBlock();
+ }
+ }
+
+ @Override
+ public long baseRamBytesUsed() {
+ long baseRamBytesUsed = BASE_RAM_BYTES_USED;
+ baseRamBytesUsed += value.baseRamBytesUsed();
+ return baseRamBytesUsed;
+ }
+
+ public DoubleBlock eval(int positionCount, LongBlock valueBlock) {
+ try(DoubleBlock.Builder result = driverContext.blockFactory().newDoubleBlockBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ if (valueBlock.isNull(p)) {
+ result.appendNull();
+ continue position;
+ }
+ if (valueBlock.getValueCount(p) != 1) {
+ if (valueBlock.getValueCount(p) > 1) {
+ warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value"));
+ }
+ result.appendNull();
+ continue position;
+ }
+ result.appendDouble(Decay.process(valueBlock.getLong(valueBlock.getFirstValueIndex(p)), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ public DoubleVector eval(int positionCount, LongVector valueVector) {
+ try(DoubleVector.FixedBuilder result = driverContext.blockFactory().newDoubleVectorFixedBuilder(positionCount)) {
+ position: for (int p = 0; p < positionCount; p++) {
+ result.appendDouble(p, Decay.process(valueVector.getLong(p), this.origin, this.scale, this.offset, this.decay, this.decayFunction));
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DecayLongEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+
+ @Override
+ public void close() {
+ Releasables.closeExpectNoException(value);
+ }
+
+ private Warnings warnings() {
+ if (warnings == null) {
+ this.warnings = Warnings.createWarnings(
+ driverContext.warningsMode(),
+ source.source().getLineNumber(),
+ source.source().getColumnNumber(),
+ source.text()
+ );
+ }
+ return warnings;
+ }
+
+ static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+ private final Source source;
+
+ private final EvalOperator.ExpressionEvaluator.Factory value;
+
+ private final long origin;
+
+ private final long scale;
+
+ private final long offset;
+
+ private final double decay;
+
+ private final Decay.DecayFunction decayFunction;
+
+ public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory value, long origin,
+ long scale, long offset, double decay, Decay.DecayFunction decayFunction) {
+ this.source = source;
+ this.value = value;
+ this.origin = origin;
+ this.scale = scale;
+ this.offset = offset;
+ this.decay = decay;
+ this.decayFunction = decayFunction;
+ }
+
+ @Override
+ public DecayLongEvaluator get(DriverContext context) {
+ return new DecayLongEvaluator(source, value.get(context), origin, scale, offset, decay, decayFunction, context);
+ }
+
+ @Override
+ public String toString() {
+ return "DecayLongEvaluator[" + "value=" + value + ", origin=" + origin + ", scale=" + scale + ", offset=" + offset + ", decay=" + decay + ", decayFunction=" + decayFunction + "]";
+ }
+ }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 36ee0536e393b..57bc9382fc446 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1388,6 +1388,11 @@ public enum Cap {
*/
CATEGORIZE_OPTIONS,
+ /**
+ * Decay function for custom scoring
+ */
+ DECAY_FUNCTION(Build.current().isSnapshot()),
+
/**
* FIRST and LAST aggregate functions.
*/
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
index f4d20dcafd1a0..08c17be59ba8c 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
@@ -145,6 +145,7 @@
import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvSum;
import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvZip;
import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce;
+import org.elasticsearch.xpack.esql.expression.function.scalar.score.Decay;
import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialContains;
import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialDisjoint;
import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialIntersects;
@@ -261,7 +262,7 @@ public class EsqlFunctionRegistry {
}
// Translation table for error messaging in the following function
- private static final String[] NUM_NAMES = { "zero", "one", "two", "three", "four", "five", };
+ private static final String[] NUM_NAMES = { "zero", "one", "two", "three", "four", "five", "six" };
// list of functions grouped by type of functions (aggregate, statistics, math etc) and ordered alphabetically inside each group
// a single function will have one entry for itself with its name associated to its instance and, also, one entry for each alias
@@ -478,6 +479,7 @@ private static FunctionDefinition[][] functions() {
def(Split.class, Split::new, "split") },
// fulltext functions
new FunctionDefinition[] {
+ def(Decay.class, quad(Decay::new), "decay"),
def(Kql.class, uni(Kql::new), "kql"),
def(Match.class, tri(Match::new), "match"),
def(MultiMatch.class, MultiMatch::new, "multi_match"),
@@ -987,7 +989,6 @@ public static FunctionDefinition def(Class function, Bin
Strings.format("function %s expects exactly two arguments, it received %d", Arrays.toString(names), children.size())
);
}
-
return ctorRef.build(source, children.get(0), children.size() == 2 ? children.get(1) : null);
};
return def(function, builder, names);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Options.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Options.java
index a4df48834eb27..113c40166eace 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Options.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Options.java
@@ -18,8 +18,10 @@
import org.elasticsearch.xpack.esql.core.type.DataType;
import org.elasticsearch.xpack.esql.core.type.DataTypeConverter;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
@@ -35,7 +37,13 @@ public static Expression.TypeResolution resolve(
TypeResolutions.ParamOrdinal paramOrdinal,
Map allowedOptions
) {
- return resolve(options, source, paramOrdinal, allowedOptions, null);
+ return resolve(
+ options,
+ source,
+ paramOrdinal,
+ null,
+ (opts, optsMap) -> populateMap(opts, optsMap, source, paramOrdinal, allowedOptions)
+ );
}
public static Expression.TypeResolution resolve(
@@ -44,6 +52,37 @@ public static Expression.TypeResolution resolve(
TypeResolutions.ParamOrdinal paramOrdinal,
Map allowedOptions,
Consumer