Skip to content

EQL: Add wildcard function #54020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Apr 3, 2020
Merged

EQL: Add wildcard function #54020

merged 16 commits into from
Apr 3, 2020

Conversation

rw-access
Copy link
Contributor

Resolves #53999

  • Added wildcard variadic function
  • Added variadic builder QL for single argument + variadic
  • Added method to wildcard function to convert to an Or of Likes, and updated Optimizer rule to uses that.
  • Using makePipe, doProcess, etc on the converted Or of Likes.

@rw-access rw-access added the :Analytics/EQL EQL querying label Mar 23, 2020
@rw-access rw-access requested review from astefan and costin March 23, 2020 20:23
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search (:Search/EQL)

Copy link
Member

@costin costin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a round of comments

}

public Wildcard(Source source, Expression field, List<Expression> patterns) {
super(source, getArguments(field, patterns));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
super(source, getArguments(field, patterns));
super(source, Arrays.asList(field, patterns));

like the rest of the subclasses.

Copy link
Contributor Author

@rw-access rw-access Mar 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't seem to work if the first value is a T, and the next is a List<T>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CollectionUtils.combine(patterns, field) or if you want to preserve the order:
CollectionUtils.combine(singletonList(field), patterns)

* wildcard(field, "*wildcard*pattern*", "*wildcard*pattern*")
*/

public class Wildcard extends ScalarFunction {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please implement the methods in the order of the super class (which is not alphabetical) which roughly is:

constructor
nodeInfo/replaceChildren
type resolution
getters
datatype/nullable
foldable/fold
scripting & co
equals/hash

@@ -421,4 +421,26 @@ public static FunctionDefinition def(Class<? extends Function> function, Functio
protected interface CastFunctionBuilder<T> {
T build(Source source, Expression expression, DataType dataType);
}

@SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do
public static <T extends Function> FunctionDefinition def(Class<T> function,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How many arguments does wildcard expect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at least two, but it's unbounded in the maximum number
https://eql.readthedocs.io/en/latest/query-guide/functions.html#wildcard

Copy link
Contributor

@astefan astefan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments. Some of these are probably because of my lack of understanding of how wildcard should work and what the scenarios it's covering.

private static FunctionDefinition[][] functions() {
return new FunctionDefinition[][] {
// Scalar functions
// String
new FunctionDefinition[] {
def(Substring.class, Substring::new, "substring"),
},
new FunctionDefinition[] {
def(Wildcard.class, Wildcard::new, "wildcard"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't wildcard a "string function"? If so, it should belong to the FunctionDefinition array that, also, has substring in it. In SQL we were grouping these functions by their type: string, grouping, math, conditional, date etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right, good catch


@Override
protected TypeResolution resolveType() {
if (!childrenResolved()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

childrenResolved() == false


@Override
public boolean foldable() {
return Expressions.foldable(arguments());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the field be, also, foldable? (ie return Expressions.foldable(children());)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since wildcard is converted to a bunch of LIKEs, I'm wondering if foldable() shouldn't fall back to the result of the wildcard -> LIKEs transformation foldable() functionality. Basically the Or.foldable().

Copy link
Contributor Author

@rw-access rw-access Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arguments() = field + patterns()
arguments() comes from the super and is identical to children()

I'll swap to children() since that's more obvious

}

for (Expression p: patterns) {
lastResolution = isStringAndExact(p, sourceText(), ParamOrdinal.DEFAULT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think isStringAndExact is correct here... "exact" refers to a field being of type keyword or having a sub-field of type keyword basically. isString should be enough imo.
Also, shouldn't the p.foldable() == false (comparison against variables basically) check be before this one?

return result;
}

private static List<Expression> toArguments(Expression src, List<Expression> patterns) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move this method to org.elasticsearch.xpack.ql.util.CollectionUtils and make it more generic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw this kind fo construct used in few places

CollectionUtils.combine(singletonList(src), patterns))

Comment on lines 70 to 74
if (e instanceof Wildcard) {
e = ((Wildcard) e).asLikes();
}

return e;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return e instanceof Wildcard ? ((Wildcard) e).asLikes() : e; as a shorter (hopefully more elegant) variant?

@@ -22,4 +24,19 @@ public void testPropertyEquationInClauseFilterUnsupported() {
String msg = e.getMessage();
assertEquals("Line 1:52: Comparisons against variables are not (currently) supported; offender [parent_process_name] in [==]", msg);
}

public void testWildcardNotEnoughArguments() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are other error messages to check with wildcard: the fact that the field needs to be string and exact and, also, that the "patterns" should be all strings, no?

Copy link
Member

@costin costin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@matriv
Copy link
Contributor

matriv commented Mar 30, 2020

@elastic/es-ql

@rw-access rw-access requested a review from aleksmaus March 30, 2020 20:22
@rw-access rw-access requested a review from astefan April 2, 2020 14:42
@rw-access rw-access merged commit f04fb68 into elastic:master Apr 3, 2020
@rw-access rw-access deleted the eql/wildcard-function branch April 3, 2020 16:14
rw-access added a commit that referenced this pull request Apr 3, 2020
* EQL: Add wildcard function
* EQL: Cleanup Wildcard.getArguments
* EQL: Cleanup Wildcard and rearrange methods
* EQL: Wildcard newline lint
* EQL: Make StringUtils function final
* EQL: Make Wildcard.asLikes return ScalarFunction
* QL: Restore BinaryLogic.java
* EQL: Add Wildcard PR feedback
* EQL: Add Wildcard verification tests
* EQL: Switch wildcard to isFoldable test
* EQL: Change wildcard test to numeric field
* EQL: Remove Wildcard.get_arguments
@rw-access
Copy link
Contributor Author

Backport 022f829

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Analytics/EQL EQL querying
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EQL: implement wildcard function
6 participants