Skip to content

Commit 347b3ce

Browse files
committed
Adding support for casting on the field type and allowing multi-index queries with different types
1 parent edf9838 commit 347b3ce

File tree

11 files changed

+1120
-849
lines changed

11 files changed

+1120
-849
lines changed

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
public class CsvTestsDataLoader {
5353
private static final int BULK_DATA_SIZE = 100_000;
5454
private static final TestsDataset EMPLOYEES = new TestsDataset("employees", "mapping-default.json", "employees.csv").noSubfields();
55+
private static final TestsDataset EMPLOYEES_INCOMPATIBLE = new TestsDataset(
56+
"employees_incompatible",
57+
"mapping-default-incompatible.json",
58+
"employees_incompatible.csv"
59+
).noSubfields();
5560
private static final TestsDataset HOSTS = new TestsDataset("hosts");
5661
private static final TestsDataset APPS = new TestsDataset("apps");
5762
private static final TestsDataset APPS_SHORT = APPS.withIndex("apps_short").withTypeMapping(Map.of("id", "short"));
@@ -98,6 +103,7 @@ public class CsvTestsDataLoader {
98103

99104
public static final Map<String, TestsDataset> CSV_DATASET_MAP = Map.ofEntries(
100105
Map.entry(EMPLOYEES.indexName, EMPLOYEES),
106+
Map.entry(EMPLOYEES_INCOMPATIBLE.indexName, EMPLOYEES_INCOMPATIBLE),
101107
Map.entry(HOSTS.indexName, HOSTS),
102108
Map.entry(APPS.indexName, APPS),
103109
Map.entry(APPS_SHORT.indexName, APPS_SHORT),

x-pack/plugin/esql/qa/testFixtures/src/main/resources/employees_incompatible.csv

Lines changed: 101 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"properties" : {
3+
"emp_no" : {
4+
"type" : "long"
5+
},
6+
"first_name" : {
7+
"type" : "text"
8+
},
9+
"last_name" : {
10+
"type" : "text"
11+
},
12+
"gender" : {
13+
"type" : "text"
14+
},
15+
"birth_date": {
16+
"type" : "date"
17+
},
18+
"hire_date": {
19+
"type" : "date"
20+
},
21+
"salary" : {
22+
"type" : "long"
23+
},
24+
"languages" : {
25+
"type" : "byte",
26+
"fields": {
27+
"long": {
28+
"type": "long"
29+
},
30+
"short": {
31+
"type": "short"
32+
},
33+
"int": {
34+
"type": "integer"
35+
}
36+
}
37+
},
38+
"height": {
39+
"type" : "float",
40+
"fields" : {
41+
"double" : {
42+
"type" : "double"
43+
},
44+
"scaled_float": {
45+
"type": "scaled_float",
46+
"scaling_factor": 100
47+
},
48+
"half_float": {
49+
"type": "half_float"
50+
}
51+
}
52+
},
53+
"still_hired": {
54+
"type" : "keyword"
55+
},
56+
"avg_worked_seconds" : {
57+
"type" : "unsigned_long"
58+
},
59+
"job_positions" : {
60+
"type" : "text"
61+
},
62+
"is_rehired" : {
63+
"type" : "text"
64+
},
65+
"salary_change": {
66+
"type": "float",
67+
"fields": {
68+
"int": {
69+
"type": "integer"
70+
},
71+
"long": {
72+
"type": "long"
73+
},
74+
"keyword": {
75+
"type" : "keyword"
76+
}
77+
}
78+
}
79+
}
80+
}

x-pack/plugin/esql/qa/testFixtures/src/main/resources/match-function.csv-spec

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,19 @@ emp_no:integer | height:double
449449
10048 | 2.0
450450
10098 | 2.0
451451
;
452+
453+
testMatchMultipleFieldTypes
454+
required_capability: match_function
455+
required_capability: match_additional_types
456+
457+
from employees,employees_incompatible
458+
| where match(emp_no::int, 10005)
459+
| eval emp_as_int = emp_no::int
460+
| eval name_as_kw = first_name::keyword
461+
| keep emp_as_int, name_as_kw
462+
;
463+
464+
emp_as_int:integer | name_as_kw:keyword
465+
10005 | Kyoichi
466+
10005 | Kyoichi
467+
;

x-pack/plugin/esql/qa/testFixtures/src/main/resources/match-operator.csv-spec

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,20 @@ emp_no:integer | height:double
469469
10048 | 2.0
470470
10098 | 2.0
471471
;
472+
473+
474+
testMatchMultipleFieldTypes
475+
required_capability: match_function
476+
required_capability: match_additional_types
477+
478+
from employees,employees_incompatible
479+
| where emp_no::int : 10005
480+
| eval emp_as_int = emp_no::int
481+
| eval name_as_kw = first_name::keyword
482+
| keep emp_as_int, name_as_kw
483+
;
484+
485+
emp_as_int:integer | name_as_kw:keyword
486+
10005 | Kyoichi
487+
10005 | Kyoichi
488+
;

x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ regexBooleanExpression
7878
;
7979

8080
matchBooleanExpression
81-
: fieldExp=qualifiedName COLON matchQuery=constant (CAST_OP dataType)?
81+
: fieldExp=qualifiedName (CAST_OP fieldType=dataType)? COLON matchQuery=constant (CAST_OP queryType=dataType)?
8282
;
8383

8484
valueExpression

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java

Lines changed: 853 additions & 841 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -927,12 +927,19 @@ String unresolvedAttributeNameInParam(ParserRuleContext ctx, Expression param) {
927927
@Override
928928
public Expression visitMatchBooleanExpression(EsqlBaseParser.MatchBooleanExpressionContext ctx) {
929929
final Expression matchQueryExpression;
930-
if (ctx.dataType() != null) {
931-
matchQueryExpression = castToType(source(ctx), ctx.matchQuery, ctx.dataType());
930+
if (ctx.queryType != null) {
931+
matchQueryExpression = castToType(source(ctx), ctx.matchQuery, ctx.queryType);
932932
} else {
933933
matchQueryExpression = expression(ctx.matchQuery);
934934
}
935935

936-
return new Match(source(ctx), expression(ctx.fieldExp), matchQueryExpression);
936+
final Expression matchFieldExpression;
937+
if (ctx.fieldType != null) {
938+
matchFieldExpression = castToType(source(ctx), ctx.fieldExp, ctx.fieldType);
939+
} else {
940+
matchFieldExpression = expression(ctx.fieldExp);
941+
}
942+
943+
return new Match(source(ctx), matchFieldExpression, matchQueryExpression);
937944
}
938945
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery;
3434
import org.elasticsearch.xpack.esql.core.tree.Source;
3535
import org.elasticsearch.xpack.esql.core.type.DataType;
36+
import org.elasticsearch.xpack.esql.core.type.MultiTypeEsField;
3637
import org.elasticsearch.xpack.esql.core.util.Check;
3738
import org.elasticsearch.xpack.esql.expression.function.fulltext.Kql;
3839
import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
@@ -531,7 +532,17 @@ private static RangeQuery translate(Range r, TranslatorHandler handler) {
531532
public static class MatchFunctionTranslator extends ExpressionTranslator<Match> {
532533
@Override
533534
protected Query asQuery(Match match, TranslatorHandler handler) {
534-
return new MatchQuery(match.source(), ((FieldAttribute) match.field()).name(), match.queryAsObject());
535+
Expression field = match.field();
536+
if (field instanceof FieldAttribute fieldAttribute) {
537+
String fieldName = fieldAttribute.name();
538+
if (fieldAttribute.field() instanceof MultiTypeEsField multiTypeEsField) {
539+
// If we have multiple field types, we allow the query to be done, but getting the underlying field name
540+
fieldName = multiTypeEsField.getName();
541+
}
542+
return new MatchQuery(match.source(), fieldName, match.queryAsObject());
543+
}
544+
545+
throw new IllegalArgumentException("Match must have a field attribute as the first argument");
535546
}
536547
}
537548

0 commit comments

Comments
 (0)