Skip to content

Commit c4f70d6

Browse files
Address code review comments
1 parent 82c88ef commit c4f70d6

File tree

7 files changed

+105
-35
lines changed

7 files changed

+105
-35
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionUtils.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import org.elasticsearch.common.lucene.BytesRefs;
1010
import org.elasticsearch.core.Nullable;
11+
import org.elasticsearch.core.Strings;
1112
import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
1213
import org.elasticsearch.xpack.esql.common.Failure;
1314
import org.elasticsearch.xpack.esql.common.Failures;
@@ -148,4 +149,13 @@ public static String queryAsString(Expression queryField, String sourceText) {
148149
format(null, "Query value must be a constant string in [{}], found [{}]", sourceText, queryField)
149150
);
150151
}
152+
153+
public static int intValueOf(Expression field, String sourceText, String fieldName) {
154+
if (field instanceof Literal literal) {
155+
return ((Number) literal.value()).intValue();
156+
}
157+
throw new EsqlIllegalArgumentException(
158+
Strings.format(null, "[{}] value must be a constant number in [{}], found [{}]", fieldName, sourceText, field)
159+
);
160+
}
151161
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@
4242
import java.util.Map;
4343
import java.util.function.Function;
4444

45-
import static org.elasticsearch.core.Strings.format;
4645
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT;
4746
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
4847
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable;
4948
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
5049
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isWholeNumber;
5150
import static org.elasticsearch.xpack.esql.core.util.CollectionUtils.nullSafeList;
51+
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.intValueOf;
5252

5353
public class CountDistinct extends AggregateFunction implements OptionalArgument, ToAggregator, SurrogateExpression {
5454
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
@@ -219,12 +219,7 @@ public AggregatorFunctionSupplier supplier() {
219219
}
220220

221221
private int precisionValue() {
222-
if (precision instanceof Literal literal) {
223-
return ((Number) literal.value()).intValue();
224-
}
225-
throw new EsqlIllegalArgumentException(
226-
format(null, "Precision value must be a constant integer in [{}], found [{}]", source(), precision)
227-
);
222+
return intValueOf(precision, source().text(), "Precision");
228223
}
229224

230225
@Override

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.elasticsearch.compute.aggregation.PercentileDoubleAggregatorFunctionSupplier;
1616
import org.elasticsearch.compute.aggregation.PercentileIntAggregatorFunctionSupplier;
1717
import org.elasticsearch.compute.aggregation.PercentileLongAggregatorFunctionSupplier;
18-
import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
1918
import org.elasticsearch.xpack.esql.core.expression.Expression;
2019
import org.elasticsearch.xpack.esql.core.expression.Literal;
2120
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
@@ -34,11 +33,11 @@
3433
import java.util.List;
3534

3635
import static java.util.Collections.singletonList;
37-
import static org.elasticsearch.core.Strings.format;
3836
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
3937
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
4038
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable;
4139
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
40+
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.intValueOf;
4241

4342
public class Percentile extends NumericAggregate implements SurrogateExpression {
4443
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
@@ -170,12 +169,7 @@ protected AggregatorFunctionSupplier doubleSupplier() {
170169
}
171170

172171
private int percentileValue() {
173-
if (percentile() instanceof Literal literal) {
174-
return ((Number) literal.value()).intValue();
175-
}
176-
throw new EsqlIllegalArgumentException(
177-
format(null, "Percentile value must be a constant number in [{}], found [{}]", source(), percentile)
178-
);
172+
return intValueOf(percentile(), source().text(), "Percentile");
179173
}
180174

181175
@Override

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHand
189189
Check.isTrue(Expressions.foldable(matches), "Expected foldable matches, but got [{}]", matches);
190190

191191
String targetFieldName = handler.nameOf(fa.exactAttribute());
192-
Set<Object> set = new LinkedHashSet<>(matches.stream().map(Foldables::extractLiteralOrReturnSelf).toList());
192+
Set<Object> set = new LinkedHashSet<>(matches.stream().map(Foldables::literalValueOf).toList());
193193

194194
return new TermsQuery(source(), targetFieldName, set);
195195
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
import java.util.ArrayList;
5252
import java.util.Arrays;
5353
import java.util.List;
54-
import java.util.Objects;
5554

5655
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
5756
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
@@ -308,18 +307,6 @@ public String toString() {
308307
}
309308
}
310309

311-
@Override
312-
public boolean equals(Object o) {
313-
if (o == null || getClass() != o.getClass()) return false;
314-
MvSort mvSort = (MvSort) o;
315-
return Objects.equals(field(), mvSort.field()) && Objects.equals(order(), mvSort.order());
316-
}
317-
318-
@Override
319-
public int hashCode() {
320-
return Objects.hash(field(), order());
321-
}
322-
323310
private static class Evaluator implements EvalOperator.ExpressionEvaluator {
324311
private final BlockFactory blockFactory;
325312
private final EvalOperator.ExpressionEvaluator field;

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,16 +615,17 @@ public void testReplaceStatsFilteredAggWithEvalFilterFalseAndNull() {
615615
from test
616616
| stats sum(salary) + 1 where false,
617617
sum(salary) + 3,
618-
sum(salary) + 2 where null
618+
sum(salary) + 2 where null,
619+
sum(salary) + 4 where not true
619620
""");
620621

621622
var project = as(plan, Project.class);
622623
assertThat(
623624
Expressions.names(project.projections()),
624-
contains("sum(salary) + 1 where false", "sum(salary) + 3", "sum(salary) + 2 where null")
625+
contains("sum(salary) + 1 where false", "sum(salary) + 3", "sum(salary) + 2 where null", "sum(salary) + 4 where not true")
625626
);
626627
var eval = as(project.child(), Eval.class);
627-
assertThat(eval.fields().size(), is(3));
628+
assertThat(eval.fields().size(), is(4));
628629

629630
var alias = as(eval.fields().getFirst(), Alias.class);
630631
assertTrue(alias.child().foldable());
@@ -664,6 +665,42 @@ public void testReplaceStatsFilteredAggWithEvalCount() {
664665
assertThat(block.asVector().getLong(0), is(0L));
665666
}
666667

668+
/*
669+
* Limit[1000[INTEGER]]
670+
* \_LocalRelation[[count(salary) where false{r}#3],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
671+
*/
672+
public void testReplaceStatsFilteredAggWithEvalNotTrue() {
673+
var plan = plan("""
674+
from test
675+
| stats count(salary) where not true
676+
""");
677+
678+
var limit = as(plan, Limit.class);
679+
var source = as(limit.child(), LocalRelation.class);
680+
assertThat(Expressions.names(source.output()), contains("count(salary) where not true"));
681+
Block[] blocks = source.supplier().get();
682+
assertThat(blocks.length, is(1));
683+
var block = as(blocks[0], LongVectorBlock.class);
684+
assertThat(block.getPositionCount(), is(1));
685+
assertThat(block.asVector().getLong(0), is(0L));
686+
}
687+
688+
/*
689+
* Limit[1000[INTEGER],false]
690+
* \_Aggregate[[],[COUNT(salary{f}#10,true[BOOLEAN]) AS m1#4]]
691+
* \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..]
692+
*/
693+
public void testReplaceStatsFilteredAggWithEvalNotFalse() {
694+
var plan = plan("""
695+
from test
696+
| stats m1 = count(salary) where not false
697+
""");
698+
var limit = as(plan, Limit.class);
699+
var aggregate = as(limit.child(), Aggregate.class);
700+
assertThat(Expressions.names(aggregate.aggregates()), contains("m1"));
701+
var source = as(aggregate.child(), EsRelation.class);
702+
}
703+
667704
/*
668705
* Project[[count_distinct(salary + 2) + 3 where false{r}#3]]
669706
* \_Eval[[$$COUNTDISTINCT$count_distinct(>$0{r$}#15 + 3[INTEGER] AS count_distinct(salary + 2) + 3 where false]]
@@ -815,6 +852,37 @@ public void testExtractStatsCommonFilter() {
815852
var source = as(filter.child(), EsRelation.class);
816853
}
817854

855+
/*
856+
Limit[1000[INTEGER],false]
857+
\_Aggregate[[],[MIN(salary{f}#15,true[BOOLEAN]) AS m1#4, MAX(salary{f}#15,true[BOOLEAN]) AS m2#8]]
858+
\_Filter[emp_no{f}#10 > 1[INTEGER]]
859+
\_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..]
860+
*/
861+
public void testExtractStatsCommonAlwaysTruePlusOtherFilter() {
862+
var plan = plan("""
863+
from test
864+
| stats m1 = min(salary) where (true and emp_no > 1),
865+
m2 = max(salary) where (1==1 and emp_no > 1)
866+
""");
867+
868+
var limit = as(plan, Limit.class);
869+
var agg = as(limit.child(), Aggregate.class);
870+
assertThat(agg.aggregates().size(), is(2));
871+
872+
var alias = as(agg.aggregates().get(0), Alias.class);
873+
var aggFunc = as(alias.child(), AggregateFunction.class);
874+
assertThat(aggFunc.filter(), is(Literal.TRUE));
875+
876+
alias = as(agg.aggregates().get(1), Alias.class);
877+
aggFunc = as(alias.child(), AggregateFunction.class);
878+
assertThat(aggFunc.filter(), is(Literal.TRUE));
879+
880+
var filter = as(agg.child(), Filter.class);
881+
assertThat(Expressions.name(filter.condition()), is("emp_no > 1"));
882+
883+
var source = as(filter.child(), EsRelation.class);
884+
}
885+
818886
public void testExtractStatsCommonFilterUsingAliases() {
819887
var plan = plan("""
820888
from test

x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/230_folding.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,20 @@ setup:
2626
similarity: l2_norm
2727
ip:
2828
type: ip
29+
favorite_numbers:
30+
type: integer
2931

3032
- do:
3133
bulk:
3234
index: employees
3335
refresh: true
3436
body:
3537
- { "index": { } }
36-
- { "hire_date": "2020-01-01", "salary_change": 100.5, "salary": 50000, "salary_change_long": 100, "name": "Alice Smith", "image_vector": [ 0.1, 0.2, 0.3 ], "ip": "192.168.1.1" }
38+
- { "hire_date": "2020-01-01", "salary_change": 100.5, "salary": 50000, "salary_change_long": 100, "name": "Alice Smith", "image_vector": [ 0.1, 0.2, 0.3 ], "ip": "192.168.1.1" , "favorite_numbers": [ 4, 2, 3 ] }
3739
- { "index": { } }
38-
- { "hire_date": "2021-01-01", "salary_change": 200.5, "salary": 60000, "salary_change_long": 200, "name": "Bob Johnson", "image_vector": [ 0.4, 0.5, 0.6 ], "ip": "192.168.1.2" }
40+
- { "hire_date": "2021-01-01", "salary_change": 200.5, "salary": 60000, "salary_change_long": 200, "name": "Bob Johnson", "image_vector": [ 0.4, 0.5, 0.6 ], "ip": "192.168.1.2" , "favorite_numbers": [ 4, 7, -2 ] }
3941
- { "index": { } }
40-
- { "hire_date": "2019-01-01", "salary_change": 50.5, "salary": 40000, "salary_change_long": 50, "name": "Charlie Smith", "image_vector": [ 0.7, 0.8, 0.9 ], "ip": "10.168.1.2" }
42+
- { "hire_date": "2019-01-01", "salary_change": 50.5, "salary": 40000, "salary_change_long": 50, "name": "Charlie Smith", "image_vector": [ 0.7, 0.8, 0.9 ], "ip": "10.168.1.2" , "favorite_numbers": [ 2, 1, 3 ] }
4143

4244
---
4345
TOP function with constant folding:
@@ -631,6 +633,20 @@ MV_SORT with foldable order:
631633
- match: { columns.2.name: "sd" }
632634
- match: { values.0.1: [ -3, 2, 2, 4 ] }
633635
- match: { values.0.2: [ 4, 2, 2, -3 ] }
636+
---
637+
MV_SORT with foldable order on employee favorite numbers:
638+
- do:
639+
esql.query:
640+
body:
641+
query: |
642+
FROM employees
643+
| WHERE salary == 50000
644+
| EVAL sa = mv_sort(favorite_numbers, CONCAT("AS", "C"))
645+
| KEEP sa
646+
| LIMIT 1
647+
648+
- match: { columns.0.name: "sa" }
649+
- match: { values.0.0: [ 2,3,4 ] }
634650

635651
---
636652
MV_SORT with invalid foldable order:

0 commit comments

Comments
 (0)