mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-24 15:17:30 -04:00
EQL: HLRC documentation (#80979)
This commit is contained in:
parent
3798ff6df5
commit
eeb39f8499
5 changed files with 247 additions and 6 deletions
|
@ -10,6 +10,7 @@ package org.elasticsearch.client.eql;
|
|||
|
||||
import org.apache.lucene.search.TotalHits;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.document.DocumentField;
|
||||
import org.elasticsearch.common.xcontent.XContentParserUtils;
|
||||
import org.elasticsearch.core.Nullable;
|
||||
import org.elasticsearch.index.get.GetResult;
|
||||
|
@ -25,6 +26,7 @@ import org.elasticsearch.xcontent.XContentParser;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -144,16 +146,19 @@ public class EqlSearchResponse {
|
|||
static final String INDEX = GetResult._INDEX;
|
||||
static final String ID = GetResult._ID;
|
||||
static final String SOURCE = SourceFieldMapper.NAME;
|
||||
static final String FIELDS = "fields";
|
||||
}
|
||||
|
||||
private static final ParseField INDEX = new ParseField(Fields.INDEX);
|
||||
private static final ParseField ID = new ParseField(Fields.ID);
|
||||
private static final ParseField SOURCE = new ParseField(Fields.SOURCE);
|
||||
private static final ParseField FIELDS = new ParseField(Fields.FIELDS);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<Event, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"eql/search_response_event",
|
||||
true,
|
||||
args -> new Event((String) args[0], (String) args[1], (BytesReference) args[2])
|
||||
args -> new Event((String) args[0], (String) args[1], (BytesReference) args[2], (Map<String, DocumentField>) args[3])
|
||||
);
|
||||
|
||||
static {
|
||||
|
@ -165,19 +170,35 @@ public class EqlSearchResponse {
|
|||
return BytesReference.bytes(builder);
|
||||
}
|
||||
}, SOURCE);
|
||||
PARSER.declareObject(optionalConstructorArg(), (p, c) -> {
|
||||
Map<String, DocumentField> fields = new HashMap<>();
|
||||
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
|
||||
DocumentField field = DocumentField.fromXContent(p);
|
||||
fields.put(field.getName(), field);
|
||||
}
|
||||
return fields;
|
||||
}, FIELDS);
|
||||
}
|
||||
|
||||
private final String index;
|
||||
private final String id;
|
||||
private final BytesReference source;
|
||||
private Map<String, Object> sourceAsMap;
|
||||
private final Map<String, DocumentField> fetchFields;
|
||||
|
||||
@Deprecated
|
||||
public Event(String index, String id, BytesReference source) {
|
||||
this(index, id, source, null);
|
||||
}
|
||||
|
||||
private Event(String index, String id, BytesReference source, Map<String, DocumentField> fetchFields) {
|
||||
this.index = index;
|
||||
this.id = id;
|
||||
this.source = source;
|
||||
this.fetchFields = fetchFields;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Event fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
@ -194,6 +215,10 @@ public class EqlSearchResponse {
|
|||
return source;
|
||||
}
|
||||
|
||||
public Map<String, DocumentField> fetchFields() {
|
||||
return fetchFields;
|
||||
}
|
||||
|
||||
public Map<String, Object> sourceAsMap() {
|
||||
if (source == null) {
|
||||
return null;
|
||||
|
@ -208,7 +233,7 @@ public class EqlSearchResponse {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(index, id, source);
|
||||
return Objects.hash(index, id, source, fetchFields);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -222,7 +247,10 @@ public class EqlSearchResponse {
|
|||
}
|
||||
|
||||
EqlSearchResponse.Event other = (EqlSearchResponse.Event) obj;
|
||||
return Objects.equals(index, other.index) && Objects.equals(id, other.id) && Objects.equals(source, other.source);
|
||||
return Objects.equals(index, other.index)
|
||||
&& Objects.equals(id, other.id)
|
||||
&& Objects.equals(source, other.source)
|
||||
&& Objects.equals(fetchFields, other.fetchFields);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,11 +290,13 @@ public class EqlSearchResponse {
|
|||
private final List<Object> joinKeys;
|
||||
private final List<Event> events;
|
||||
|
||||
@Deprecated
|
||||
public Sequence(List<Object> joinKeys, List<Event> events) {
|
||||
this.joinKeys = joinKeys == null ? Collections.emptyList() : joinKeys;
|
||||
this.events = events == null ? Collections.emptyList() : events;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Sequence fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
@ -311,6 +341,7 @@ public class EqlSearchResponse {
|
|||
static final String SEQUENCES = "sequences";
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Hits(@Nullable List<Event> events, @Nullable List<Sequence> sequences, @Nullable TotalHits totalHits) {
|
||||
this.events = events;
|
||||
this.sequences = sequences;
|
||||
|
@ -345,6 +376,7 @@ public class EqlSearchResponse {
|
|||
);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Hits fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
package org.elasticsearch.client.documentation;
|
||||
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.client.WarningsHandler;
|
||||
import org.elasticsearch.client.eql.EqlSearchRequest;
|
||||
import org.elasticsearch.client.eql.EqlSearchResponse;
|
||||
import org.elasticsearch.client.eql.EqlSearchResponse.Event;
|
||||
import org.elasticsearch.client.eql.EqlSearchResponse.Hits;
|
||||
import org.elasticsearch.client.eql.EqlSearchResponse.Sequence;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.CreateIndexResponse;
|
||||
import org.elasticsearch.common.document.DocumentField;
|
||||
import org.elasticsearch.core.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.fetch.subphase.FieldAndFormat;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xcontent.XContentType.JSON;
|
||||
|
||||
/**
|
||||
* Documentation for EQL APIs in the high level java client.
|
||||
* Code wrapped in {@code tag} and {@code end} tags is included in the docs.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public class EqlDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
|
||||
@Before
|
||||
void setUpIndex() throws IOException {
|
||||
String index = "my-index";
|
||||
CreateIndexResponse createIndexResponse = highLevelClient().indices().create(new CreateIndexRequest(index), RequestOptions.DEFAULT);
|
||||
assertTrue(createIndexResponse.isAcknowledged());
|
||||
BulkRequest bulk = new BulkRequest(index).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
bulk.add(new IndexRequest().source(JSON, "event_category", "process", "timestamp", "2021-11-23T00:00:00Z", "tie", 1, "host", "A"));
|
||||
bulk.add(new IndexRequest().source(JSON, "event_category", "process", "timestamp", "2021-11-23T00:00:00Z", "tie", 2, "host", "B"));
|
||||
bulk.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
highLevelClient().bulk(bulk, RequestOptions.DEFAULT);
|
||||
}
|
||||
|
||||
public void testEqlSearch() throws Exception {
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
|
||||
// tag::eql-search-request
|
||||
String indices = "my-index"; // <1>
|
||||
String query = "any where true"; // <2>
|
||||
EqlSearchRequest request = new EqlSearchRequest(indices, query);
|
||||
// end::eql-search-request
|
||||
|
||||
// tag::eql-search-request-arguments
|
||||
request.eventCategoryField("event_category"); // <1>
|
||||
request.fetchSize(50); // <2>
|
||||
request.size(15); // <3>
|
||||
request.tiebreakerField("tie"); // <4>
|
||||
request.timestampField("timestamp"); // <5>
|
||||
request.filter(QueryBuilders.matchAllQuery()); // <6>
|
||||
request.resultPosition("head"); // <7>
|
||||
|
||||
List<FieldAndFormat> fields = new ArrayList<>();
|
||||
fields.add(new FieldAndFormat("hostname", null));
|
||||
request.fetchFields(fields); // <8>
|
||||
|
||||
IndicesOptions op = IndicesOptions.fromOptions(true, true, true, false);
|
||||
request.indicesOptions(op); // <9>
|
||||
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
settings.put("type", "keyword");
|
||||
settings.put("script", "emit(doc['host.keyword'].value)");
|
||||
Map<String, Object> field = new HashMap<>();
|
||||
field.put("hostname", settings);
|
||||
request.runtimeMappings(field); // <10>
|
||||
|
||||
request.waitForCompletionTimeout(TimeValue.timeValueMinutes(1)); // <11>
|
||||
request.keepOnCompletion(true); // <12>
|
||||
request.keepAlive(TimeValue.timeValueHours(12)); // <13>
|
||||
// end::eql-search-request-arguments
|
||||
|
||||
// Ignore warning about ignore_throttled being deprecated
|
||||
RequestOptions options = RequestOptions.DEFAULT.toBuilder().setWarningsHandler(WarningsHandler.PERMISSIVE).build();
|
||||
// tag::eql-search-response
|
||||
EqlSearchResponse response = client.eql().search(request, options);
|
||||
response.id(); // <1>
|
||||
response.isPartial(); // <2>
|
||||
response.isRunning(); // <3>
|
||||
response.isTimeout(); // <4>
|
||||
response.took(); // <5>
|
||||
Hits hits = response.hits(); // <6>
|
||||
hits.totalHits(); // <7>
|
||||
List<Event> events = hits.events(); // <8>
|
||||
List<Sequence> sequences = hits.sequences(); // <9>
|
||||
Map<String, Object> event = events.get(0).sourceAsMap();
|
||||
Map<String, DocumentField> fetchField = events.get(0).fetchFields();
|
||||
fetchField.get("hostname").getValues(); // <10>
|
||||
// end::eql-search-response
|
||||
assertFalse(response.isPartial());
|
||||
assertFalse(response.isRunning());
|
||||
assertFalse(response.isTimeout());
|
||||
assertEquals(2, hits.totalHits().value);
|
||||
assertEquals(2, events.size());
|
||||
assertNull(sequences);
|
||||
assertEquals(1, fetchField.size());
|
||||
assertEquals(1, fetchField.get("hostname").getValues().size());
|
||||
assertEquals("A", fetchField.get("hostname").getValues().get(0));
|
||||
}
|
||||
}
|
|
@ -93,9 +93,10 @@ public class EqlSearchResponseTests extends AbstractResponseTestCase<
|
|||
Map<String, DocumentField> fetchFields = new HashMap<>();
|
||||
int fieldsCount = randomIntBetween(0, 5);
|
||||
for (int j = 0; j < fieldsCount; j++) {
|
||||
fetchFields.put(randomAlphaOfLength(10), randomDocumentField(xType).v1());
|
||||
DocumentField doc = randomDocumentField(xType).v2();
|
||||
fetchFields.put(doc.getName(), doc);
|
||||
}
|
||||
if (fetchFields.isEmpty() && randomBoolean()) {
|
||||
if (fetchFields.isEmpty()) {
|
||||
fetchFields = null;
|
||||
}
|
||||
hits.add(
|
||||
|
@ -262,7 +263,10 @@ public class EqlSearchResponseTests extends AbstractResponseTestCase<
|
|||
) {
|
||||
assertThat(serverEvents.size(), equalTo(clientEvents.size()));
|
||||
for (int j = 0; j < serverEvents.size(); j++) {
|
||||
assertThat(SourceLookup.sourceAsMap(serverEvents.get(j).source()), is(clientEvents.get(j).sourceAsMap()));
|
||||
org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event serverEvent = serverEvents.get(j);
|
||||
EqlSearchResponse.Event clientEvent = clientEvents.get(j);
|
||||
assertThat(SourceLookup.sourceAsMap(serverEvent.source()), is(clientEvent.sourceAsMap()));
|
||||
assertThat(serverEvent.fetchFields(), equalTo(clientEvent.fetchFields()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue