Skip to content

Commit

Permalink
Adding support for casting on the field type and allowing multi-index…
Browse files Browse the repository at this point in the history
… queries with different types
  • Loading branch information
carlosdelest committed Dec 3, 2024
1 parent edf9838 commit 347b3ce
Show file tree
Hide file tree
Showing 11 changed files with 1,120 additions and 849 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
public class CsvTestsDataLoader {
private static final int BULK_DATA_SIZE = 100_000;
private static final TestsDataset EMPLOYEES = new TestsDataset("employees", "mapping-default.json", "employees.csv").noSubfields();
private static final TestsDataset EMPLOYEES_INCOMPATIBLE = new TestsDataset(
"employees_incompatible",
"mapping-default-incompatible.json",
"employees_incompatible.csv"
).noSubfields();
private static final TestsDataset HOSTS = new TestsDataset("hosts");
private static final TestsDataset APPS = new TestsDataset("apps");
private static final TestsDataset APPS_SHORT = APPS.withIndex("apps_short").withTypeMapping(Map.of("id", "short"));
Expand Down Expand Up @@ -98,6 +103,7 @@ public class CsvTestsDataLoader {

public static final Map<String, TestsDataset> CSV_DATASET_MAP = Map.ofEntries(
Map.entry(EMPLOYEES.indexName, EMPLOYEES),
Map.entry(EMPLOYEES_INCOMPATIBLE.indexName, EMPLOYEES_INCOMPATIBLE),
Map.entry(HOSTS.indexName, HOSTS),
Map.entry(APPS.indexName, APPS),
Map.entry(APPS_SHORT.indexName, APPS_SHORT),
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"properties" : {
"emp_no" : {
"type" : "long"
},
"first_name" : {
"type" : "text"
},
"last_name" : {
"type" : "text"
},
"gender" : {
"type" : "text"
},
"birth_date": {
"type" : "date"
},
"hire_date": {
"type" : "date"
},
"salary" : {
"type" : "long"
},
"languages" : {
"type" : "byte",
"fields": {
"long": {
"type": "long"
},
"short": {
"type": "short"
},
"int": {
"type": "integer"
}
}
},
"height": {
"type" : "float",
"fields" : {
"double" : {
"type" : "double"
},
"scaled_float": {
"type": "scaled_float",
"scaling_factor": 100
},
"half_float": {
"type": "half_float"
}
}
},
"still_hired": {
"type" : "keyword"
},
"avg_worked_seconds" : {
"type" : "unsigned_long"
},
"job_positions" : {
"type" : "text"
},
"is_rehired" : {
"type" : "text"
},
"salary_change": {
"type": "float",
"fields": {
"int": {
"type": "integer"
},
"long": {
"type": "long"
},
"keyword": {
"type" : "keyword"
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,19 @@ emp_no:integer | height:double
10048 | 2.0
10098 | 2.0
;

testMatchMultipleFieldTypes
required_capability: match_function
required_capability: match_additional_types

from employees,employees_incompatible
| where match(emp_no::int, 10005)
| eval emp_as_int = emp_no::int
| eval name_as_kw = first_name::keyword
| keep emp_as_int, name_as_kw
;

emp_as_int:integer | name_as_kw:keyword
10005 | Kyoichi
10005 | Kyoichi
;
Original file line number Diff line number Diff line change
Expand Up @@ -469,3 +469,20 @@ emp_no:integer | height:double
10048 | 2.0
10098 | 2.0
;


testMatchMultipleFieldTypes
required_capability: match_function
required_capability: match_additional_types

from employees,employees_incompatible
| where emp_no::int : 10005
| eval emp_as_int = emp_no::int
| eval name_as_kw = first_name::keyword
| keep emp_as_int, name_as_kw
;

emp_as_int:integer | name_as_kw:keyword
10005 | Kyoichi
10005 | Kyoichi
;
2 changes: 1 addition & 1 deletion x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ regexBooleanExpression
;

matchBooleanExpression
: fieldExp=qualifiedName COLON matchQuery=constant (CAST_OP dataType)?
: fieldExp=qualifiedName (CAST_OP fieldType=dataType)? COLON matchQuery=constant (CAST_OP queryType=dataType)?
;

valueExpression
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -927,12 +927,19 @@ String unresolvedAttributeNameInParam(ParserRuleContext ctx, Expression param) {
@Override
public Expression visitMatchBooleanExpression(EsqlBaseParser.MatchBooleanExpressionContext ctx) {
final Expression matchQueryExpression;
if (ctx.dataType() != null) {
matchQueryExpression = castToType(source(ctx), ctx.matchQuery, ctx.dataType());
if (ctx.queryType != null) {
matchQueryExpression = castToType(source(ctx), ctx.matchQuery, ctx.queryType);
} else {
matchQueryExpression = expression(ctx.matchQuery);
}

return new Match(source(ctx), expression(ctx.fieldExp), matchQueryExpression);
final Expression matchFieldExpression;
if (ctx.fieldType != null) {
matchFieldExpression = castToType(source(ctx), ctx.fieldExp, ctx.fieldType);
} else {
matchFieldExpression = expression(ctx.fieldExp);
}

return new Match(source(ctx), matchFieldExpression, matchQueryExpression);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery;
import org.elasticsearch.xpack.esql.core.tree.Source;
import org.elasticsearch.xpack.esql.core.type.DataType;
import org.elasticsearch.xpack.esql.core.type.MultiTypeEsField;
import org.elasticsearch.xpack.esql.core.util.Check;
import org.elasticsearch.xpack.esql.expression.function.fulltext.Kql;
import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
Expand Down Expand Up @@ -531,7 +532,17 @@ private static RangeQuery translate(Range r, TranslatorHandler handler) {
public static class MatchFunctionTranslator extends ExpressionTranslator<Match> {
@Override
protected Query asQuery(Match match, TranslatorHandler handler) {
return new MatchQuery(match.source(), ((FieldAttribute) match.field()).name(), match.queryAsObject());
Expression field = match.field();
if (field instanceof FieldAttribute fieldAttribute) {
String fieldName = fieldAttribute.name();
if (fieldAttribute.field() instanceof MultiTypeEsField multiTypeEsField) {
// If we have multiple field types, we allow the query to be done, but getting the underlying field name
fieldName = multiTypeEsField.getName();
}
return new MatchQuery(match.source(), fieldName, match.queryAsObject());
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.elasticsearch.xpack.esql.expression.function.aggregate.FilteredExpression;
import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToIP;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToInteger;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.RLike;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLike;
import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add;
Expand Down Expand Up @@ -2334,7 +2335,7 @@ public void testInvalidMatchOperator() {
);
}

public void testMatchFunctionCasting() {
public void testMatchFunctionQueryCasting() {
var plan = statement("FROM test | WHERE match(field, \"value\"::IP)");
var filter = as(plan, Filter.class);
var function = (UnresolvedFunction) filter.condition();
Expand All @@ -2344,7 +2345,7 @@ public void testMatchFunctionCasting() {
assertThat(literal.value(), equalTo("value"));
}

public void testMatchOperatorCasting() {
public void testMatchOperatorQueryCasting() {
var plan = statement("FROM test | WHERE field:\"value\"::IP");
var filter = as(plan, Filter.class);
var match = (Match) filter.condition();
Expand All @@ -2354,4 +2355,24 @@ public void testMatchOperatorCasting() {
var literal = (Literal) toIp.field();
assertThat(literal.value(), equalTo("value"));
}

public void testMatchFunctionFieldCasting() {
var plan = statement("FROM test | WHERE match(field::int, \"value\")");
var filter = as(plan, Filter.class);
var function = (UnresolvedFunction) filter.condition();
var toInteger = (ToInteger) function.children().get(0);
var matchField = (UnresolvedAttribute) toInteger.field();
assertThat(matchField.name(), equalTo("field"));
assertThat(function.children().get(1).fold(), equalTo("value"));
}

public void testMatchOperatorFieldCasting() {
var plan = statement("FROM test | WHERE field::int : \"value\"");
var filter = as(plan, Filter.class);
var match = (Match) filter.condition();
var toInteger = (ToInteger) match.field();
var matchField = (UnresolvedAttribute) toInteger.field();
assertThat(matchField.name(), equalTo("field"));
assertThat(match.query().fold(), equalTo("value"));
}
}

0 comments on commit 347b3ce

Please sign in to comment.