Skip to content

Commit 69c9c47

Browse files
kaushalmahi12Gagan Singh Saini
authored andcommitted
[Rule based auto-tagging] Add rule sync service (opensearch-project#18128)
--------- Signed-off-by: Kaushal Kumar <[email protected]>
1 parent f9a98b8 commit 69c9c47

File tree

23 files changed

+962
-34
lines changed

23 files changed

+962
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1616
- Update API of Message in index to add the timestamp for lag calculation in ingestion polling ([#17977](https://github.com/opensearch-project/OpenSearch/pull/17977/))
1717
- Add Warm Disk Threshold Allocation Decider for Warm shards ([#18082](https://github.com/opensearch-project/OpenSearch/pull/18082))
1818
- Add composite directory factory ([#17988](https://github.com/opensearch-project/OpenSearch/pull/17988))
19+
- [Rule based auto-tagging] Add refresh based synchronization service for `Rule`s ([#18128](https://github.com/opensearch-project/OpenSearch/pull/18128))
1920
- Add pull-based ingestion error metrics and make internal queue size configurable ([#18088](https://github.com/opensearch-project/OpenSearch/pull/18088))
2021
- Adding support for derive source feature and implementing it for various type of field mappers ([#17759](https://github.com/opensearch-project/OpenSearch/pull/17759))
2122
- [Security Manager Replacement] Enhance Java Agent to intercept newByteChannel ([#17989](https://github.com/opensearch-project/OpenSearch/pull/17989))

modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* @opensearch.experimental
3939
*/
4040
public class Rule implements Writeable, ToXContentObject {
41+
private final String id;
4142
private final String description;
4243
private final FeatureType featureType;
4344
private final Map<Attribute, Set<String>> attributeMap;
@@ -59,19 +60,22 @@ public class Rule implements Writeable, ToXContentObject {
5960

6061
/**
6162
* Main constructor
63+
* @param id
6264
* @param description
6365
* @param attributeMap
6466
* @param featureType
6567
* @param featureValue
6668
* @param updatedAt
6769
*/
6870
public Rule(
71+
String id,
6972
String description,
7073
Map<Attribute, Set<String>> attributeMap,
7174
FeatureType featureType,
7275
String featureValue,
7376
String updatedAt
7477
) {
78+
this.id = id;
7579
this.description = description;
7680
this.featureType = featureType;
7781
this.attributeMap = attributeMap;
@@ -87,6 +91,7 @@ public Rule(
8791
* @throws IOException
8892
*/
8993
public Rule(StreamInput in) throws IOException {
94+
id = in.readString();
9095
description = in.readString();
9196
featureType = FeatureType.from(in);
9297
attributeMap = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList()));
@@ -98,6 +103,7 @@ public Rule(StreamInput in) throws IOException {
98103

99104
@Override
100105
public void writeTo(StreamOutput out) throws IOException {
106+
out.writeString(id);
101107
out.writeString(description);
102108
featureType.writeTo(out);
103109
out.writeMap(attributeMap, (output, attribute) -> attribute.writeTo(output), StreamOutput::writeStringCollection);
@@ -116,6 +122,14 @@ public static Rule fromXContent(final XContentParser parser, FeatureType feature
116122
return Builder.fromXContent(parser, featureType).build();
117123
}
118124

125+
/**
126+
* id getter
127+
* @return
128+
*/
129+
public String getId() {
130+
return id;
131+
}
132+
119133
/**
120134
* description getter
121135
* @return
@@ -159,10 +173,7 @@ public Map<Attribute, Set<String>> getAttributeMap() {
159173
@Override
160174
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
161175
builder.startObject();
162-
String id = params.param(_ID_STRING);
163-
if (id != null) {
164-
builder.field(_ID_STRING, id);
165-
}
176+
builder.field(_ID_STRING, id);
166177
builder.field(DESCRIPTION_STRING, description);
167178
for (Map.Entry<Attribute, Set<String>> entry : attributeMap.entrySet()) {
168179
builder.array(entry.getKey().getName(), entry.getValue().toArray(new String[0]));
@@ -204,6 +215,7 @@ public static Builder builder() {
204215
* @opensearch.experimental
205216
*/
206217
public static class Builder {
218+
private String id;
207219
private String description;
208220
private Map<Attribute, Set<String>> attributeMap;
209221
private FeatureType featureType;
@@ -235,7 +247,9 @@ public static Builder fromXContent(XContentParser parser, FeatureType featureTyp
235247
if (token == XContentParser.Token.FIELD_NAME) {
236248
fieldName = parser.currentName();
237249
} else if (token.isValue()) {
238-
if (fieldName.equals(DESCRIPTION_STRING)) {
250+
if (fieldName.equals(_ID_STRING)) {
251+
builder.id(parser.text());
252+
} else if (fieldName.equals(DESCRIPTION_STRING)) {
239253
builder.description(parser.text());
240254
} else if (fieldName.equals(UPDATED_AT_STRING)) {
241255
builder.updatedAt(parser.text());
@@ -271,6 +285,16 @@ private static void fromXContentParseArray(
271285
attributeMap.put(attribute, attributeValueSet);
272286
}
273287

288+
/**
289+
* Sets the id
290+
* @param id
291+
* @return
292+
*/
293+
public Builder id(String id) {
294+
this.id = id;
295+
return this;
296+
}
297+
274298
/**
275299
* sets the description
276300
* @param description
@@ -326,7 +350,7 @@ public Builder updatedAt(String updatedAt) {
326350
* @return
327351
*/
328352
public Rule build() {
329-
return new Rule(description, attributeMap, featureType, featureValue, updatedAt);
353+
return new Rule(id, description, attributeMap, featureType, featureValue, updatedAt);
330354
}
331355

332356
/**

modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,12 @@ private String findLongestMatchingPrefix(String key) {
109109

110110
@Override
111111
public void clear() {
112-
trie.clear();
112+
writeLock.lock();
113+
try {
114+
trie.clear();
115+
} finally {
116+
writeLock.unlock();
117+
}
113118
}
114119

115120
@Override

modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
import org.opensearch.common.io.stream.BytesStreamOutput;
1212
import org.opensearch.core.common.io.stream.StreamInput;
1313
import org.opensearch.rule.GetRuleRequest;
14+
import org.opensearch.rule.autotagging.Attribute;
15+
import org.opensearch.rule.autotagging.Rule;
1416
import org.opensearch.rule.utils.RuleTestUtils;
1517
import org.opensearch.test.OpenSearchTestCase;
1618

1719
import java.io.IOException;
1820
import java.util.HashMap;
19-
20-
import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP;
21-
import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER;
22-
import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE;
21+
import java.util.Map;
22+
import java.util.Set;
2323

2424
public class GetRuleRequestTests extends OpenSearchTestCase {
2525
/**
@@ -64,4 +64,65 @@ public void testValidate() {
6464
request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE);
6565
assertThrows(IllegalArgumentException.class, request::validate);
6666
}
67+
68+
public static final String _ID_ONE = "id_1";
69+
public static final String SEARCH_AFTER = "search_after";
70+
public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1";
71+
public static final String FEATURE_VALUE_ONE = "feature_value_one";
72+
public static final String FEATURE_VALUE_TWO = "feature_value_two";
73+
public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one";
74+
public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two";
75+
public static final String DESCRIPTION_ONE = "description_1";
76+
public static final String DESCRIPTION_TWO = "description_2";
77+
public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z";
78+
public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z";
79+
public static final Map<Attribute, Set<String>> ATTRIBUTE_MAP = Map.of(
80+
RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE,
81+
Set.of(ATTRIBUTE_VALUE_ONE)
82+
);
83+
84+
public static final Rule ruleOne = Rule.builder()
85+
.id(_ID_ONE)
86+
.description(DESCRIPTION_ONE)
87+
.featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE)
88+
.featureValue(FEATURE_VALUE_ONE)
89+
.attributeMap(ATTRIBUTE_MAP)
90+
.updatedAt(TIMESTAMP_ONE)
91+
.build();
92+
93+
public static final Rule ruleTwo = Rule.builder()
94+
.id(_ID_TWO)
95+
.description(DESCRIPTION_TWO)
96+
.featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE)
97+
.featureValue(FEATURE_VALUE_TWO)
98+
.attributeMap(Map.of(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO)))
99+
.updatedAt(TIMESTAMP_TWO)
100+
.build();
101+
102+
public static Map<String, Rule> ruleMap() {
103+
return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo);
104+
}
105+
106+
public static void assertEqualRules(Map<String, Rule> mapOne, Map<String, Rule> mapTwo, boolean ruleUpdated) {
107+
assertEquals(mapOne.size(), mapTwo.size());
108+
for (Map.Entry<String, Rule> entry : mapOne.entrySet()) {
109+
String id = entry.getKey();
110+
assertTrue(mapTwo.containsKey(id));
111+
Rule one = mapOne.get(id);
112+
Rule two = mapTwo.get(id);
113+
assertEqualRule(one, two, ruleUpdated);
114+
}
115+
}
116+
117+
public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) {
118+
if (ruleUpdated) {
119+
assertEquals(one.getDescription(), two.getDescription());
120+
assertEquals(one.getFeatureType(), two.getFeatureType());
121+
assertEquals(one.getFeatureValue(), two.getFeatureValue());
122+
assertEquals(one.getAttributeMap(), two.getAttributeMap());
123+
assertEquals(one.getAttributeMap(), two.getAttributeMap());
124+
} else {
125+
assertEquals(one, two);
126+
}
127+
}
67128
}

modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class GetRuleResponseTests extends OpenSearchTestCase {
4141
);
4242

4343
public static final Rule ruleOne = Rule.builder()
44+
.id(_ID_ONE)
4445
.description(DESCRIPTION_ONE)
4546
.featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE)
4647
.featureValue(FEATURE_VALUE_ONE)

modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected Rule createTestInstance() {
4747
String description = randomAlphaOfLength(10);
4848
String featureValue = randomAlphaOfLength(5);
4949
String updatedAt = Instant.now().toString();
50-
return new Rule(description, ATTRIBUTE_MAP, FEATURE_TYPE, featureValue, updatedAt);
50+
return new Rule("test_id", description, ATTRIBUTE_MAP, FEATURE_TYPE, featureValue, updatedAt);
5151
}
5252

5353
@Override
@@ -123,6 +123,7 @@ static Rule buildRule(
123123
String description
124124
) {
125125
return Rule.builder()
126+
.id(_ID)
126127
.featureValue(featureValue)
127128
.featureType(featureType)
128129
.description(description)

modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class RuleTestUtils {
4242
);
4343

4444
public static final Rule ruleOne = Rule.builder()
45+
.id(_ID_ONE)
4546
.description(DESCRIPTION_ONE)
4647
.featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE)
4748
.featureValue(FEATURE_VALUE_ONE)
@@ -50,6 +51,7 @@ public class RuleTestUtils {
5051
.build();
5152

5253
public static final Rule ruleTwo = Rule.builder()
54+
.id(_ID_TWO)
5355
.description(DESCRIPTION_TWO)
5456
.featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE)
5557
.featureValue(FEATURE_VALUE_TWO)

modules/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import org.opensearch.rule.attribute_extractor.AttributeExtractor;
1212
import org.opensearch.rule.autotagging.Attribute;
13-
import org.opensearch.rule.autotagging.FeatureType;
1413
import org.opensearch.rule.autotagging.Rule;
1514
import org.opensearch.rule.storage.AttributeValueStore;
1615
import org.opensearch.rule.storage.AttributeValueStoreFactory;
@@ -20,7 +19,6 @@
2019
import java.util.Optional;
2120
import java.util.Set;
2221
import java.util.function.BiConsumer;
23-
import java.util.function.Supplier;
2422

2523
/**
2624
* This class is responsible for managing in-memory view of Rules and Find matching Rule for the request
@@ -29,18 +27,18 @@
2927
*/
3028
public class InMemoryRuleProcessingService {
3129

30+
/**
31+
* Wildcard character which will be removed as we only support prefix based search rather than pattern match based
32+
*/
33+
public static final String WILDCARD = "*";
3234
private final AttributeValueStoreFactory attributeValueStoreFactory;
3335

3436
/**
35-
* Constrcutor
36-
* @param featureType
37-
* @param attributeValueStoreSupplier
37+
* Constructor
38+
* @param attributeValueStoreFactory
3839
*/
39-
public InMemoryRuleProcessingService(
40-
FeatureType featureType,
41-
Supplier<AttributeValueStore<String, String>> attributeValueStoreSupplier
42-
) {
43-
attributeValueStoreFactory = new AttributeValueStoreFactory(featureType, attributeValueStoreSupplier);
40+
public InMemoryRuleProcessingService(AttributeValueStoreFactory attributeValueStoreFactory) {
41+
this.attributeValueStoreFactory = attributeValueStoreFactory;
4442
}
4543

4644
/**
@@ -75,7 +73,7 @@ private void removeOperation(Map.Entry<Attribute, Set<String>> attributeEntry, R
7573
private void addOperation(Map.Entry<Attribute, Set<String>> attributeEntry, Rule rule) {
7674
AttributeValueStore<String, String> valueStore = attributeValueStoreFactory.getAttributeValueStore(attributeEntry.getKey());
7775
for (String value : attributeEntry.getValue()) {
78-
valueStore.put(value, rule.getFeatureValue());
76+
valueStore.put(value.replace(WILDCARD, ""), rule.getFeatureValue());
7977
}
8078
}
8179

modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.opensearch.rule.autotagging.AutoTaggingRegistry;
1414
import org.opensearch.rule.autotagging.FeatureType;
1515
import org.opensearch.rule.autotagging.Rule;
16+
import org.opensearch.rule.storage.AttributeValueStoreFactory;
1617
import org.opensearch.rule.storage.DefaultAttributeValueStore;
1718
import org.opensearch.test.OpenSearchTestCase;
1819

@@ -26,7 +27,11 @@ public class InMemoryRuleProcessingServiceTests extends OpenSearchTestCase {
2627

2728
public void setUp() throws Exception {
2829
super.setUp();
29-
sut = new InMemoryRuleProcessingService(WLMFeatureType.WLM, DefaultAttributeValueStore::new);
30+
AttributeValueStoreFactory attributeValueStoreFactory = new AttributeValueStoreFactory(
31+
WLMFeatureType.WLM,
32+
DefaultAttributeValueStore::new
33+
);
34+
sut = new InMemoryRuleProcessingService(attributeValueStoreFactory);
3035
}
3136

3237
public void testAdd() {
@@ -97,6 +102,7 @@ public void testEvaluateLabelForNoMatchWithLongestMatchingPrefixCase() {
97102

98103
private static Rule getRule(Set<String> attributeValues, String label) {
99104
return new Rule(
105+
randomAlphaOfLength(5),
100106
"test description",
101107
Map.of(TestAttribute.TEST_ATTRIBUTE, attributeValues),
102108
WLMFeatureType.WLM,

plugins/workload-management/build.gradle

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
* Modifications Copyright OpenSearch Contributors. See
99
* GitHub history for details.
1010
*/
11-
1211
apply plugin: 'opensearch.opensearchplugin'
1312
apply plugin: 'opensearch.yaml-rest-test'
1413
apply plugin: 'opensearch.java-rest-test'
1514
apply plugin: 'opensearch.internal-cluster-test'
16-
1715
opensearchplugin {
1816
description = 'OpenSearch Workload Management Plugin.'
1917
classname = 'org.opensearch.plugin.wlm.WorkloadManagementPlugin'

0 commit comments

Comments
 (0)