Skip to content

Commit

Permalink
Add CreateAnomalyDetectorTool (opensearch-project#348)
Browse files Browse the repository at this point in the history
* Add CreateAnomalyDetectorTool

Signed-off-by: gaobinlong <[email protected]>

* Optimize some code

Signed-off-by: gaobinlong <[email protected]>

* Fix test failure

Signed-off-by: gaobinlong <[email protected]>

* Optimize exception

Signed-off-by: gaobinlong <[email protected]>

---------

Signed-off-by: gaobinlong <[email protected]>
(cherry picked from commit 63be179)
  • Loading branch information
gaobinlong committed Jul 17, 2024
1 parent 5340662 commit 08cc9f4
Show file tree
Hide file tree
Showing 8 changed files with 1,140 additions and 25 deletions.
5 changes: 4 additions & 1 deletion src/main/java/org/opensearch/agent/ToolPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.List;
import java.util.function.Supplier;

import org.opensearch.agent.tools.CreateAnomalyDetectorTool;
import org.opensearch.agent.tools.NeuralSparseSearchTool;
import org.opensearch.agent.tools.PPLTool;
import org.opensearch.agent.tools.RAGTool;
Expand Down Expand Up @@ -68,6 +69,7 @@ public Collection<Object> createComponents(
SearchAnomalyDetectorsTool.Factory.getInstance().init(client, namedWriteableRegistry);
SearchAnomalyResultsTool.Factory.getInstance().init(client, namedWriteableRegistry);
SearchMonitorsTool.Factory.getInstance().init(client);
CreateAnomalyDetectorTool.Factory.getInstance().init(client);
return Collections.emptyList();
}

Expand All @@ -82,7 +84,8 @@ public List<Tool.Factory<? extends Tool>> getToolFactories() {
SearchAlertsTool.Factory.getInstance(),
SearchAnomalyDetectorsTool.Factory.getInstance(),
SearchAnomalyResultsTool.Factory.getInstance(),
SearchMonitorsTool.Factory.getInstance()
SearchMonitorsTool.Factory.getInstance(),
CreateAnomalyDetectorTool.Factory.getInstance()
);
}
}

Large diffs are not rendered by default.

26 changes: 2 additions & 24 deletions src/main/java/org/opensearch/agent/tools/PPLTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.opensearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.opensearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.opensearch.action.search.SearchRequest;
import org.opensearch.action.search.SearchResponse;
import org.opensearch.agent.tools.utils.ToolHelper;
import org.opensearch.client.Client;
import org.opensearch.cluster.metadata.MappingMetadata;
import org.opensearch.core.action.ActionListener;
Expand Down Expand Up @@ -392,7 +392,7 @@ private String constructTableInfo(SearchHit[] searchHits, Map<String, MappingMet
);
}
Map<String, String> fieldsToType = new HashMap<>();
extractNamesTypes(mappingSource, fieldsToType, "");
ToolHelper.extractFieldNamesTypes(mappingSource, fieldsToType, "");
StringJoiner tableInfoJoiner = new StringJoiner("\n");
List<String> sortedKeys = new ArrayList<>(fieldsToType.keySet());
Collections.sort(sortedKeys);
Expand Down Expand Up @@ -432,28 +432,6 @@ private String constructPrompt(String tableInfo, String question, String indexNa
return finalPrompt;
}

private void extractNamesTypes(Map<String, Object> mappingSource, Map<String, String> fieldsToType, String prefix) {
if (prefix.length() > 0) {
prefix += ".";
}

for (Map.Entry<String, Object> entry : mappingSource.entrySet()) {
String n = entry.getKey();
Object v = entry.getValue();

if (v instanceof Map) {
Map<String, Object> vMap = (Map<String, Object>) v;
if (vMap.containsKey("type")) {
if (!((vMap.getOrDefault("type", "")).equals("alias"))) {
fieldsToType.put(prefix + n, (String) vMap.get("type"));
}
} else if (vMap.containsKey("properties")) {
extractNamesTypes((Map<String, Object>) vMap.get("properties"), fieldsToType, prefix + n);
}
}
}
}

private static void extractSamples(Map<String, Object> sampleSource, Map<String, String> fieldsToSample, String prefix)
throws PrivilegedActionException {
if (prefix.length() > 0) {
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/org/opensearch/agent/tools/utils/ToolHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.agent.tools.utils;

import java.util.Map;

public class ToolHelper {
/**
* Flatten all the fields in the mappings, insert the field->field type mapping to a map
* @param mappingSource the mappings of an index
* @param fieldsToType the result containing the field->field type mapping
* @param prefix the parent field path
*/
public static void extractFieldNamesTypes(Map<String, Object> mappingSource, Map<String, String> fieldsToType, String prefix) {
if (prefix.length() > 0) {
prefix += ".";
}

for (Map.Entry<String, Object> entry : mappingSource.entrySet()) {
String n = entry.getKey();
Object v = entry.getValue();

if (v instanceof Map) {
Map<String, Object> vMap = (Map<String, Object>) v;
if (vMap.containsKey("type")) {
if (!((vMap.getOrDefault("type", "")).equals("alias"))) {
fieldsToType.put(prefix + n, (String) vMap.get("type"));
}
}
if (vMap.containsKey("properties")) {
extractFieldNamesTypes((Map<String, Object>) vMap.get("properties"), fieldsToType, prefix + n);
}
if (vMap.containsKey("fields")) {
extractFieldNamesTypes((Map<String, Object>) vMap.get("fields"), fieldsToType, prefix + n);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"CLAUDE": "Human:\" turn\": Here is an example of the create anomaly detector API: POST _plugins/_anomaly_detection/detectors, {\"time_field\":\"timestamp\",\"indices\":[\"server_log*\"],\"feature_attributes\":[{\"feature_name\":\"test\",\"feature_enabled\":true,\"aggregation_query\":{\"test\":{\"sum\":{\"field\":\"value\"}}}}],\"category_field\":[\"ip\"]}, and here are the mapping info containing all the fields in the index ${indexInfo.indexName}: ${indexInfo.indexMapping}, and the optional aggregation methods are count, avg, min, max and sum. Please give me some suggestion about creating an anomaly detector for the index ${indexInfo.indexName}, you need to give the key information: the top 3 suitable aggregation fields which are numeric types and the suitable aggregation method for each field, if there are no numeric type fields, both the aggregation field and method are empty string, and also give the category field if there exists a keyword type field like ip, address, host, city, country or region, if not exist, the category field is empty. Show me a format of keyed and pipe-delimited list wrapped in a curly bracket just like {category_field=the category field if exists|aggregation_field=comma-delimited list of all the aggregation field names|aggregation_method=comma-delimited list of all the aggregation methods}. \n\nAssistant:\" turn\"",
"OPENAI": "Here is an example of the create anomaly detector API: POST _plugins/_anomaly_detection/detectors, {\"time_field\":\"timestamp\",\"indices\":[\"server_log*\"],\"feature_attributes\":[{\"feature_name\":\"test\",\"feature_enabled\":true,\"aggregation_query\":{\"test\":{\"sum\":{\"field\":\"value\"}}}}],\"category_field\":[\"ip\"]}, and here are the mapping info containing all the fields in the index ${indexInfo.indexName}: ${indexInfo.indexMapping}, and the optional aggregation methods are count, avg, min, max and sum. Please give me some suggestion about creating an anomaly detector for the index ${indexInfo.indexName}, you need to give the key information: the top 3 suitable aggregation fields which are numeric types and the suitable aggregation method for each field, if there are no numeric type fields, both the aggregation field and method are empty string, and also give the category field if there exists a keyword type field like ip, address, host, city, country or region, if not exist, the category field is empty. Show me a format of keyed and pipe-delimited list wrapped in a curly bracket just like {category_field=the category field if exists|aggregation_field=comma-delimited list of all the aggregation field names|aggregation_method=comma-delimited list of all the aggregation methods}. "
}
Loading

0 comments on commit 08cc9f4

Please sign in to comment.