diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/scalar/string/StringContains.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/scalar/string/StringContains.java index 4728f6ad3e0..2f5ed1d4411 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/scalar/string/StringContains.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/scalar/string/StringContains.java @@ -58,6 +58,14 @@ public class StringContains extends CaseSensitiveScalarFunction { return isStringAndExact(substring, sourceText(), Expressions.ParamOrdinal.SECOND); } + public Expression string() { + return string; + } + + public Expression substring() { + return substring; + } + @Override protected Pipe makePipe() { return new StringContainsFunctionPipe(source(), this, diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/planner/QueryTranslator.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/planner/QueryTranslator.java index 6381cd20b14..8f4ad850e03 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/planner/QueryTranslator.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/planner/QueryTranslator.java @@ -7,11 +7,13 @@ package org.elasticsearch.xpack.eql.planner; import org.elasticsearch.xpack.eql.expression.function.scalar.string.CIDRMatch; +import org.elasticsearch.xpack.eql.expression.function.scalar.string.StringContains; import org.elasticsearch.xpack.ql.QlIllegalArgumentException; import org.elasticsearch.xpack.ql.expression.Expression; import org.elasticsearch.xpack.ql.expression.Expressions; import org.elasticsearch.xpack.ql.expression.FieldAttribute; import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.ql.expression.function.scalar.string.CaseSensitiveScalarFunction; import org.elasticsearch.xpack.ql.expression.predicate.logical.And; import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; import org.elasticsearch.xpack.ql.planner.ExpressionTranslator; @@ -20,6 +22,7 @@ import org.elasticsearch.xpack.ql.planner.TranslatorHandler; import org.elasticsearch.xpack.ql.querydsl.query.Query; import org.elasticsearch.xpack.ql.querydsl.query.ScriptQuery; import org.elasticsearch.xpack.ql.querydsl.query.TermsQuery; +import org.elasticsearch.xpack.ql.querydsl.query.WildcardQuery; import org.elasticsearch.xpack.ql.util.CollectionUtils; import java.util.Arrays; @@ -42,6 +45,7 @@ final class QueryTranslator { new ExpressionTranslators.StringQueries(), new ExpressionTranslators.Matches(), new ExpressionTranslators.MultiMatches(), + new CaseSensitiveScalarFunctions(), new Scalars() ); @@ -113,4 +117,34 @@ final class QueryTranslator { return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript())); } } + + public static class CaseSensitiveScalarFunctions extends ExpressionTranslator { + + @Override + protected Query asQuery(CaseSensitiveScalarFunction f, TranslatorHandler handler) { + return f.isCaseSensitive() ? doTranslate(f, handler) : null; + } + + public static Query doTranslate(CaseSensitiveScalarFunction f, TranslatorHandler handler) { + Expression field = null; + Expression constant = null; + + if (f instanceof StringContains) { + StringContains sc = (StringContains) f; + field = sc.string(); + constant = sc.substring(); + } else { + return null; + } + + if (field instanceof FieldAttribute && constant.foldable()) { + String targetFieldName = handler.nameOf(((FieldAttribute) field).exactAttribute()); + String substring = (String) constant.fold(); + + return new WildcardQuery(f.source(), targetFieldName, "*" + substring + "*"); + } + + return null; + } + } } diff --git a/x-pack/plugin/eql/src/test/resources/mapping-default.json b/x-pack/plugin/eql/src/test/resources/mapping-default.json index a065003ddd5..0052eecd7a3 100644 --- a/x-pack/plugin/eql/src/test/resources/mapping-default.json +++ b/x-pack/plugin/eql/src/test/resources/mapping-default.json @@ -56,7 +56,7 @@ "type" : "text", "fields" : { "keyword" : { - "type" : "keyword", + "type" : "wildcard", "ignore_above" : 256 } } diff --git a/x-pack/plugin/eql/src/test/resources/queryfolder_tests.txt b/x-pack/plugin/eql/src/test/resources/queryfolder_tests.txt index 0202769caba..b261a6c803d 100644 --- a/x-pack/plugin/eql/src/test/resources/queryfolder_tests.txt +++ b/x-pack/plugin/eql/src/test/resources/queryfolder_tests.txt @@ -189,12 +189,18 @@ process where startsWith(user_name, 'A') or startsWith(user_name, 'B') {"prefix":{"user_name":{"value":"B","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}] ; -stringContains-caseSensitive +stringContainsExactField-caseSensitive process where stringContains(process_name, "foo") ; -"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalEqlScriptUtils.stringContains( -InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))" -"params":{"v0":"process_name","v1":"foo","v2":true} +{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}}, +{"wildcard":{"process_name":{"wildcard":"*foo*","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}} +; + +stringContainsExactSubField-caseSensitive +process where stringContains(hostname, "foo") +; +{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}}, +{"wildcard":{"hostname.keyword":{"wildcard":"*foo*","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}} ; stringContains-caseInsensitive