mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-23 13:26:02 +00:00
[ML] Add description to ML filters (#31330)
This adds a `description` to ML filters in order to allow users to describe their filters in a human readable form which is also editable (filter updates to be added shortly).
This commit is contained in:
parent
f7a0cafe55
commit
9b293275af
@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.core.ml.job.config;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
@ -30,6 +31,7 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
|
||||
public static final ParseField TYPE = new ParseField("type");
|
||||
public static final ParseField ID = new ParseField("filter_id");
|
||||
public static final ParseField DESCRIPTION = new ParseField("description");
|
||||
public static final ParseField ITEMS = new ParseField("items");
|
||||
|
||||
// For QueryPage
|
||||
@ -43,27 +45,38 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
|
||||
parser.declareString((builder, s) -> {}, TYPE);
|
||||
parser.declareString(Builder::setId, ID);
|
||||
parser.declareStringOrNull(Builder::setDescription, DESCRIPTION);
|
||||
parser.declareStringArray(Builder::setItems, ITEMS);
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
private final String id;
|
||||
private final String description;
|
||||
private final List<String> items;
|
||||
|
||||
public MlFilter(String id, List<String> items) {
|
||||
public MlFilter(String id, String description, List<String> items) {
|
||||
this.id = Objects.requireNonNull(id, ID.getPreferredName() + " must not be null");
|
||||
this.description = description;
|
||||
this.items = Objects.requireNonNull(items, ITEMS.getPreferredName() + " must not be null");
|
||||
}
|
||||
|
||||
public MlFilter(StreamInput in) throws IOException {
|
||||
id = in.readString();
|
||||
if (in.getVersion().onOrAfter(Version.V_6_4_0)) {
|
||||
description = in.readOptionalString();
|
||||
} else {
|
||||
description = null;
|
||||
}
|
||||
items = Arrays.asList(in.readStringArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(id);
|
||||
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
|
||||
out.writeOptionalString(description);
|
||||
}
|
||||
out.writeStringArray(items.toArray(new String[items.size()]));
|
||||
}
|
||||
|
||||
@ -71,6 +84,9 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(ID.getPreferredName(), id);
|
||||
if (description != null) {
|
||||
builder.field(DESCRIPTION.getPreferredName(), description);
|
||||
}
|
||||
builder.field(ITEMS.getPreferredName(), items);
|
||||
if (params.paramAsBoolean(MlMetaIndex.INCLUDE_TYPE_KEY, false)) {
|
||||
builder.field(TYPE.getPreferredName(), FILTER_TYPE);
|
||||
@ -83,6 +99,10 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<String> getItems() {
|
||||
return new ArrayList<>(items);
|
||||
}
|
||||
@ -98,12 +118,12 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
}
|
||||
|
||||
MlFilter other = (MlFilter) obj;
|
||||
return id.equals(other.id) && items.equals(other.items);
|
||||
return id.equals(other.id) && Objects.equals(description, other.description) && items.equals(other.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, items);
|
||||
return Objects.hash(id, description, items);
|
||||
}
|
||||
|
||||
public String documentId() {
|
||||
@ -114,30 +134,45 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||
return DOCUMENT_ID_PREFIX + filterId;
|
||||
}
|
||||
|
||||
public static Builder builder(String filterId) {
|
||||
return new Builder().setId(filterId);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private String id;
|
||||
private String description;
|
||||
private List<String> items = Collections.emptyList();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Builder() {}
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Builder setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setItems(List<String> items) {
|
||||
this.items = items;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setItems(String... items) {
|
||||
this.items = Arrays.asList(items);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MlFilter build() {
|
||||
return new MlFilter(id, items);
|
||||
return new MlFilter(id, description, items);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import org.elasticsearch.test.AbstractStreamableTestCase;
|
||||
import org.elasticsearch.xpack.core.ml.action.GetFiltersAction.Response;
|
||||
import org.elasticsearch.xpack.core.ml.action.util.QueryPage;
|
||||
import org.elasticsearch.xpack.core.ml.job.config.MlFilter;
|
||||
import org.elasticsearch.xpack.core.ml.job.config.MlFilterTests;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@ -17,9 +18,7 @@ public class GetFiltersActionResponseTests extends AbstractStreamableTestCase<Ge
|
||||
@Override
|
||||
protected Response createTestInstance() {
|
||||
final QueryPage<MlFilter> result;
|
||||
|
||||
MlFilter doc = new MlFilter(
|
||||
randomAlphaOfLengthBetween(1, 20), Collections.singletonList(randomAlphaOfLengthBetween(1, 20)));
|
||||
MlFilter doc = MlFilterTests.createRandom();
|
||||
result = new QueryPage<>(Collections.singletonList(doc), 1, MlFilter.RESULTS_FIELD);
|
||||
return new Response(result);
|
||||
}
|
||||
|
@ -8,10 +8,7 @@ package org.elasticsearch.xpack.core.ml.action;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||
import org.elasticsearch.xpack.core.ml.action.PutFilterAction.Request;
|
||||
import org.elasticsearch.xpack.core.ml.job.config.MlFilter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.elasticsearch.xpack.core.ml.job.config.MlFilterTests;
|
||||
|
||||
public class PutFilterActionRequestTests extends AbstractStreamableXContentTestCase<Request> {
|
||||
|
||||
@ -19,13 +16,7 @@ public class PutFilterActionRequestTests extends AbstractStreamableXContentTestC
|
||||
|
||||
@Override
|
||||
protected Request createTestInstance() {
|
||||
int size = randomInt(10);
|
||||
List<String> items = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
items.add(randomAlphaOfLengthBetween(1, 20));
|
||||
}
|
||||
MlFilter filter = new MlFilter(filterId, items);
|
||||
return new PutFilterAction.Request(filter);
|
||||
return new PutFilterAction.Request(MlFilterTests.createRandom(filterId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,5 +33,4 @@ public class PutFilterActionRequestTests extends AbstractStreamableXContentTestC
|
||||
protected Request doParseInstance(XContentParser parser) {
|
||||
return PutFilterAction.Request.parseRequest(filterId, parser);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,12 +26,25 @@ public class MlFilterTests extends AbstractSerializingTestCase<MlFilter> {
|
||||
|
||||
@Override
|
||||
protected MlFilter createTestInstance() {
|
||||
return createRandom();
|
||||
}
|
||||
|
||||
public static MlFilter createRandom() {
|
||||
return createRandom(randomAlphaOfLengthBetween(1, 20));
|
||||
}
|
||||
|
||||
public static MlFilter createRandom(String filterId) {
|
||||
String description = null;
|
||||
if (randomBoolean()) {
|
||||
description = randomAlphaOfLength(20);
|
||||
}
|
||||
|
||||
int size = randomInt(10);
|
||||
List<String> items = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
items.add(randomAlphaOfLengthBetween(1, 20));
|
||||
}
|
||||
return new MlFilter(randomAlphaOfLengthBetween(1, 20), items);
|
||||
return new MlFilter(filterId, description, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -45,13 +58,13 @@ public class MlFilterTests extends AbstractSerializingTestCase<MlFilter> {
|
||||
}
|
||||
|
||||
public void testNullId() {
|
||||
NullPointerException ex = expectThrows(NullPointerException.class, () -> new MlFilter(null, Collections.emptyList()));
|
||||
NullPointerException ex = expectThrows(NullPointerException.class, () -> new MlFilter(null, "", Collections.emptyList()));
|
||||
assertEquals(MlFilter.ID.getPreferredName() + " must not be null", ex.getMessage());
|
||||
}
|
||||
|
||||
public void testNullItems() {
|
||||
NullPointerException ex =
|
||||
expectThrows(NullPointerException.class, () -> new MlFilter(randomAlphaOfLengthBetween(1, 20), null));
|
||||
expectThrows(NullPointerException.class, () -> new MlFilter(randomAlphaOfLengthBetween(1, 20), "", null));
|
||||
assertEquals(MlFilter.ITEMS.getPreferredName() + " must not be null", ex.getMessage());
|
||||
}
|
||||
|
||||
|
@ -385,8 +385,8 @@ public class JobProviderIT extends MlSingleNodeTestCase {
|
||||
indexScheduledEvents(events);
|
||||
|
||||
List<MlFilter> filters = new ArrayList<>();
|
||||
filters.add(new MlFilter("fruit", Arrays.asList("apple", "pear")));
|
||||
filters.add(new MlFilter("tea", Arrays.asList("green", "builders")));
|
||||
filters.add(MlFilter.builder("fruit").setItems("apple", "pear").build());
|
||||
filters.add(MlFilter.builder("tea").setItems("green", "builders").build());
|
||||
indexFilters(filters);
|
||||
|
||||
DataCounts earliestCounts = DataCountsTests.createTestInstance(jobId);
|
||||
|
@ -210,7 +210,7 @@ public class JobManagerTests extends ESTestCase {
|
||||
|
||||
JobManager jobManager = createJobManager();
|
||||
|
||||
MlFilter filter = new MlFilter("foo_filter", Arrays.asList("a", "b"));
|
||||
MlFilter filter = MlFilter.builder("foo_filter").setItems("a", "b").build();
|
||||
|
||||
jobManager.updateProcessOnFilterChanged(filter);
|
||||
|
||||
|
@ -207,8 +207,8 @@ public class ControlMsgToProcessWriterTests extends ESTestCase {
|
||||
public void testWriteUpdateFiltersMessage() throws IOException {
|
||||
ControlMsgToProcessWriter writer = new ControlMsgToProcessWriter(lengthEncodedWriter, 2);
|
||||
|
||||
MlFilter filter1 = new MlFilter("filter_1", Arrays.asList("a"));
|
||||
MlFilter filter2 = new MlFilter("filter_2", Arrays.asList("b", "c"));
|
||||
MlFilter filter1 = MlFilter.builder("filter_1").setItems("a").build();
|
||||
MlFilter filter2 = MlFilter.builder("filter_2").setItems("b", "c").build();
|
||||
|
||||
writer.writeUpdateFiltersMessage(Arrays.asList(filter1, filter2));
|
||||
|
||||
|
@ -220,8 +220,8 @@ public class FieldConfigWriterTests extends ESTestCase {
|
||||
AnalysisConfig.Builder builder = new AnalysisConfig.Builder(Collections.singletonList(d));
|
||||
analysisConfig = builder.build();
|
||||
|
||||
filters.add(new MlFilter("filter_1", Arrays.asList("a", "b")));
|
||||
filters.add(new MlFilter("filter_2", Arrays.asList("c", "d")));
|
||||
filters.add(MlFilter.builder("filter_1").setItems("a", "b").build());
|
||||
filters.add(MlFilter.builder("filter_2").setItems("c", "d").build());
|
||||
writer = mock(OutputStreamWriter.class);
|
||||
|
||||
createFieldConfigWriter().write();
|
||||
|
@ -10,7 +10,6 @@ import org.elasticsearch.xpack.core.ml.job.config.MlFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -28,8 +27,8 @@ public class MlFilterWriterTests extends ESTestCase {
|
||||
|
||||
public void testWrite() throws IOException {
|
||||
List<MlFilter> filters = new ArrayList<>();
|
||||
filters.add(new MlFilter("filter_1", Arrays.asList("a", "b")));
|
||||
filters.add(new MlFilter("filter_2", Arrays.asList("c", "d")));
|
||||
filters.add(MlFilter.builder("filter_1").setItems("a", "b").build());
|
||||
filters.add(MlFilter.builder("filter_2").setItems("c", "d").build());
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
new MlFilterWriter(filters, buffer).write();
|
||||
|
@ -32,6 +32,7 @@ setup:
|
||||
filter_id: filter-foo2
|
||||
body: >
|
||||
{
|
||||
"description": "This filter has a description",
|
||||
"items": ["123", "lmnop"]
|
||||
}
|
||||
|
||||
@ -76,6 +77,7 @@ setup:
|
||||
- match:
|
||||
filters.1:
|
||||
filter_id: "filter-foo2"
|
||||
description: "This filter has a description"
|
||||
items: ["123", "lmnop"]
|
||||
|
||||
- do:
|
||||
|
@ -120,7 +120,7 @@ public class DetectionRulesIT extends MlNativeAutodetectIntegTestCase {
|
||||
}
|
||||
|
||||
public void testScope() throws Exception {
|
||||
MlFilter safeIps = new MlFilter("safe_ips", Arrays.asList("111.111.111.111", "222.222.222.222"));
|
||||
MlFilter safeIps = MlFilter.builder("safe_ips").setItems("111.111.111.111", "222.222.222.222").build();
|
||||
assertThat(putMlFilter(safeIps), is(true));
|
||||
|
||||
DetectionRule rule = new DetectionRule.Builder(RuleScope.builder().include("ip", "safe_ips")).build();
|
||||
@ -178,7 +178,7 @@ public class DetectionRulesIT extends MlNativeAutodetectIntegTestCase {
|
||||
assertThat(records.get(0).getOverFieldValue(), equalTo("333.333.333.333"));
|
||||
|
||||
// Now let's update the filter
|
||||
MlFilter updatedFilter = new MlFilter(safeIps.getId(), Collections.singletonList("333.333.333.333"));
|
||||
MlFilter updatedFilter = MlFilter.builder(safeIps.getId()).setItems("333.333.333.333").build();
|
||||
assertThat(putMlFilter(updatedFilter), is(true));
|
||||
|
||||
// Wait until the notification that the process was updated is indexed
|
||||
@ -229,7 +229,7 @@ public class DetectionRulesIT extends MlNativeAutodetectIntegTestCase {
|
||||
public void testScopeAndCondition() throws IOException {
|
||||
// We have 2 IPs and they're both safe-listed.
|
||||
List<String> ips = Arrays.asList("111.111.111.111", "222.222.222.222");
|
||||
MlFilter safeIps = new MlFilter("safe_ips", ips);
|
||||
MlFilter safeIps = MlFilter.builder("safe_ips").setItems(ips).build();
|
||||
assertThat(putMlFilter(safeIps), is(true));
|
||||
|
||||
// Ignore if ip in safe list AND actual < 10.
|
||||
|
Loading…
x
Reference in New Issue
Block a user