Skip to content

Commit 9060cba

Browse files
committed
Use lenient match queries to allow mixed data fields with wrong values provided in the query
1 parent fa14ff5 commit 9060cba

File tree

4 files changed

+36
-11
lines changed

4 files changed

+36
-11
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,15 @@ hire_date_nanos:date_nanos
547547
1986-06-26T00:00:00.000Z
548548
;
549549

550+
testMatchWithWrongFieldValue
551+
required_capability: match_function
552+
required_capability: match_additional_types
553+
554+
from employees,employees_incompatible
555+
| where match(still_hired::boolean, "Wrong boolean")
556+
| eval emp_no_bool = emp_no::boolean
557+
| keep emp_no_bool
558+
;
550559

560+
emp_no_bool:boolean
561+
;

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,3 +568,16 @@ hire_date_nanos:date_nanos
568568
1986-06-26T00:00:00.000Z
569569
;
570570

571+
testMatchWithWrongFieldValue
572+
required_capability: match_function
573+
required_capability: match_additional_types
574+
575+
from employees,employees_incompatible
576+
| where still_hired::boolean : "Wrong boolean"
577+
| eval emp_no_bool = emp_no::boolean
578+
| keep emp_no_bool
579+
;
580+
581+
emp_no_bool:boolean
582+
;
583+

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,8 @@ protected Query asQuery(Match match, TranslatorHandler handler) {
544544
// If we have multiple field types, we allow the query to be done, but getting the underlying field name
545545
fieldName = multiTypeEsField.getName();
546546
}
547-
return new MatchQuery(match.source(), fieldName, match.queryAsObject());
547+
// Make query lenient so mixed field types can be queried when a field type is incompatible with the value provided
548+
return new MatchQuery(match.source(), fieldName, match.queryAsObject(), Map.of("lenient", "true"));
548549
}
549550

550551
throw new IllegalArgumentException("Match must have a field attribute as the first argument");

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ public void testMatchFunction() {
646646
var field = as(project.child(), FieldExtractExec.class);
647647
var query = as(field.child(), EsQueryExec.class);
648648
assertThat(query.limit().fold(), is(1000));
649-
var expected = QueryBuilders.matchQuery("last_name", "Smith");
649+
var expected = QueryBuilders.matchQuery("last_name", "Smith").lenient(true);
650650
assertThat(query.query().toString(), is(expected.toString()));
651651
}
652652

@@ -678,7 +678,7 @@ public void testMatchFunctionConjunctionWhereOperands() {
678678

679679
Source filterSource = new Source(2, 38, "emp_no > 10000");
680680
var range = wrapWithSingleQuery(queryText, QueryBuilders.rangeQuery("emp_no").gt(10010), "emp_no", filterSource);
681-
var queryString = QueryBuilders.matchQuery("last_name", "Smith");
681+
var queryString = QueryBuilders.matchQuery("last_name", "Smith").lenient(true);
682682
var expected = QueryBuilders.boolQuery().must(queryString).must(range);
683683
assertThat(query.query().toString(), is(expected.toString()));
684684
}
@@ -713,7 +713,7 @@ public void testMatchFunctionWithFunctionsPushedToLucene() {
713713

714714
Source filterSource = new Source(2, 32, "cidr_match(ip, \"127.0.0.1/32\")");
715715
var terms = wrapWithSingleQuery(queryText, QueryBuilders.termsQuery("ip", "127.0.0.1/32"), "ip", filterSource);
716-
var queryString = QueryBuilders.matchQuery("text", "beta");
716+
var queryString = QueryBuilders.matchQuery("text", "beta").lenient(true);
717717
var expected = QueryBuilders.boolQuery().must(queryString).must(terms);
718718
assertThat(query.query().toString(), is(expected.toString()));
719719
}
@@ -747,7 +747,7 @@ public void testMatchFunctionMultipleWhereClauses() {
747747

748748
Source filterSource = new Source(3, 8, "emp_no > 10000");
749749
var range = wrapWithSingleQuery(queryText, QueryBuilders.rangeQuery("emp_no").gt(10010), "emp_no", filterSource);
750-
var queryString = QueryBuilders.matchQuery("last_name", "Smith");
750+
var queryString = QueryBuilders.matchQuery("last_name", "Smith").lenient(true);
751751
var expected = QueryBuilders.boolQuery().must(queryString).must(range);
752752
assertThat(query.query().toString(), is(expected.toString()));
753753
}
@@ -777,8 +777,8 @@ public void testMatchFunctionMultipleMatchClauses() {
777777
var query = as(field.child(), EsQueryExec.class);
778778
assertThat(query.limit().fold(), is(1000));
779779

780-
var queryStringLeft = QueryBuilders.matchQuery("last_name", "Smith");
781-
var queryStringRight = QueryBuilders.matchQuery("first_name", "John");
780+
var queryStringLeft = QueryBuilders.matchQuery("last_name", "Smith").lenient(true);
781+
var queryStringRight = QueryBuilders.matchQuery("first_name", "John").lenient(true);
782782
var expected = QueryBuilders.boolQuery().must(queryStringLeft).must(queryStringRight);
783783
assertThat(query.query().toString(), is(expected.toString()));
784784
}
@@ -1476,7 +1476,7 @@ private void checkMatchFunctionPushDown(
14761476
var fieldExtract = as(project.child(), FieldExtractExec.class);
14771477
var actualLuceneQuery = as(fieldExtract.child(), EsQueryExec.class).query();
14781478

1479-
var expectedLuceneQuery = new MatchQueryBuilder(fieldName, expectedValueProvider.apply(queryValue));
1479+
var expectedLuceneQuery = new MatchQueryBuilder(fieldName, expectedValueProvider.apply(queryValue)).lenient(true);
14801480
assertThat("Unexpected match query for data type " + fieldDataType, actualLuceneQuery, equalTo(expectedLuceneQuery));
14811481
} catch (ParsingException e) {
14821482
fail("Error parsing ESQL query: " + esqlQuery + "\n" + e.getMessage());
@@ -1551,10 +1551,10 @@ public void testMultipleMatchFilterPushdown() {
15511551
var actualLuceneQuery = as(fieldExtract.child(), EsQueryExec.class).query();
15521552

15531553
Source filterSource = new Source(4, 8, "emp_no > 10000");
1554-
var expectedLuceneQuery = new BoolQueryBuilder().must(new MatchQueryBuilder("first_name", "Anna"))
1555-
.must(new MatchQueryBuilder("first_name", "Anneke"))
1554+
var expectedLuceneQuery = new BoolQueryBuilder().must(new MatchQueryBuilder("first_name", "Anna").lenient(true))
1555+
.must(new MatchQueryBuilder("first_name", "Anneke").lenient(true))
15561556
.must(wrapWithSingleQuery(query, QueryBuilders.rangeQuery("emp_no").gt(10000), "emp_no", filterSource))
1557-
.must(new MatchQueryBuilder("last_name", "Xinglin"));
1557+
.must(new MatchQueryBuilder("last_name", "Xinglin").lenient(true));
15581558
assertThat(actualLuceneQuery.toString(), is(expectedLuceneQuery.toString()));
15591559
}
15601560

0 commit comments

Comments
 (0)