EQL: make stringContains function use a wildcard ES query (#61189) (#61313)

(cherry picked from commit 039a7d1c68f6f1ed0e7e6cfb86be6b04eec8051c)
This commit is contained in:
Andrei Stefan 2020-08-19 12:40:48 +03:00 committed by GitHub
parent be4ebfbf46
commit a6c0670a14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 5 deletions

View File

@ -58,6 +58,14 @@ public class StringContains extends CaseSensitiveScalarFunction {
return isStringAndExact(substring, sourceText(), Expressions.ParamOrdinal.SECOND); return isStringAndExact(substring, sourceText(), Expressions.ParamOrdinal.SECOND);
} }
public Expression string() {
return string;
}
public Expression substring() {
return substring;
}
@Override @Override
protected Pipe makePipe() { protected Pipe makePipe() {
return new StringContainsFunctionPipe(source(), this, return new StringContainsFunctionPipe(source(), this,

View File

@ -7,11 +7,13 @@
package org.elasticsearch.xpack.eql.planner; 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.CIDRMatch;
import org.elasticsearch.xpack.eql.expression.function.scalar.string.StringContains;
import org.elasticsearch.xpack.ql.QlIllegalArgumentException; import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
import org.elasticsearch.xpack.ql.expression.Expression; import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.Expressions; import org.elasticsearch.xpack.ql.expression.Expressions;
import org.elasticsearch.xpack.ql.expression.FieldAttribute; import org.elasticsearch.xpack.ql.expression.FieldAttribute;
import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; 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.And;
import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; import org.elasticsearch.xpack.ql.expression.predicate.logical.Or;
import org.elasticsearch.xpack.ql.planner.ExpressionTranslator; 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.Query;
import org.elasticsearch.xpack.ql.querydsl.query.ScriptQuery; import org.elasticsearch.xpack.ql.querydsl.query.ScriptQuery;
import org.elasticsearch.xpack.ql.querydsl.query.TermsQuery; import org.elasticsearch.xpack.ql.querydsl.query.TermsQuery;
import org.elasticsearch.xpack.ql.querydsl.query.WildcardQuery;
import org.elasticsearch.xpack.ql.util.CollectionUtils; import org.elasticsearch.xpack.ql.util.CollectionUtils;
import java.util.Arrays; import java.util.Arrays;
@ -42,6 +45,7 @@ final class QueryTranslator {
new ExpressionTranslators.StringQueries(), new ExpressionTranslators.StringQueries(),
new ExpressionTranslators.Matches(), new ExpressionTranslators.Matches(),
new ExpressionTranslators.MultiMatches(), new ExpressionTranslators.MultiMatches(),
new CaseSensitiveScalarFunctions(),
new Scalars() new Scalars()
); );
@ -113,4 +117,34 @@ final class QueryTranslator {
return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript())); return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript()));
} }
} }
public static class CaseSensitiveScalarFunctions extends ExpressionTranslator<CaseSensitiveScalarFunction> {
@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;
}
}
} }

View File

@ -56,7 +56,7 @@
"type" : "text", "type" : "text",
"fields" : { "fields" : {
"keyword" : { "keyword" : {
"type" : "keyword", "type" : "wildcard",
"ignore_above" : 256 "ignore_above" : 256
} }
} }

View File

@ -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}}] {"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") process where stringContains(process_name, "foo")
; ;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalEqlScriptUtils.stringContains( {"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}},
InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))" {"wildcard":{"process_name":{"wildcard":"*foo*","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}
"params":{"v0":"process_name","v1":"foo","v2":true} ;
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 stringContains-caseInsensitive