Skip to content

Commit 6d77393

Browse files
authored
EQL: Adds "fields" request field to the eql request (elastic#68962) (elastic#69447)
(cherry picked from commit 22c880e)
1 parent 119ba5a commit 6d77393

File tree

18 files changed

+472
-50
lines changed

18 files changed

+472
-50
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/eql/EqlSearchRequest.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
import org.elasticsearch.common.xcontent.ToXContentObject;
1616
import org.elasticsearch.common.xcontent.XContentBuilder;
1717
import org.elasticsearch.index.query.QueryBuilder;
18+
import org.elasticsearch.search.fetch.subphase.FieldAndFormat;
1819

1920
import java.io.IOException;
2021
import java.util.Arrays;
22+
import java.util.List;
2123
import java.util.Objects;
2224

2325
public class EqlSearchRequest implements Validatable, ToXContentObject {
@@ -29,6 +31,7 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
2931
private String timestampField = "@timestamp";
3032
private String eventCategoryField = "event.category";
3133
private String resultPosition = "tail";
34+
private List<FieldAndFormat> fetchFields;
3235

3336
private int size = 10;
3437
private int fetchSize = 1000;
@@ -51,6 +54,7 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
5154
static final String KEY_WAIT_FOR_COMPLETION_TIMEOUT = "wait_for_completion_timeout";
5255
static final String KEY_KEEP_ALIVE = "keep_alive";
5356
static final String KEY_KEEP_ON_COMPLETION = "keep_on_completion";
57+
static final String KEY_FETCH_FIELDS = "fields";
5458

5559
public EqlSearchRequest(String indices, String query) {
5660
indices(indices);
@@ -80,6 +84,9 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par
8084
builder.field(KEY_KEEP_ALIVE, keepAlive);
8185
}
8286
builder.field(KEY_KEEP_ON_COMPLETION, keepOnCompletion);
87+
if (fetchFields != null) {
88+
builder.field(KEY_FETCH_FIELDS, fetchFields);
89+
}
8390
builder.endObject();
8491
return builder;
8592
}
@@ -145,6 +152,15 @@ public EqlSearchRequest resultPosition(String position) {
145152
return this;
146153
}
147154

155+
public List<FieldAndFormat> fetchFields() {
156+
return fetchFields;
157+
}
158+
159+
public EqlSearchRequest fetchFields(List<FieldAndFormat> fetchFields) {
160+
this.fetchFields = fetchFields;
161+
return this;
162+
}
163+
148164
public int size() {
149165
return this.size;
150166
}
@@ -226,7 +242,8 @@ public boolean equals(Object o) {
226242
Objects.equals(waitForCompletionTimeout, that.waitForCompletionTimeout) &&
227243
Objects.equals(keepAlive, that.keepAlive) &&
228244
Objects.equals(keepOnCompletion, that.keepOnCompletion) &&
229-
Objects.equals(resultPosition, that.resultPosition);
245+
Objects.equals(resultPosition, that.resultPosition) &&
246+
Objects.equals(fetchFields, that.fetchFields);
230247
}
231248

232249
@Override
@@ -244,7 +261,8 @@ public int hashCode() {
244261
waitForCompletionTimeout,
245262
keepAlive,
246263
keepOnCompletion,
247-
resultPosition);
264+
resultPosition,
265+
fetchFields);
248266
}
249267

250268
public String[] indices() {

client/rest-high-level/src/test/java/org/elasticsearch/client/eql/EqlSearchResponseTests.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,23 @@
1111
import org.apache.lucene.search.TotalHits;
1212
import org.elasticsearch.client.AbstractResponseTestCase;
1313
import org.elasticsearch.common.bytes.BytesReference;
14+
import org.elasticsearch.common.collect.Tuple;
15+
import org.elasticsearch.common.document.DocumentField;
1416
import org.elasticsearch.common.xcontent.ToXContent;
1517
import org.elasticsearch.common.xcontent.ToXContentObject;
1618
import org.elasticsearch.common.xcontent.XContentBuilder;
1719
import org.elasticsearch.common.xcontent.XContentParser;
1820
import org.elasticsearch.common.xcontent.XContentType;
1921
import org.elasticsearch.search.lookup.SourceLookup;
22+
import org.elasticsearch.test.ESTestCase;
23+
import org.elasticsearch.test.RandomObjects;
2024

2125
import java.io.IOException;
2226
import java.util.ArrayList;
2327
import java.util.Arrays;
28+
import java.util.HashMap;
2429
import java.util.List;
30+
import java.util.Map;
2531
import java.util.Objects;
2632
import java.util.function.Supplier;
2733

@@ -83,7 +89,16 @@ static List<org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event> randomEv
8389
hits = new ArrayList<>();
8490
for (int i = 0; i < size; i++) {
8591
BytesReference bytes = new RandomSource(() -> randomAlphaOfLength(10)).toBytes(xType);
86-
hits.add(new org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event(String.valueOf(i), randomAlphaOfLength(10), bytes));
92+
Map<String, DocumentField> fetchFields = new HashMap<>();
93+
int fieldsCount = randomIntBetween(0, 5);
94+
for (int j = 0; j < fieldsCount; j++) {
95+
fetchFields.put(randomAlphaOfLength(10), randomDocumentField(xType).v1());
96+
}
97+
if (fetchFields.isEmpty() && randomBoolean()) {
98+
fetchFields = null;
99+
}
100+
hits.add(new org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event(String.valueOf(i), randomAlphaOfLength(10), bytes,
101+
fetchFields));
87102
}
88103
}
89104
if (randomBoolean()) {
@@ -92,6 +107,28 @@ static List<org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event> randomEv
92107
return hits;
93108
}
94109

110+
private static Tuple<DocumentField, DocumentField> randomDocumentField(XContentType xType) {
111+
switch (randomIntBetween(0, 2)) {
112+
case 0:
113+
String fieldName = randomAlphaOfLengthBetween(3, 10);
114+
Tuple<List<Object>, List<Object>> tuple = RandomObjects.randomStoredFieldValues(random(), xType);
115+
DocumentField input = new DocumentField(fieldName, tuple.v1());
116+
DocumentField expected = new DocumentField(fieldName, tuple.v2());
117+
return Tuple.tuple(input, expected);
118+
case 1:
119+
List<Object> listValues = randomList(1, 5, () -> randomList(1, 5, ESTestCase::randomInt));
120+
DocumentField listField = new DocumentField(randomAlphaOfLength(5), listValues);
121+
return Tuple.tuple(listField, listField);
122+
case 2:
123+
List<Object> objectValues = randomList(1, 5,
124+
randomFrom(Arrays.asList(() -> randomAlphaOfLength(10), ESTestCase::randomInt, ESTestCase::randomBoolean)));
125+
DocumentField objectField = new DocumentField(randomAlphaOfLength(5), objectValues);
126+
return Tuple.tuple(objectField, objectField);
127+
default:
128+
throw new IllegalStateException();
129+
}
130+
}
131+
95132
public static org.elasticsearch.xpack.eql.action.EqlSearchResponse createRandomEventsResponse(TotalHits totalHits, XContentType xType) {
96133
org.elasticsearch.xpack.eql.action.EqlSearchResponse.Hits hits = null;
97134
if (randomBoolean()) {

x-pack/plugin/eql/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/eql/10_basic.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
---
22
setup:
3+
- do:
4+
indices.create:
5+
index: eql_test
6+
body:
7+
mappings:
8+
runtime:
9+
day_of_week:
10+
type: keyword
11+
script:
12+
source: "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
313
- do:
414
bulk:
515
refresh: true
@@ -49,6 +59,55 @@ setup:
4959
- match: {hits.events.1._id: "2"}
5060
- match: {hits.events.2._id: "3"}
5161

62+
---
63+
"Execute EQL events query with fields filtering":
64+
- do:
65+
eql.search:
66+
index: eql_test
67+
body:
68+
query: 'process where user == "SYSTEM"'
69+
fields: [{"field":"@timestamp","format":"epoch_millis"},"id","valid","day_of_week"]
70+
71+
- match: {timed_out: false}
72+
- match: {hits.total.value: 3}
73+
- match: {hits.total.relation: "eq"}
74+
- match: {hits.events.0._source.user: "SYSTEM"}
75+
- match: {hits.events.0._id: "1"}
76+
- match: {hits.events.0.fields.@timestamp: ["1580733296000"]}
77+
- match: {hits.events.0.fields.id: [123]}
78+
- match: {hits.events.0.fields.valid: [false]}
79+
- match: {hits.events.0.fields.day_of_week: ["Monday"]}
80+
- match: {hits.events.1._id: "2"}
81+
- match: {hits.events.1.fields.@timestamp: ["1580819696000"]}
82+
- match: {hits.events.1.fields.id: [123]}
83+
- match: {hits.events.1.fields.valid: [true]}
84+
- match: {hits.events.1.fields.day_of_week: ["Tuesday"]}
85+
- match: {hits.events.2._id: "3"}
86+
- match: {hits.events.2.fields.@timestamp: ["1580906096000"]}
87+
- match: {hits.events.2.fields.id: [123]}
88+
- match: {hits.events.2.fields.valid: [true]}
89+
- match: {hits.events.2.fields.day_of_week: ["Wednesday"]}
90+
91+
---
92+
"Execute EQL events query with filter_path":
93+
- do:
94+
eql.search:
95+
index: eql_test
96+
filter_path: "hits.events._source.event.category,hits.events.fields.user,hits.events.fields.id"
97+
body:
98+
query: 'process where user == "SYSTEM"'
99+
fields: [{"field":"@timestamp","format":"epoch_millis"},"id","valid","user"]
100+
101+
- match: {hits.events.0._source.event.0.category: "process"}
102+
- match: {hits.events.0.fields.id: [123]}
103+
- match: {hits.events.0.fields.user: ["SYSTEM"]}
104+
- match: {hits.events.1._source.event.0.category: "process"}
105+
- match: {hits.events.1.fields.id: [123]}
106+
- match: {hits.events.1.fields.user: ["SYSTEM"]}
107+
- match: {hits.events.2._source.event.0.category: "process"}
108+
- match: {hits.events.2.fields.id: [123]}
109+
- match: {hits.events.2.fields.user: ["SYSTEM"]}
110+
52111
---
53112
"Execute EQL sequence with string key.":
54113
- do:
@@ -124,6 +183,57 @@ setup:
124183
- match: {hits.sequences.0.join_keys.0: true}
125184
- match: {hits.sequences.0.events.0._id: "2"}
126185
- match: {hits.sequences.0.events.1._id: "3"}
186+
187+
---
188+
"Execute EQL sequence with fields filtering.":
189+
- do:
190+
eql.search:
191+
index: eql_test
192+
body:
193+
query: 'sequence by user [process where user == "SYSTEM"] [process where true]'
194+
fields: [{"field":"@timestamp","format":"epoch_millis"},"id","valid","day_of_week"]
195+
- match: {timed_out: false}
196+
- match: {hits.total.value: 2}
197+
- match: {hits.total.relation: "eq"}
198+
- match: {hits.sequences.0.join_keys.0: "SYSTEM"}
199+
- match: {hits.sequences.0.events.0._id: "1"}
200+
- match: {hits.sequences.0.events.0.fields.@timestamp: ["1580733296000"]}
201+
- match: {hits.sequences.0.events.0.fields.id: [123]}
202+
- match: {hits.sequences.0.events.0.fields.valid: [false]}
203+
- match: {hits.sequences.0.events.0.fields.day_of_week: ["Monday"]}
204+
- match: {hits.sequences.0.events.1._id: "2"}
205+
- match: {hits.sequences.0.events.1.fields.@timestamp: ["1580819696000"]}
206+
- match: {hits.sequences.0.events.1.fields.id: [123]}
207+
- match: {hits.sequences.0.events.1.fields.valid: [true]}
208+
- match: {hits.sequences.0.events.1.fields.day_of_week: ["Tuesday"]}
209+
- match: {hits.sequences.1.join_keys.0: "SYSTEM"}
210+
- match: {hits.sequences.1.events.0._id: "2"}
211+
- match: {hits.sequences.1.events.0.fields.@timestamp: ["1580819696000"]}
212+
- match: {hits.sequences.1.events.0.fields.id: [123]}
213+
- match: {hits.sequences.1.events.0.fields.valid: [true]}
214+
- match: {hits.sequences.1.events.0.fields.day_of_week: ["Tuesday"]}
215+
- match: {hits.sequences.1.events.1._id: "3"}
216+
- match: {hits.sequences.1.events.1.fields.@timestamp: ["1580906096000"]}
217+
- match: {hits.sequences.1.events.1.fields.id: [123]}
218+
- match: {hits.sequences.1.events.1.fields.valid: [true]}
219+
- match: {hits.sequences.1.events.1.fields.day_of_week: ["Wednesday"]}
220+
221+
---
222+
"Execute EQL sequence with filter_path":
223+
- do:
224+
eql.search:
225+
index: eql_test
226+
filter_path: "hits.sequences.join_keys,hits.sequences.events.fields.valid"
227+
body:
228+
query: 'sequence by user [process where user == "SYSTEM"] [process where true]'
229+
fields: ["id","valid"]
230+
- match: {hits.sequences.0.join_keys.0: "SYSTEM"}
231+
- match: {hits.sequences.0.events.0.fields.valid: [false]}
232+
- match: {hits.sequences.0.events.1.fields.valid: [true]}
233+
- match: {hits.sequences.1.join_keys.0: "SYSTEM"}
234+
- match: {hits.sequences.1.events.0.fields.valid: [true]}
235+
- match: {hits.sequences.1.events.1.fields.valid: [true]}
236+
127237
---
128238
"Execute some EQL in async mode.":
129239
- do:

0 commit comments

Comments
 (0)