Skip to content

Commit b182a87

Browse files
committed
Additional tests and checks for using multi index fields with different types
1 parent 347b3ce commit b182a87

File tree

8 files changed

+213
-8
lines changed

8 files changed

+213
-8
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
birth_date:date ,emp_no:long,first_name:text,gender:text,hire_date:date,languages:byte,languages.long:long,languages.short:short,languages.byte:byte,last_name:text,salary:long,height:float,height.float:float,height.scaled_float:scaled_float,height.half_float:half_float,still_hired:keyword,avg_worked_seconds:unsigned_long,job_positions:text,is_rehired:keyword,salary_change:float,salary_change.int:integer,salary_change.long:long,salary_change.keyword:keyword
1+
birth_date:date_nanos ,emp_no:long,first_name:text,gender:text,hire_date:date_nanos,languages:byte,languages.long:long,languages.short:short,languages.byte:byte,last_name:text,salary:long,height:float,height.double:double,height.scaled_float:scaled_float,height.half_float:half_float,still_hired:keyword,avg_worked_seconds:unsigned_long,job_positions:text,is_rehired:keyword,salary_change:float,salary_change.int:integer,salary_change.long:long,salary_change.keyword:keyword
22
1953-09-02T00:00:00Z,10001,Georgi ,M,1986-06-26T00:00:00Z,2,2,2,2,Facello ,57305,2.03,2.03,2.03,2.03,true ,268728049,[Senior Python Developer,Accountant],[false,true],[1.19],[1],[1],[1.19]
33
1964-06-02T00:00:00Z,10002,Bezalel ,F,1985-11-21T00:00:00Z,5,5,5,5,Simmel ,56371,2.08,2.08,2.08,2.08,true ,328922887,[Senior Team Lead],[false,false],[-7.23,11.17],[-7,11],[-7,11],[-7.23,11.17]
44
1959-12-03T00:00:00Z,10003,Parto ,M,1986-08-28T00:00:00Z,4,4,4,4,Bamford ,61805,1.83,1.83,1.83,1.83,false,200296405,[],[],[14.68,12.82],[14,12],[14,12],[14.68,12.82]

x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-basic.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
"_meta_field": {
2222
"type" : "keyword"
2323
},
24+
"hire_date": {
25+
"type": "date"
26+
},
2427
"job": {
2528
"type": "text",
2629
"fields": {

x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-default-incompatible.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"type" : "date"
1717
},
1818
"hire_date": {
19-
"type" : "date"
19+
"type" : "date_nanos"
2020
},
2121
"salary" : {
2222
"type" : "long"
@@ -60,7 +60,7 @@
6060
"type" : "text"
6161
},
6262
"is_rehired" : {
63-
"type" : "text"
63+
"type" : "keyword"
6464
},
6565
"salary_change": {
6666
"type": "float",

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

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ emp_no:integer | height:double
450450
10098 | 2.0
451451
;
452452

453-
testMatchMultipleFieldTypes
453+
testMatchMultipleFieldTypesIntLong
454454
required_capability: match_function
455455
required_capability: match_additional_types
456456

@@ -465,3 +465,86 @@ emp_as_int:integer | name_as_kw:keyword
465465
10005 | Kyoichi
466466
10005 | Kyoichi
467467
;
468+
469+
testMatchMultipleFieldTypesKeywordText
470+
required_capability: match_function
471+
required_capability: match_additional_types
472+
473+
from employees,employees_incompatible
474+
| where match(first_name::keyword, "Kazuhito")
475+
| eval first_name_kwd = first_name::keyword
476+
| keep first_name_kwd
477+
;
478+
479+
first_name_kwd:keyword
480+
Kazuhito
481+
Kazuhito
482+
;
483+
484+
testMatchMultipleFieldTypesDoubleFloat
485+
required_capability: match_function
486+
required_capability: match_additional_types
487+
488+
from employees,employees_incompatible
489+
| where match(height::double, 2.03)
490+
| eval height_dbl = height::double
491+
| eval emp_no = emp_no::int
492+
| keep emp_no, height_dbl
493+
;
494+
ignoreOrder:true
495+
496+
emp_no:integer | height_dbl:double
497+
10001 | 2.0299999713897705
498+
10090 | 2.0299999713897705
499+
10001 | 2.03
500+
10090 | 2.03
501+
;
502+
503+
testMatchMultipleFieldTypesBooleanKeyword
504+
required_capability: match_function
505+
required_capability: match_additional_types
506+
507+
from employees,employees_incompatible
508+
| where match(still_hired::keyword, "true") and height.scaled_float == 2.08
509+
| eval still_hired_bool = still_hired::boolean
510+
| keep still_hired_bool
511+
;
512+
513+
still_hired_bool:boolean
514+
true
515+
true
516+
true
517+
true
518+
;
519+
520+
testMatchMultipleFieldTypesLongUnsignedLong
521+
required_capability: match_function
522+
required_capability: match_additional_types
523+
524+
from employees,employees_incompatible
525+
| where match(avg_worked_seconds::unsigned_long, 200296405)
526+
| eval avg_worked_seconds_ul = avg_worked_seconds::unsigned_long
527+
| keep avg_worked_seconds_ul
528+
;
529+
530+
avg_worked_seconds_ul:unsigned_long
531+
200296405
532+
200296405
533+
;
534+
535+
testMatchMultipleFieldTypesDateNanosDate
536+
required_capability: match_function
537+
required_capability: match_additional_types
538+
539+
from employees,employees_incompatible
540+
| where match(hire_date::datetime, "1986-06-26T00:00:00.000Z")
541+
| eval hire_date_nanos = hire_date::date_nanos
542+
| keep hire_date_nanos
543+
;
544+
545+
hire_date_nanos:date_nanos
546+
1986-06-26T00:00:00.000Z
547+
1986-06-26T00:00:00.000Z
548+
;
549+
550+

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,6 @@ emp_no:integer | height:double
470470
10098 | 2.0
471471
;
472472

473-
474473
testMatchMultipleFieldTypes
475474
required_capability: match_function
476475
required_capability: match_additional_types
@@ -486,3 +485,86 @@ emp_as_int:integer | name_as_kw:keyword
486485
10005 | Kyoichi
487486
10005 | Kyoichi
488487
;
488+
489+
490+
testMatchMultipleFieldTypesKeywordText
491+
required_capability: match_function
492+
required_capability: match_additional_types
493+
494+
from employees,employees_incompatible
495+
| where first_name::keyword : "Kazuhito"
496+
| eval first_name_kwd = first_name::keyword
497+
| keep first_name_kwd
498+
;
499+
500+
first_name_kwd:keyword
501+
Kazuhito
502+
Kazuhito
503+
;
504+
505+
testMatchMultipleFieldTypesDoubleFloat
506+
required_capability: match_function
507+
required_capability: match_additional_types
508+
509+
from employees,employees_incompatible
510+
| where height::double : 2.03
511+
| eval height_dbl = height::double
512+
| eval emp_no = emp_no::int
513+
| keep emp_no, height_dbl
514+
;
515+
ignoreOrder:true
516+
517+
emp_no:integer | height_dbl:double
518+
10001 | 2.0299999713897705
519+
10090 | 2.0299999713897705
520+
10001 | 2.03
521+
10090 | 2.03
522+
;
523+
524+
testMatchMultipleFieldTypesBooleanKeyword
525+
required_capability: match_function
526+
required_capability: match_additional_types
527+
528+
from employees,employees_incompatible
529+
| where still_hired::keyword : "true" and height.scaled_float == 2.08
530+
| eval still_hired_bool = still_hired::boolean
531+
| keep still_hired_bool
532+
;
533+
534+
still_hired_bool:boolean
535+
true
536+
true
537+
true
538+
true
539+
;
540+
541+
testMatchMultipleFieldTypesLongUnsignedLong
542+
required_capability: match_function
543+
required_capability: match_additional_types
544+
545+
from employees,employees_incompatible
546+
| where avg_worked_seconds::unsigned_long : 200296405
547+
| eval avg_worked_seconds_ul = avg_worked_seconds::unsigned_long
548+
| keep avg_worked_seconds_ul
549+
;
550+
551+
avg_worked_seconds_ul:unsigned_long
552+
200296405
553+
200296405
554+
;
555+
556+
testMatchMultipleFieldTypesDateNanosDate
557+
required_capability: match_function
558+
required_capability: match_additional_types
559+
560+
from employees,employees_incompatible
561+
| where hire_date::datetime : "1986-06-26T00:00:00.000Z"
562+
| eval hire_date_nanos = hire_date::date_nanos
563+
| keep hire_date_nanos
564+
;
565+
566+
hire_date_nanos:date_nanos
567+
1986-06-26T00:00:00.000Z
568+
1986-06-26T00:00:00.000Z
569+
;
570+

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.xpack.esql.expression.function.Example;
2626
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
2727
import org.elasticsearch.xpack.esql.expression.function.Param;
28+
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
2829
import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
2930
import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter;
3031

@@ -177,7 +178,12 @@ protected TypeResolution checkParamCompatibility() {
177178

178179
@Override
179180
public void validate(Failures failures) {
180-
if (field instanceof FieldAttribute == false) {
181+
Expression fieldExpression = field();
182+
// Field may be converted to other data type (field_name :: data_type), so we need to check the original field
183+
if (fieldExpression instanceof AbstractConvertFunction convertFunction) {
184+
fieldExpression = convertFunction.field();
185+
}
186+
if (fieldExpression instanceof FieldAttribute == false) {
181187
failures.add(
182188
Failure.fail(
183189
field,

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.xpack.esql.expression.function.fulltext.Kql;
3939
import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
4040
import org.elasticsearch.xpack.esql.expression.function.fulltext.QueryString;
41+
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
4142
import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch;
4243
import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesFunction;
4344
import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils;
@@ -532,8 +533,12 @@ private static RangeQuery translate(Range r, TranslatorHandler handler) {
532533
public static class MatchFunctionTranslator extends ExpressionTranslator<Match> {
533534
@Override
534535
protected Query asQuery(Match match, TranslatorHandler handler) {
535-
Expression field = match.field();
536-
if (field instanceof FieldAttribute fieldAttribute) {
536+
Expression fieldExpression = match.field();
537+
// Field may be converted to other data type (field_name :: data_type), so we need to check the original field
538+
if (fieldExpression instanceof AbstractConvertFunction convertFunction) {
539+
fieldExpression = convertFunction.field();
540+
}
541+
if (fieldExpression instanceof FieldAttribute fieldAttribute) {
537542
String fieldName = fieldAttribute.name();
538543
if (fieldAttribute.field() instanceof MultiTypeEsField multiTypeEsField) {
539544
// If we have multiple field types, we allow the query to be done, but getting the underlying field name

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,32 @@ public void testMultipleMatchFilterPushdown() {
15461546
assertThat(actualLuceneQuery.toString(), is(expectedLuceneQuery.toString()));
15471547
}
15481548

1549+
/**
1550+
* Expects
1551+
* LimitExec[1000[INTEGER]]
1552+
* \_ExchangeExec[[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gender{f}#5, hire_date{f}#10, job{f}#11, job.raw{f}#12
1553+
* \_ProjectExec[[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gender{f}#5, hire_date{f}#10, job{f}#11, job.raw{f}#12
1554+
* \_FieldExtractExec[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gen]
1555+
* \_EsQueryExec[test], indexMode[standard], query[{"match":{"emp_no":{"query":123456}}}][_doc{f}#14],
1556+
* limit[1000], sort[] estimatedRowSize[332]
1557+
*/
1558+
public void testMatchWithFieldCasting() {
1559+
String query = """
1560+
from test
1561+
| where emp_no::long : 123456
1562+
""";
1563+
var plan = plannerOptimizer.plan(query);
1564+
1565+
var limit = as(plan, LimitExec.class);
1566+
var exchange = as(limit.child(), ExchangeExec.class);
1567+
var project = as(exchange.child(), ProjectExec.class);
1568+
var fieldExtract = as(project.child(), FieldExtractExec.class);
1569+
var queryExec = as(fieldExtract.child(), EsQueryExec.class);
1570+
var queryBuilder = as(queryExec.query(), MatchQueryBuilder.class);
1571+
assertThat(queryBuilder.fieldName(), is("emp_no"));
1572+
assertThat(queryBuilder.value(), is(123456));
1573+
}
1574+
15491575
private QueryBuilder wrapWithSingleQuery(String query, QueryBuilder inner, String fieldName, Source source) {
15501576
return FilterTests.singleValueQuery(query, inner, fieldName, source);
15511577
}

0 commit comments

Comments
 (0)