Skip to content

Commit a852152

Browse files
Introduce Ml Inference Search Request Extension (#3284) (#3438)
* add ml inference search extension Signed-off-by: Mingshi Liu <mingshl@amazon.com> * pass search extension to pipeline context Signed-off-by: Mingshi Liu <mingshl@amazon.com> * allow write to requestContext when outputmap's key not present in request body Signed-off-by: Mingshi Liu <mingshl@amazon.com> * add REST test and javadoc Signed-off-by: Mingshi Liu <mingshl@amazon.com> * increase code coverage for StringUtils Signed-off-by: Mingshi Liu <mingshl@amazon.com> --------- Signed-off-by: Mingshi Liu <mingshl@amazon.com> (cherry picked from commit 3cbd09a) Co-authored-by: Mingshi Liu <mingshl@amazon.com>
1 parent ffe34aa commit a852152

17 files changed

+1825
-118
lines changed

common/src/main/java/org/opensearch/ml/common/utils/StringUtils.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.google.gson.JsonParser;
3636
import com.google.gson.JsonSyntaxException;
3737
import com.jayway.jsonpath.JsonPath;
38+
import com.jayway.jsonpath.PathNotFoundException;
3839
import com.networknt.schema.JsonSchema;
3940
import com.networknt.schema.JsonSchemaFactory;
4041
import com.networknt.schema.SpecVersion;
@@ -347,6 +348,111 @@ public static JsonObject getJsonObjectFromString(String jsonString) {
347348
return JsonParser.parseString(jsonString).getAsJsonObject();
348349
}
349350

351+
/**
352+
* Checks if a specified JSON path exists within a given JSON object.
353+
*
354+
* This method attempts to read the value at the specified path in the JSON object.
355+
* If the path exists, it returns true. If a PathNotFoundException is thrown,
356+
* indicating that the path does not exist, it returns false.
357+
*
358+
* @param json The JSON object to check. This can be a Map, List, or any object
359+
* that JsonPath can parse.
360+
* @param path The JSON path to check for existence. This should be a valid
361+
* JsonPath expression (e.g., "$.store.book[0].title").
362+
* @return true if the path exists in the JSON object, false otherwise.
363+
* @throws IllegalArgumentException if the json object is null or if the path is null or empty.
364+
*/
365+
public static boolean pathExists(Object json, String path) {
366+
if (json == null) {
367+
throw new IllegalArgumentException("JSON object cannot be null");
368+
}
369+
if (path == null || path.isEmpty()) {
370+
throw new IllegalArgumentException("Path cannot be null or empty");
371+
}
372+
if (!isValidJSONPath(path)) {
373+
throw new IllegalArgumentException("the field path is not a valid json path: " + path);
374+
}
375+
try {
376+
JsonPath.read(json, path);
377+
return true;
378+
} catch (PathNotFoundException e) {
379+
return false;
380+
}
381+
}
382+
383+
/**
384+
* Prepares nested structures in a JSON object based on the given field path.
385+
*
386+
* This method ensures that all intermediate nested objects and arrays exist in the JSON object
387+
* for a given field path. If any part of the path doesn't exist, it creates new empty objects
388+
* (HashMaps) or arrays (ArrayLists) for those parts.
389+
*
390+
* The method can handle complex paths including both object properties and array indices.
391+
* For example, it can process paths like "foo.bar[1].baz[0].qux".
392+
*
393+
* @param jsonObject The JSON object to be updated. If this is not a Map, a new Map will be created.
394+
* @param fieldPath The full path of the field, potentially including nested structures and array indices.
395+
* The path can optionally start with "$." which will be ignored if present.
396+
* @return The updated JSON object with necessary nested structures in place.
397+
* If the input was not a Map, returns the newly created Map structure.
398+
*
399+
* @throws IllegalArgumentException If the field path is null or not a valid JSON path.
400+
*
401+
*/
402+
public static Object prepareNestedStructures(Object jsonObject, String fieldPath) {
403+
if (fieldPath == null) {
404+
throw new IllegalArgumentException("The field path is null");
405+
}
406+
if (jsonObject == null) {
407+
throw new IllegalArgumentException("The object is null");
408+
}
409+
if (!isValidJSONPath(fieldPath)) {
410+
throw new IllegalArgumentException("The field path is not a valid JSON path: " + fieldPath);
411+
}
412+
413+
String path = fieldPath.startsWith("$.") ? fieldPath.substring(2) : fieldPath;
414+
String[] pathParts = path.split("(?<!\\\\)\\.");
415+
416+
Map<String, Object> current = (jsonObject instanceof Map) ? (Map<String, Object>) jsonObject : new HashMap<>();
417+
418+
for (String part : pathParts) {
419+
if (part.contains("[")) {
420+
// Handle array notation
421+
String[] arrayParts = part.split("\\[");
422+
String key = arrayParts[0];
423+
int index = Integer.parseInt(arrayParts[1].replaceAll("\\]", ""));
424+
425+
if (!current.containsKey(key)) {
426+
current.put(key, new ArrayList<>());
427+
}
428+
if (!(current.get(key) instanceof List)) {
429+
return jsonObject;
430+
}
431+
List<Object> list = (List<Object>) current.get(key);
432+
if (index >= list.size()) {
433+
while (list.size() <= index) {
434+
list.add(null);
435+
}
436+
list.set(index, new HashMap<>());
437+
}
438+
if (!(list.get(index) instanceof Map)) {
439+
return jsonObject;
440+
}
441+
current = (Map<String, Object>) list.get(index);
442+
} else {
443+
// Handle object notation
444+
if (!current.containsKey(part)) {
445+
current.put(part, new HashMap<>());
446+
} else if (!(current.get(part) instanceof Map)) {
447+
return jsonObject;
448+
}
449+
current = (Map<String, Object>) current.get(part);
450+
}
451+
}
452+
453+
return jsonObject;
454+
}
455+
350456
public static void validateSchema(String schemaString, String instanceString) {
351457
try {
352458
// parse the schema JSON as string

0 commit comments

Comments
 (0)