Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.common.breaker.NoopCircuitBreaker;
import org.elasticsearch.common.logging.LogConfigurator;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.compute.data.Block;
import org.elasticsearch.compute.data.BlockFactory;
Expand Down Expand Up @@ -44,13 +45,15 @@
import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Case;
import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc;
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs;
import org.elasticsearch.xpack.esql.expression.function.scalar.math.RoundTo;
import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMin;
import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.RLike;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToLower;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToUpper;
import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add;
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals;
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThan;
import org.elasticsearch.xpack.esql.planner.Layout;
import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
import org.elasticsearch.xpack.esql.session.Configuration;
Expand Down Expand Up @@ -128,6 +131,10 @@ static void selfTest() {
"long_equal_to_int",
"mv_min",
"mv_min_ascending",
"round_to_4_via_case",
"round_to_2",
"round_to_3",
"round_to_4",
"rlike",
"to_lower",
"to_lower_ords",
Expand Down Expand Up @@ -240,6 +247,65 @@ private static EvalOperator.ExpressionEvaluator evaluator(String operation) {
RLike rlike = new RLike(Source.EMPTY, keywordField, new RLikePattern(".ar"));
yield EvalMapper.toEvaluator(FOLD_CONTEXT, rlike, layout(keywordField)).get(driverContext);
}
case "round_to_4_via_case" -> {
FieldAttribute f = longField();

Expression ltkb = new LessThan(Source.EMPTY, f, kb());
Expression ltmb = new LessThan(Source.EMPTY, f, mb());
Expression ltgb = new LessThan(Source.EMPTY, f, gb());
EvalOperator.ExpressionEvaluator evaluator = EvalMapper.toEvaluator(
FOLD_CONTEXT,
new Case(Source.EMPTY, ltkb, List.of(b(), ltmb, kb(), ltgb, mb(), gb())),
layout(f)
).get(driverContext);
String desc = "CaseLazyEvaluator";
if (evaluator.toString().contains(desc) == false) {
throw new IllegalArgumentException("Evaluator was [" + evaluator + "] but expected one containing [" + desc + "]");
}
yield evaluator;
}
case "round_to_2" -> {
FieldAttribute f = longField();

EvalOperator.ExpressionEvaluator evaluator = EvalMapper.toEvaluator(
FOLD_CONTEXT,
new RoundTo(Source.EMPTY, f, List.of(b(), kb())),
layout(f)
).get(driverContext);
String desc = "RoundToLong2";
if (evaluator.toString().contains(desc) == false) {
throw new IllegalArgumentException("Evaluator was [" + evaluator + "] but expected one containing [" + desc + "]");
}
yield evaluator;
}
case "round_to_3" -> {
FieldAttribute f = longField();

EvalOperator.ExpressionEvaluator evaluator = EvalMapper.toEvaluator(
FOLD_CONTEXT,
new RoundTo(Source.EMPTY, f, List.of(b(), kb(), mb())),
layout(f)
).get(driverContext);
String desc = "RoundToLong3";
if (evaluator.toString().contains(desc) == false) {
throw new IllegalArgumentException("Evaluator was [" + evaluator + "] but expected one containing [" + desc + "]");
}
yield evaluator;
}
case "round_to_4" -> {
FieldAttribute f = longField();

EvalOperator.ExpressionEvaluator evaluator = EvalMapper.toEvaluator(
FOLD_CONTEXT,
new RoundTo(Source.EMPTY, f, List.of(b(), kb(), mb(), gb())),
layout(f)
).get(driverContext);
String desc = "RoundToLong4";
if (evaluator.toString().contains(desc) == false) {
throw new IllegalArgumentException("Evaluator was [" + evaluator + "] but expected one containing [" + desc + "]");
}
yield evaluator;
}
case "to_lower", "to_lower_ords" -> {
FieldAttribute keywordField = keywordField();
ToLower toLower = new ToLower(Source.EMPTY, keywordField, configuration());
Expand Down Expand Up @@ -419,6 +485,69 @@ private static void checkExpected(String operation, Page actual) {
}
}
}
case "round_to_4_via_case", "round_to_4" -> {
long b = 1;
long kb = ByteSizeUnit.KB.toBytes(1);
long mb = ByteSizeUnit.MB.toBytes(1);
long gb = ByteSizeUnit.GB.toBytes(1);

LongVector f = actual.<LongBlock>getBlock(0).asVector();
LongVector result = actual.<LongBlock>getBlock(1).asVector();
for (int i = 0; i < BLOCK_LENGTH; i++) {
long expected = f.getLong(i);
if (expected < kb) {
expected = b;
} else if (expected < mb) {
expected = kb;
} else if (expected < gb) {
expected = mb;
} else {
expected = gb;
}
if (result.getLong(i) != expected) {
throw new AssertionError("[" + operation + "] expected [" + expected + "] but was [" + result.getLong(i) + "]");
}
}
}
case "round_to_3" -> {
long b = 1;
long kb = ByteSizeUnit.KB.toBytes(1);
long mb = ByteSizeUnit.MB.toBytes(1);

LongVector f = actual.<LongBlock>getBlock(0).asVector();
LongVector result = actual.<LongBlock>getBlock(1).asVector();
for (int i = 0; i < BLOCK_LENGTH; i++) {
long expected = f.getLong(i);
if (expected < kb) {
expected = b;
} else if (expected < mb) {
expected = kb;
} else {
expected = mb;
}
if (result.getLong(i) != expected) {
throw new AssertionError("[" + operation + "] expected [" + expected + "] but was [" + result.getLong(i) + "]");
}
}
}
case "round_to_2" -> {
long b = 1;
long kb = ByteSizeUnit.KB.toBytes(1);

LongVector f = actual.<LongBlock>getBlock(0).asVector();
LongVector result = actual.<LongBlock>getBlock(1).asVector();
for (int i = 0; i < BLOCK_LENGTH; i++) {
long expected = f.getLong(i);
if (expected < kb) {
expected = b;
} else {
expected = kb;
}
if (result.getLong(i) != expected) {
throw new AssertionError("[" + operation + "] expected [" + expected + "] but was [" + result.getLong(i) + "]");
}
}
}
case "to_lower" -> checkBytes(operation, actual, false, new BytesRef[] { new BytesRef("foo"), new BytesRef("bar") });
case "to_lower_ords" -> checkBytes(operation, actual, true, new BytesRef[] { new BytesRef("foo"), new BytesRef("bar") });
case "to_upper" -> checkBytes(operation, actual, false, new BytesRef[] { new BytesRef("FOO"), new BytesRef("BAR") });
Expand Down Expand Up @@ -450,7 +579,7 @@ private static void checkBytes(String operation, Page actual, boolean expectOrds

private static Page page(String operation) {
return switch (operation) {
case "abs", "add", "date_trunc", "equal_to_const" -> {
case "abs", "add", "date_trunc", "equal_to_const", "round_to_4_via_case", "round_to_2", "round_to_3", "round_to_4" -> {
var builder = blockFactory.newLongBlockBuilder(BLOCK_LENGTH);
for (int i = 0; i < BLOCK_LENGTH; i++) {
builder.appendLong(i * 100_000);
Expand Down Expand Up @@ -540,6 +669,22 @@ private static Page page(String operation) {
};
}

private static Literal b() {
return new Literal(Source.EMPTY, 1L, DataType.LONG);
}

private static Literal kb() {
return new Literal(Source.EMPTY, ByteSizeUnit.KB.toBytes(1), DataType.LONG);
}

private static Literal mb() {
return new Literal(Source.EMPTY, ByteSizeUnit.MB.toBytes(1), DataType.LONG);
}

private static Literal gb() {
return new Literal(Source.EMPTY, ByteSizeUnit.GB.toBytes(1), DataType.LONG);
}

@Benchmark
@OperationsPerInvocation(1024 * BLOCK_LENGTH)
public void run() {
Expand Down
5 changes: 5 additions & 0 deletions docs/changelog/128278.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 128278
summary: ROUND_TO function
area: ES|QL
type: enhancement
issues: []

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading