forked from opensearch-project/OpenSearch
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Kaushal Kumar <[email protected]>
- Loading branch information
1 parent
2a97774
commit cc729f9
Showing
8 changed files
with
596 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
...rkload-management/src/main/java/org/opensearch/plugin/wlm/rule/structure/TrieDeleter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* 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.plugin.wlm.rule.structure; | ||
|
||
/** | ||
* Handles the deletion operation for the Augmented Trie. | ||
*/ | ||
class TrieDeleter { | ||
private TrieNode root; | ||
private String key; | ||
|
||
/** | ||
* Constructs a TrieDeleter with the given root and key. | ||
* | ||
* @param root The root node of the trie. | ||
* @param key The key to be deleted. | ||
*/ | ||
public TrieDeleter(TrieNode root, String key) { | ||
this.root = root; | ||
this.key = key; | ||
} | ||
|
||
/** | ||
* Performs the deletion operation. | ||
* | ||
* @return true if the key was successfully deleted, false otherwise. | ||
*/ | ||
public boolean delete() { | ||
TrieNode current = root; | ||
TrieNode parent = null; | ||
String remainingKey = key; | ||
while (!remainingKey.isEmpty()) { | ||
TrieNode childNode = current.findCommonPrefixChild(remainingKey); | ||
|
||
if (childNode == null) { | ||
return false; | ||
} | ||
parent = current; | ||
current = childNode; | ||
remainingKey = remainingKey.substring(childNode.getKey().length()); | ||
} | ||
final boolean deleted = current.isEndOfWord(); | ||
|
||
if (deleted) { | ||
current.setEndOfWord(false); | ||
current.setValue(null); | ||
if (current.getChildren().isEmpty()) { | ||
deleteLeafNode(parent, current); | ||
} | ||
} | ||
|
||
return deleted; | ||
} | ||
|
||
private static void deleteLeafNode(TrieNode parent, TrieNode current) { | ||
if (parent != null) { | ||
parent.getChildren().remove(current.getKey()); | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
...kload-management/src/main/java/org/opensearch/plugin/wlm/rule/structure/TrieInserter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* 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.plugin.wlm.rule.structure; | ||
|
||
/** | ||
* Handles the insertion operation for the Augmented Trie. | ||
*/ | ||
class TrieInserter { | ||
private TrieNode root; | ||
private String key; | ||
private String value; | ||
|
||
/** | ||
* Constructs a TrieInserter with the given root, key, and value. | ||
* | ||
* @param root The root node of the trie. | ||
* @param key The key to be inserted. | ||
* @param value The value associated with the key. | ||
*/ | ||
public TrieInserter(TrieNode root, String key, String value) { | ||
this.root = root; | ||
this.key = key; | ||
this.value = value; | ||
} | ||
|
||
/** | ||
* Performs the insertion operation. | ||
* <ol>Method should handle 3 cases | ||
* <li>Simple addition of new child </li> | ||
* <li>insert splits a node</li> | ||
* <li>inserted key is a prefix to existing key|s, this could either mark a node as endOfWord or it could also split the node</li> | ||
* </ol> | ||
* @return The root node of the trie after insertion. | ||
*/ | ||
public TrieNode insert() { | ||
TrieNode current = root; | ||
String remainingKey = key; | ||
while (!remainingKey.isEmpty()) { | ||
TrieNode child = current.findCommonPrefixChild(remainingKey); | ||
|
||
if (child == null) { | ||
boolean partialMatch = false; | ||
// partial match | ||
for (String childKey : current.getChildren().keySet()) { | ||
int commonPrefixLength = getLongestCommonPrefixLength(childKey, remainingKey); | ||
if (commonPrefixLength > 0) { | ||
TrieNode newNode = current.splitNode(childKey, commonPrefixLength); | ||
|
||
remainingKey = remainingKey.substring(commonPrefixLength); | ||
|
||
current = newNode; | ||
partialMatch = true; | ||
break; | ||
} | ||
} | ||
// no match | ||
if (!partialMatch) { | ||
current = current.addNewChild(remainingKey); | ||
remainingKey = ""; | ||
} | ||
} else { | ||
current = child; | ||
remainingKey = remainingKey.substring(child.getKey().length()); | ||
} | ||
} | ||
updateNodeValue(current); | ||
return root; | ||
} | ||
|
||
private void updateNodeValue(TrieNode node) { | ||
node.setValue(value); | ||
node.setEndOfWord(true); | ||
} | ||
|
||
private int getLongestCommonPrefixLength(String str1, String str2) { | ||
int minLength = Math.min(str1.length(), str2.length()); | ||
for (int i = 0; i < minLength; i++) { | ||
if (str1.charAt(i) != str2.charAt(i)) { | ||
return i; | ||
} | ||
} | ||
return minLength; | ||
} | ||
} |
118 changes: 118 additions & 0 deletions
118
.../workload-management/src/main/java/org/opensearch/plugin/wlm/rule/structure/TrieNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* | ||
* 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.plugin.wlm.rule.structure; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Queue; | ||
|
||
/** | ||
* Represents a node in the Augmented Trie. | ||
* Each node contains a key, an optional value, and references to child nodes. | ||
*/ | ||
class TrieNode { | ||
public static final int CLOSEST_LIMIT = 5; | ||
private Map<String, TrieNode> children; | ||
private String key; | ||
private String value; | ||
private boolean isEndOfWord; | ||
|
||
/** | ||
* Constructs a TrieNode with the given key. | ||
* | ||
* @param key The key associated with this node. | ||
*/ | ||
public TrieNode(String key) { | ||
this.children = new HashMap<>(); | ||
this.key = key; | ||
this.value = null; | ||
this.isEndOfWord = false; | ||
} | ||
|
||
// Getters and setters | ||
public Map<String, TrieNode> getChildren() { | ||
return children; | ||
} | ||
|
||
public String getKey() { | ||
return key; | ||
} | ||
|
||
public void setKey(String key) { | ||
this.key = key; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
|
||
public void setValue(String value) { | ||
this.value = value; | ||
} | ||
|
||
public boolean isEndOfWord() { | ||
return isEndOfWord; | ||
} | ||
|
||
public void setEndOfWord(boolean endOfWord) { | ||
isEndOfWord = endOfWord; | ||
} | ||
|
||
public TrieNode addNewChild(String key) { | ||
TrieNode newNode = new TrieNode(key); | ||
newNode.setValue(value); | ||
newNode.setEndOfWord(true); | ||
getChildren().put(key, newNode); | ||
return newNode; | ||
} | ||
|
||
public TrieNode splitNode(String childKey, int commonPrefixLength) { | ||
String commonPrefix = childKey.substring(0, commonPrefixLength); | ||
TrieNode newNode = new TrieNode(commonPrefix); | ||
TrieNode childNode = getChildren().get(childKey); | ||
|
||
// remove the existing partially matching child node since we will split that | ||
getChildren().remove(childKey); | ||
// re-attach common prefix as direct child | ||
getChildren().put(commonPrefix, newNode); | ||
|
||
childNode.setKey(childKey.substring(commonPrefixLength)); | ||
|
||
newNode.getChildren().put(childKey.substring(commonPrefixLength), childNode); | ||
return newNode; | ||
} | ||
|
||
public TrieNode findCommonPrefixChild(String key) { | ||
return getChildren().entrySet() | ||
.stream() | ||
.filter(entry -> key.startsWith(entry.getKey())) | ||
.findFirst() | ||
.map(Map.Entry::getValue) | ||
.orElse(null); | ||
} | ||
|
||
public List<String> findTopFiveClosest() { | ||
List<String> ans = new ArrayList<>(CLOSEST_LIMIT); | ||
Queue<TrieNode> queue = new LinkedList<>(); | ||
queue.offer(this); | ||
|
||
while (!queue.isEmpty() && ans.size() < CLOSEST_LIMIT) { | ||
TrieNode current = queue.poll(); | ||
if (current.isEndOfWord()) { | ||
ans.add(current.getValue()); | ||
} | ||
queue.addAll(current.getChildren().values()); | ||
} | ||
|
||
return ans; | ||
} | ||
} |
Oops, something went wrong.