Skip to content

Commit

Permalink
Introduce Ml Inference Search Request Extension (#3284)
Browse files Browse the repository at this point in the history
* add ml inference search extension

Signed-off-by: Mingshi Liu <[email protected]>

* pass search extension to pipeline context

Signed-off-by: Mingshi Liu <[email protected]>

* allow write to requestContext when outputmap's key not present in request body

Signed-off-by: Mingshi Liu <[email protected]>

* add REST test and javadoc

Signed-off-by: Mingshi Liu <[email protected]>

* increase code coverage for StringUtils

Signed-off-by: Mingshi Liu <[email protected]>

---------

Signed-off-by: Mingshi Liu <[email protected]>
  • Loading branch information
mingshl authored Jan 27, 2025
1 parent 571de0e commit 3cbd09a
Show file tree
Hide file tree
Showing 17 changed files with 1,825 additions and 118 deletions.
106 changes: 106 additions & 0 deletions common/src/main/java/org/opensearch/ml/common/utils/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SpecVersion;
Expand Down Expand Up @@ -347,6 +348,111 @@ public static JsonObject getJsonObjectFromString(String jsonString) {
return JsonParser.parseString(jsonString).getAsJsonObject();
}

/**
* Checks if a specified JSON path exists within a given JSON object.
*
* This method attempts to read the value at the specified path in the JSON object.
* If the path exists, it returns true. If a PathNotFoundException is thrown,
* indicating that the path does not exist, it returns false.
*
* @param json The JSON object to check. This can be a Map, List, or any object
* that JsonPath can parse.
* @param path The JSON path to check for existence. This should be a valid
* JsonPath expression (e.g., "$.store.book[0].title").
* @return true if the path exists in the JSON object, false otherwise.
* @throws IllegalArgumentException if the json object is null or if the path is null or empty.
*/
public static boolean pathExists(Object json, String path) {
if (json == null) {
throw new IllegalArgumentException("JSON object cannot be null");
}
if (path == null || path.isEmpty()) {
throw new IllegalArgumentException("Path cannot be null or empty");
}
if (!isValidJSONPath(path)) {
throw new IllegalArgumentException("the field path is not a valid json path: " + path);
}
try {
JsonPath.read(json, path);
return true;
} catch (PathNotFoundException e) {
return false;
}
}

/**
* Prepares nested structures in a JSON object based on the given field path.
*
* This method ensures that all intermediate nested objects and arrays exist in the JSON object
* for a given field path. If any part of the path doesn't exist, it creates new empty objects
* (HashMaps) or arrays (ArrayLists) for those parts.
*
* The method can handle complex paths including both object properties and array indices.
* For example, it can process paths like "foo.bar[1].baz[0].qux".
*
* @param jsonObject The JSON object to be updated. If this is not a Map, a new Map will be created.
* @param fieldPath The full path of the field, potentially including nested structures and array indices.
* The path can optionally start with "$." which will be ignored if present.
* @return The updated JSON object with necessary nested structures in place.
* If the input was not a Map, returns the newly created Map structure.
*
* @throws IllegalArgumentException If the field path is null or not a valid JSON path.
*
*/
public static Object prepareNestedStructures(Object jsonObject, String fieldPath) {
if (fieldPath == null) {
throw new IllegalArgumentException("The field path is null");
}
if (jsonObject == null) {
throw new IllegalArgumentException("The object is null");
}
if (!isValidJSONPath(fieldPath)) {
throw new IllegalArgumentException("The field path is not a valid JSON path: " + fieldPath);
}

String path = fieldPath.startsWith("$.") ? fieldPath.substring(2) : fieldPath;
String[] pathParts = path.split("(?<!\\\\)\\.");

Map<String, Object> current = (jsonObject instanceof Map) ? (Map<String, Object>) jsonObject : new HashMap<>();

for (String part : pathParts) {
if (part.contains("[")) {
// Handle array notation
String[] arrayParts = part.split("\\[");
String key = arrayParts[0];
int index = Integer.parseInt(arrayParts[1].replaceAll("\\]", ""));

if (!current.containsKey(key)) {
current.put(key, new ArrayList<>());
}
if (!(current.get(key) instanceof List)) {
return jsonObject;
}
List<Object> list = (List<Object>) current.get(key);
if (index >= list.size()) {
while (list.size() <= index) {
list.add(null);
}
list.set(index, new HashMap<>());
}
if (!(list.get(index) instanceof Map)) {
return jsonObject;
}
current = (Map<String, Object>) list.get(index);
} else {
// Handle object notation
if (!current.containsKey(part)) {
current.put(part, new HashMap<>());
} else if (!(current.get(part) instanceof Map)) {
return jsonObject;
}
current = (Map<String, Object>) current.get(part);
}
}

return jsonObject;
}

public static void validateSchema(String schemaString, String instanceString) {
try {
// parse the schema JSON as string
Expand Down
Loading

0 comments on commit 3cbd09a

Please sign in to comment.