Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scripted_metric agg context to unsigned_long #64422

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/64422.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 64422
summary: Add `scripted_metric` agg context to `unsigned_long`
area: Search
type: enhancement
issues:
- 64347
68 changes: 63 additions & 5 deletions docs/reference/mapping/types/unsigned_long.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ GET /my_index/_search
"query": {
"range" : {
"my_counter" : {
"gte" : "9223372036854775808.5",
"gte" : "9223372036854775808",
"lte" : "18446744073709551615"
}
}
Expand All @@ -80,7 +80,7 @@ GET /my_index/_search
--------------------------------
//TEST[continued]


==== Sort values
For queries with sort on an `unsigned_long` field,
for a particular document {es} returns a sort value of the type `long`
if the value of this document is within the range of long values,
Expand All @@ -102,9 +102,6 @@ GET /my_index/_search
//TEST[continued]


==== Unsigned long in scripts
Currently unsigned_long is not supported in scripts.

==== Stored fields
A stored field of `unsigned_long` is stored and returned as `String`.

Expand All @@ -113,6 +110,67 @@ For `terms` aggregations, similarly to sort values, `Long` or
`BigInteger` values are used. For other aggregations,
values are converted to the `double` type.

==== Script values
By default, script values of an `unsigned_long` field are returned as
Java signed `Long`, which means that values that are greater than
`Long.MAX_VALUE` are shown as negative values. You can use
`Long.compareUnsigned(long, long)`, `Long.divideUnsigned(long, long)`
and `Long.remainderUnsigned(long, long)` to correctly work with
these values.

For example, the script below returns a value of the counter
divided by 10.

[source,console]
--------------------------------
GET /my_index/_search
{
"query": {
"match_all" : {}
},
"script_fields": {
"count10" : {
"script": {
"source": "Long.divideUnsigned(doc['my_counter'].value, 10)"
}
}
}
}
--------------------------------
//TEST[continued]


Alternatively, you can treat the unsigned long type as `BigInteger`
in your scripts by using the field API. For example, this script
treats `my_counter` as `BigInteger` with a default value of `BigInteger.ZERO`:

[source,js]
--------------------------------------------------
"script": {
"source": "field('my_counter').asBigInteger(BigInteger.ZERO)"
}
--------------------------------------------------
// NOTCONSOLE

For scripts that need to return float or double values, you
can further convert `BigInteger` values to double or float:

[source,console]
--------------------------------
GET /my_index/_search
{
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "field('my_counter').asBigInteger(BigInteger.ZERO).floatValue()"
}
}
}
}
--------------------------------
//TEST[continued]

==== Queries with mixed numeric types

Searches with mixed numeric types one of which is `unsigned_long` are
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import org.elasticsearch.script.NumberSortScript;
import org.elasticsearch.script.ScoreScript;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptedMetricAggContexts;
import org.elasticsearch.script.StringSortScript;

import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;
import static java.util.Map.entry;

public class DocValuesWhitelistExtension implements PainlessExtension {

Expand All @@ -34,21 +36,18 @@ public class DocValuesWhitelistExtension implements PainlessExtension {
@Override
public Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists() {
List<Whitelist> whitelist = singletonList(WHITELIST);
return Map.of(
FieldScript.CONTEXT,
whitelist,
ScoreScript.CONTEXT,
whitelist,
FilterScript.CONTEXT,
whitelist,
AggregationScript.CONTEXT,
whitelist,
NumberSortScript.CONTEXT,
whitelist,
StringSortScript.CONTEXT,
whitelist,
BucketAggregationSelectorScript.CONTEXT,
whitelist
return Map.ofEntries(
entry(FieldScript.CONTEXT, whitelist),
entry(ScoreScript.CONTEXT, whitelist),
entry(FilterScript.CONTEXT, whitelist),
entry(AggregationScript.CONTEXT, whitelist),
entry(NumberSortScript.CONTEXT, whitelist),
entry(StringSortScript.CONTEXT, whitelist),
entry(BucketAggregationSelectorScript.CONTEXT, whitelist),
entry(ScriptedMetricAggContexts.InitScript.CONTEXT, whitelist),
entry(ScriptedMetricAggContexts.MapScript.CONTEXT, whitelist),
entry(ScriptedMetricAggContexts.CombineScript.CONTEXT, whitelist),
entry(ScriptedMetricAggContexts.ReduceScript.CONTEXT, whitelist)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ setup:
script:
source: "field('ul').isEmpty() == false"
- match: { hits.total.value: 5 }


- do:
search:
index: test1
Expand Down Expand Up @@ -185,6 +187,7 @@ setup:
source: "field('ul').asBigInteger(BigInteger.valueOf(Long.parseUnsignedLong('18446744073709551614'))).doubleValue()"

- match: { hits.total.value: 5 }

- do:
search:
index: test1
Expand All @@ -196,3 +199,36 @@ setup:
source: "Math.abs(doc['ul'].value)"

- match: { hits.total.value: 5 }

---
"Scripted Metric":
- skip:
version: " - 8.0.99"
reason: "context for scripted metric was added in 8.1"

- do:
search:
index: test1
body:
query:
term:
ul: 18446744073709551615
aggs:
sqrt:
scripted_metric:
init_script: |
state.sqrd = []
map_script: |
double v = field('ul').asBigInteger(BigInteger.ZERO).doubleValue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is added in 7.16

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stu-elastic Thanks for your feedback. Indeed field API was added in 7.16, but scripted_metric agg context was added to unsigned_long only from 8.1 ( I should correct 8.0 to 8.1).

state.sqrd.add(v * v)
combine_script: |
state.sqrd
reduce_script: |
def sum = 0.0;
for (s in states) {
for (v in s) {
sum += v;
}
}
return sum
- match: { aggregations.sqrt.value: 3.4028236692093846E38 }