Skip to content

Commit 5b4a3a3

Browse files
authored
EQL: Plug query params into the AstBuilder (#51886)
As the eventType is customizable, plug that into the parser based on the given request.
1 parent 374eca7 commit 5b4a3a3

File tree

10 files changed

+136
-33
lines changed

10 files changed

+136
-33
lines changed

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/action/EqlSearchRequest.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
import java.util.function.Supplier;
2727

2828
import static org.elasticsearch.action.ValidateActions.addValidationError;
29+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.FETCH_SIZE;
30+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.FIELD_EVENT_TYPE;
31+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.FIELD_TIMESTAMP;
32+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.IMPLICIT_JOIN_KEY;
2933

3034
public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Replaceable, ToXContent {
3135

@@ -34,10 +38,10 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
3438
false, true, false);
3539

3640
private QueryBuilder query = null;
37-
private String timestampField = "@timestamp";
38-
private String eventTypeField = "event.category";
39-
private String implicitJoinKeyField = "agent.id";
40-
private int fetchSize = 50;
41+
private String timestampField = FIELD_TIMESTAMP;
42+
private String eventTypeField = FIELD_EVENT_TYPE;
43+
private String implicitJoinKeyField = IMPLICIT_JOIN_KEY;
44+
private int fetchSize = FETCH_SIZE;
4145
private SearchAfterBuilder searchAfterBuilder;
4246
private String rule;
4347

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.eql.action;
8+
9+
public final class RequestDefaults {
10+
11+
private RequestDefaults() {}
12+
13+
public static final String FIELD_TIMESTAMP = "@timestamp";
14+
public static final String FIELD_EVENT_TYPE = "event_type";
15+
public static final String IMPLICIT_JOIN_KEY = "agent.id";
16+
17+
public static int FETCH_SIZE = 50;
18+
}

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/execution/PlanExecutor.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@
1313
import org.elasticsearch.xpack.eql.analysis.PreAnalyzer;
1414
import org.elasticsearch.xpack.eql.analysis.Verifier;
1515
import org.elasticsearch.xpack.eql.optimizer.Optimizer;
16+
import org.elasticsearch.xpack.eql.parser.ParserParams;
1617
import org.elasticsearch.xpack.eql.planner.Planner;
1718
import org.elasticsearch.xpack.eql.session.Configuration;
1819
import org.elasticsearch.xpack.eql.session.EqlSession;
1920
import org.elasticsearch.xpack.eql.session.Results;
2021
import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry;
2122
import org.elasticsearch.xpack.ql.index.IndexResolver;
2223

23-
import java.util.List;
24-
2524
import static org.elasticsearch.action.ActionListener.wrap;
2625

2726
public class PlanExecutor {
@@ -53,7 +52,7 @@ private EqlSession newSession(Configuration cfg) {
5352
return new EqlSession(client, cfg, indexResolver, preAnalyzer, analyzer, optimizer, planner, this);
5453
}
5554

56-
public void eql(Configuration cfg, String eql, List<Object> params, ActionListener<Results> listener) {
57-
newSession(cfg).eql(eql, params, wrap(listener::onResponse, listener::onFailure));
55+
public void eql(Configuration cfg, String eql, ParserParams parserParams, ActionListener<Results> listener) {
56+
newSession(cfg).eql(eql, parserParams, wrap(listener::onResponse, listener::onFailure));
5857
}
5958
}

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/AstBuilder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
public class AstBuilder extends LogicalPlanBuilder {
1313

14+
AstBuilder(ParserParams params) {
15+
super(params);
16+
}
17+
1418
@Override
1519
public LogicalPlan visitSingleStatement(SingleStatementContext ctx) {
1620
return plan(ctx.statement());

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/EqlParser.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,33 @@ public class EqlParser {
3939

4040
/**
4141
* Parses an EQL statement into execution plan
42-
* @param eql - the EQL statement
4342
*/
4443
public LogicalPlan createStatement(String eql) {
44+
return createStatement(eql, new ParserParams());
45+
}
46+
47+
public LogicalPlan createStatement(String eql, ParserParams params) {
4548
if (log.isDebugEnabled()) {
4649
log.debug("Parsing as statement: {}", eql);
4750
}
48-
return invokeParser(eql, EqlBaseParser::singleStatement, AstBuilder::plan);
51+
return invokeParser(eql, params, EqlBaseParser::singleStatement, AstBuilder::plan);
4952
}
5053

5154
public Expression createExpression(String expression) {
55+
return createExpression(expression, new ParserParams());
56+
}
57+
58+
public Expression createExpression(String expression, ParserParams params) {
5259
if (log.isDebugEnabled()) {
5360
log.debug("Parsing as expression: {}", expression);
5461
}
5562

56-
return invokeParser(expression, EqlBaseParser::singleExpression, AstBuilder::expression);
63+
return invokeParser(expression, params, EqlBaseParser::singleExpression, AstBuilder::expression);
5764
}
5865

59-
private <T> T invokeParser(String eql,
66+
private <T> T invokeParser(String eql, ParserParams params,
6067
Function<EqlBaseParser, ParserRuleContext> parseFunction,
61-
BiFunction<AstBuilder, ParserRuleContext, T> visitor) {
68+
BiFunction<AstBuilder, ParserRuleContext, T> visitor) {
6269
try {
6370
EqlBaseLexer lexer = new EqlBaseLexer(new ANTLRInputStream(eql));
6471

@@ -94,7 +101,7 @@ private <T> T invokeParser(String eql,
94101
log.info("Parse tree {} " + tree.toStringTree());
95102
}
96103

97-
return visitor.apply(new AstBuilder(), tree);
104+
return visitor.apply(new AstBuilder(params), tree);
98105
} catch (StackOverflowError e) {
99106
throw new ParsingException("EQL statement is too large, " +
100107
"causing stack overflow when generating the parsing tree: [{}]", eql);

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* or more contributor license agreements. Licensed under the Elastic License;
44
* you may not use this file except in compliance with the Elastic License.
55
*/
6-
76
package org.elasticsearch.xpack.eql.parser;
87

98
import org.elasticsearch.xpack.ql.expression.Expression;
@@ -19,24 +18,26 @@
1918

2019
public abstract class LogicalPlanBuilder extends ExpressionBuilder {
2120

22-
// TODO: these need to be made configurable
23-
private static final String EVENT_TYPE = "event_type";
21+
private final ParserParams params;
22+
23+
public LogicalPlanBuilder(ParserParams params) {
24+
this.params = params;
25+
}
2426

2527
@Override
2628
public LogicalPlan visitEventQuery(EqlBaseParser.EventQueryContext ctx) {
2729
Source source = source(ctx);
2830
Expression condition = expression(ctx.expression());
2931

3032
if (ctx.event != null) {
31-
Source eventTypeSource = source(ctx.event);
32-
String eventTypeName = visitIdentifier(ctx.event);
33-
Literal eventTypeValue = new Literal(eventTypeSource, eventTypeName, DataTypes.KEYWORD);
34-
35-
UnresolvedAttribute eventTypeField = new UnresolvedAttribute(eventTypeSource, EVENT_TYPE);
36-
Expression eventTypeCheck = new Equals(eventTypeSource, eventTypeField, eventTypeValue);
33+
Source eventSource = source(ctx.event);
34+
String eventName = visitIdentifier(ctx.event);
35+
Literal eventValue = new Literal(eventSource, eventName, DataTypes.KEYWORD);
3736

38-
condition = new And(source, eventTypeCheck, condition);
37+
UnresolvedAttribute eventField = new UnresolvedAttribute(eventSource, params.fieldEventType());
38+
Expression eventMatch = new Equals(eventSource, eventField, eventValue);
3939

40+
condition = new And(source, eventMatch, condition);
4041
}
4142

4243
return new Filter(source(ctx), new UnresolvedRelation(Source.EMPTY, null, "", false, ""), condition);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.eql.parser;
8+
9+
import java.util.List;
10+
11+
import static java.util.Collections.emptyList;
12+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.FIELD_EVENT_TYPE;
13+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.FIELD_TIMESTAMP;
14+
import static org.elasticsearch.xpack.eql.action.RequestDefaults.IMPLICIT_JOIN_KEY;
15+
16+
public class ParserParams {
17+
18+
private String fieldEventType = FIELD_EVENT_TYPE;
19+
private String fieldTimestamp = FIELD_TIMESTAMP;
20+
private String implicitJoinKey = IMPLICIT_JOIN_KEY;
21+
private List<Object> queryParams = emptyList();
22+
23+
public String fieldEventType() {
24+
return fieldEventType;
25+
}
26+
27+
public ParserParams fieldEventType(String fieldEventType) {
28+
this.fieldEventType = fieldEventType;
29+
return this;
30+
}
31+
32+
public String fieldTimestamp() {
33+
return fieldTimestamp;
34+
}
35+
36+
public ParserParams fieldTimestamp(String fieldTimestamp) {
37+
this.fieldTimestamp = fieldTimestamp;
38+
return this;
39+
}
40+
41+
public String implicitJoinKey() {
42+
return implicitJoinKey;
43+
}
44+
45+
public ParserParams implicitJoinKey(String implicitJoinKey) {
46+
this.implicitJoinKey = implicitJoinKey;
47+
return this;
48+
}
49+
50+
public List<Object> params() {
51+
return queryParams;
52+
}
53+
54+
public ParserParams params(List<Object> params) {
55+
this.queryParams = params;
56+
return this;
57+
}
58+
}

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/TransportEqlSearchAction.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.xpack.eql.action.EqlSearchRequest;
2626
import org.elasticsearch.xpack.eql.action.EqlSearchResponse;
2727
import org.elasticsearch.xpack.eql.execution.PlanExecutor;
28+
import org.elasticsearch.xpack.eql.parser.ParserParams;
2829
import org.elasticsearch.xpack.eql.session.Configuration;
2930
import org.elasticsearch.xpack.eql.session.Results;
3031

@@ -63,8 +64,13 @@ public static void operation(PlanExecutor planExecutor, EqlSearchRequest request
6364
boolean includeFrozen = request.indicesOptions().ignoreThrottled() == false;
6465
String clientId = null;
6566

67+
ParserParams params = new ParserParams()
68+
.fieldEventType(request.eventTypeField())
69+
.fieldTimestamp(request.timestampField())
70+
.implicitJoinKey(request.implicitJoinKeyField());
71+
6672
Configuration cfg = new Configuration(request.indices(), zoneId, username, clusterName, filter, timeout, includeFrozen, clientId);
67-
//planExecutor.eql(cfg, request.rule(), emptyList(), wrap(r -> listener.onResponse(createResponse(r)), listener::onFailure));
73+
//planExecutor.eql(cfg, request.rule(), params, wrap(r -> listener.onResponse(createResponse(r)), listener::onFailure));
6874
listener.onResponse(createResponse(null));
6975
}
7076

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/EqlSession.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414
import org.elasticsearch.xpack.eql.execution.PlanExecutor;
1515
import org.elasticsearch.xpack.eql.optimizer.Optimizer;
1616
import org.elasticsearch.xpack.eql.parser.EqlParser;
17+
import org.elasticsearch.xpack.eql.parser.ParserParams;
1718
import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan;
1819
import org.elasticsearch.xpack.eql.planner.Planner;
1920
import org.elasticsearch.xpack.ql.index.IndexResolver;
2021
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
21-
import org.elasticsearch.xpack.ql.util.Check;
22-
23-
import java.util.List;
2422

2523
import static org.elasticsearch.action.ActionListener.wrap;
2624

@@ -59,11 +57,11 @@ public Configuration configuration() {
5957
return configuration;
6058
}
6159

62-
public void eql(String eql, List<Object> params, ActionListener<Results> listener) {
60+
public void eql(String eql, ParserParams params, ActionListener<Results> listener) {
6361
eqlExecutable(eql, params, wrap(e -> e.execute(this, listener), listener::onFailure));
6462
}
6563

66-
public void eqlExecutable(String eql, List<Object> params, ActionListener<PhysicalPlan> listener) {
64+
public void eqlExecutable(String eql, ParserParams params, ActionListener<PhysicalPlan> listener) {
6765
try {
6866
physicalPlan(doParse(eql, params), listener);
6967
} catch (Exception ex) {
@@ -96,8 +94,7 @@ private <T> void preAnalyze(LogicalPlan parsed, ActionListener<LogicalPlan> list
9694
}, listener::onFailure));
9795
}
9896

99-
private LogicalPlan doParse(String eql, List<Object> params) {
100-
Check.isTrue(params.isEmpty(), "Parameters were given despite being ignored - server bug");
101-
return new EqlParser().createStatement(eql);
97+
private LogicalPlan doParse(String eql, ParserParams params) {
98+
return new EqlParser().createStatement(eql, params);
10299
}
103100
}

x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/parser/LogicalPlanTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,13 @@ public void testEventQuery() {
2727

2828
assertEquals(fullQuery, new Filter(Source.EMPTY, new UnresolvedRelation(Source.EMPTY, null, "", false, ""), fullExpression));
2929
}
30+
31+
public void testParameterizedEventQuery() {
32+
ParserParams params = new ParserParams().fieldEventType("myCustomEvent");
33+
LogicalPlan fullQuery = parser.createStatement("process where process_name == 'net.exe'", params);
34+
Expression fullExpression = expr("myCustomEvent == 'process' and process_name == 'net.exe'");
35+
36+
assertEquals(fullQuery, new Filter(Source.EMPTY, new UnresolvedRelation(Source.EMPTY, null, "", false, ""), fullExpression));
37+
}
38+
3039
}

0 commit comments

Comments
 (0)