Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5e4257f
add get rule api logic
ruai0511 Jan 23, 2025
e57f764
modify based on comments
ruai0511 Feb 19, 2025
bf5589e
rebase from main after the schema merged
ruai0511 Mar 22, 2025
d1cab5d
modify based on comments
ruai0511 Mar 25, 2025
34fa4ad
extract common logics to libs
ruai0511 Mar 31, 2025
09178eb
Add javadocs for libs
ruai0511 Mar 31, 2025
f7a324a
modify based on comments
ruai0511 Apr 2, 2025
1e59826
modify based on comments
ruai0511 Apr 3, 2025
a852352
modify based on comments
ruai0511 Apr 3, 2025
0790b36
correct UT
ruai0511 Apr 4, 2025
5c4856c
modify based on comments
ruai0511 Apr 5, 2025
b4ec49b
refactor code and fix ut
kaushalmahi12 Apr 9, 2025
a280686
remove commented code
kaushalmahi12 Apr 9, 2025
062c05c
address comments
kaushalmahi12 Apr 10, 2025
55b8da1
change method name
kaushalmahi12 Apr 10, 2025
98f54aa
fix merge conflicts
kaushalmahi12 Apr 14, 2025
05a8747
rename queryGroup to workloadGroup
kaushalmahi12 Apr 16, 2025
3ed6f94
add guice binding related changes
kaushalmahi12 Apr 16, 2025
1fa8311
refactor code to create a generic rule framework structure
kaushalmahi12 Apr 19, 2025
099616c
fix javadoc
ruai0511 Apr 21, 2025
8f27349
fix UT
ruai0511 Apr 21, 2025
5e2209c
restructure tests
kaushalmahi12 Apr 21, 2025
37ac465
rebase with mainline
kaushalmahi12 Apr 21, 2025
ebfdf43
fix gradlew file
ruai0511 Apr 22, 2025
a2ef820
add UT
ruai0511 Apr 22, 2025
5394f0d
add action UTs
kaushalmahi12 Apr 22, 2025
783ce61
correct the comment
kaushalmahi12 Apr 22, 2025
d6b3e79
add more UT
ruai0511 Apr 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased 3.x]
### Added
- [Rule based auto-tagging] Add get rule API ([#17336](https://github.com/opensearch-project/OpenSearch/pull/17336))
- Add multi-threaded writer support in pull-based ingestion ([#17912](https://github.com/opensearch-project/OpenSearch/pull/17912))
- Implement parallel shard refresh behind cluster settings ([#17782](https://github.com/opensearch-project/OpenSearch/pull/17782))

Expand Down
21 changes: 21 additions & 0 deletions modules/autotagging-commons/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/


opensearchplugin {
description = 'OpenSearch Rule Framework plugin'
classname = 'org.opensearch.rule.RuleFrameworkPlugin'
}

dependencies {
api project("spi")
api project("common")
testImplementation(project(":test:framework")) {
exclude group: 'org.opensearch', module: 'opensearch-core'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@
* compatible open source license.
*/

apply plugin: 'opensearch.build'
apply plugin: 'opensearch.publish'

description = 'OpenSearch Rule framework common constructs which spi and module shares'

dependencies {
api 'org.apache.commons:commons-collections4:4.4'
api project(":server")
implementation project(":libs:opensearch-common")
compileOnly project(":server")

testImplementation(project(":test:framework")) {
exclude group: 'org.opensearch', module: 'opensearch-core'
}
}


tasks.named("dependencyLicenses").configure {
mapping from: /commons-collections.*/, to: 'commons-collections'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.action.ActionRequest;
import org.opensearch.action.ActionRequestValidationException;
import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.rule.autotagging.Attribute;
import org.opensearch.rule.autotagging.FeatureType;
import org.opensearch.rule.autotagging.Rule;
import org.opensearch.rule.autotagging.RuleValidator;

import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* A request for get Rule
* Example Request:
* The endpoint "localhost:9200/_wlm/rule" is specific to the Workload Management feature to manage rules
* curl -X GET "localhost:9200/_wlm/rule" - get all rules
* curl -X GET "localhost:9200/_wlm/rule/{_id}" - get single rule by id
* curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b
* @opensearch.experimental
*/
@ExperimentalApi
public class GetRuleRequest extends ActionRequest {
private final String id;
private final Map<Attribute, Set<String>> attributeFilters;
private final String searchAfter;
private final FeatureType featureType;

/**
* Constructor for GetRuleRequest
* @param id - Rule id to get
* @param attributeFilters - Rules will be filtered based on the attribute-value mappings.
* @param searchAfter - The sort value used for pagination.
* @param featureType - The feature type related to rule.
*/
public GetRuleRequest(String id, Map<Attribute, Set<String>> attributeFilters, String searchAfter, FeatureType featureType) {
this.id = id;
this.attributeFilters = attributeFilters;
this.searchAfter = searchAfter;
this.featureType = featureType;
}

/**
* Constructs a GetRuleRequest from a StreamInput for deserialization.
* @param in - The {@link StreamInput} instance to read from.
*/
public GetRuleRequest(StreamInput in) throws IOException {
super(in);
id = in.readOptionalString();
featureType = FeatureType.from(in);
attributeFilters = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList()));
searchAfter = in.readOptionalString();
}

@Override
public ActionRequestValidationException validate() {
if (RuleValidator.isEmpty(id)) {
throw new IllegalArgumentException(Rule._ID_STRING + " cannot be empty.");
}
if (RuleValidator.isEmpty(searchAfter)) {
throw new IllegalArgumentException("search_after cannot be empty.");
}
return null;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeOptionalString(id);
featureType.writeTo(out);
out.writeMap(attributeFilters, (output, attribute) -> attribute.writeTo(output), StreamOutput::writeStringCollection);
out.writeOptionalString(searchAfter);
}

/**
* id getter
*/
public String getId() {
return id;
}

/**
* attributeFilters getter
*/
public Map<Attribute, Set<String>> getAttributeFilters() {
return attributeFilters;
}

/**
* searchAfter getter
*/
public String getSearchAfter() {
return searchAfter;
}

/**
* FeatureType getter
* @return
*/
public FeatureType getFeatureType() {
return featureType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.core.action.ActionResponse;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.rule.autotagging.Rule;

import java.io.IOException;
import java.util.Map;

import static org.opensearch.rule.autotagging.Rule._ID_STRING;

/**
* Response for the get API for Rule.
* Example response:
* {
* "rules": [
* {
* "_id": "z1MJApUB0zgMcDmz-UQq",
* "description": "Rule for tagging query_group_id to index123"
* "index_pattern": ["index123"],
* "query_group": "query_group_id",
* "updated_at": "2025-02-14T01:19:22.589Z"
* },
* ...
* ],
* "search_after": ["z1MJApUB0zgMcDmz-UQq"]
* }
* @opensearch.experimental
*/
@ExperimentalApi
public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject {
private final Map<String, Rule> rules;
private final String searchAfter;

/**
* Constructor for GetRuleResponse
* @param rules - Rules get from the request
* @param searchAfter - The sort value used for pagination.
*/
public GetRuleResponse(final Map<String, Rule> rules, String searchAfter) {
this.rules = rules;
this.searchAfter = searchAfter;
}

/**
* Constructs a GetRuleResponse from a StreamInput for deserialization
* @param in - The {@link StreamInput} instance to read from.
*/
public GetRuleResponse(StreamInput in) throws IOException {
this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString());
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream));
out.writeOptionalString(searchAfter);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startArray("rules");
for (Map.Entry<String, Rule> entry : rules.entrySet()) {
entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey())));
}
builder.endArray();
if (searchAfter != null && !searchAfter.isEmpty()) {
builder.field("search_after", new Object[] { searchAfter });
}
builder.endObject();
return builder;
}

/**
* rules getter
*/
public Map<String, Rule> getRules() {
return rules;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.rule.autotagging.Attribute;

/**
* Generic Rule attributes that features can use out of the use by using the lib.
* @opensearch.experimental
*/
public enum RuleAttribute implements Attribute {
/**
* Represents the index_pattern attribute in RuleAttribute
*/
INDEX_PATTERN("index_pattern");

private final String name;

RuleAttribute(String name) {
this.name = name;
validateAttribute();
}

@Override
public String getName() {
return name;
}

/**
* Retrieves the RuleAttribute from a name string
* @param name - attribute name
*/
public static RuleAttribute fromName(String name) {
for (RuleAttribute attr : RuleAttribute.values()) {
if (attr.getName().equals(name)) {
return attr;
}
}
throw new IllegalArgumentException("Unknown RuleAttribute: " + name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.rule.autotagging.Rule;

/**
* Interface to parse various string representation of Rule entity
* clients can use/implement as per their choice of storage for the Rule
*/
@ExperimentalApi
public interface RuleEntityParser {
/**
* Parses the src string into {@link Rule} object
* @param src String representation of Rule, it could be a XContentObject or something else based on
* where and how it is stored
* @return Rule
*/
Rule parse(String src);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.core.action.ActionListener;

/**
* Interface for a service that handles rule persistence CRUD operations.
* @opensearch.experimental
*/
public interface RulePersistenceService {

/**
* Get rules based on the provided request.
* @param request The request containing the details for retrieving the rule.
* @param listener The listener that will handle the response or failure.
*/
void getRule(GetRuleRequest request, ActionListener<GetRuleResponse> listener);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.rule;

import org.opensearch.common.annotation.ExperimentalApi;

/**
* This interface is responsible for creating query objects which storage layer can use
* to query the backend
* @param <T>
*/
@ExperimentalApi
public interface RuleQueryMapper<T> {
/**
* This method translates the {@link GetRuleRequest} to a storage engine specific query object
* @param request
* @return
*/
T from(GetRuleRequest request);
}
Loading
Loading