diff --git a/src/main/java/org/opensearch/knn/index/IndexUtil.java b/src/main/java/org/opensearch/knn/index/IndexUtil.java index 574e4a9773..ffded7626f 100644 --- a/src/main/java/org/opensearch/knn/index/IndexUtil.java +++ b/src/main/java/org/opensearch/knn/index/IndexUtil.java @@ -59,6 +59,31 @@ public static int getFileSizeInKB(String filePath) { return Math.toIntExact((file.length() / BYTES_PER_KILOBYTES) + 1L); // Add one so that integer division rounds up } + /** + * Retrieves a field mapping from properties map by recursively searching through the map. + * + * @param properties A map representing properties, where each key is a property name and + * the value is either a sub-map of properties or the property value itself. + * @param field The name of the field to retrieve. + * @return The value of the field if found, or null if the field is not present in the map. + */ + public static Object getFieldMapping(Map properties, String field) { + if (properties.containsKey(field)) { + return properties.get(field); + } else { + for (Map.Entry entry : properties.entrySet()) { + Object value = entry.getValue(); + if (value instanceof Map) { + Object result = getFieldMapping((Map) value, field); + if (result != null) { + return result; + } + } + } + } + return null; + } + /** * Validate that a field is a k-NN vector field and has the expected dimension * @@ -100,7 +125,7 @@ public static ValidationException validateKnnField( return exception; } - Object fieldMapping = properties.get(field); + Object fieldMapping = getFieldMapping(properties, field); // Check field existence if (fieldMapping == null) { diff --git a/src/test/java/org/opensearch/knn/index/IndexUtilTests.java b/src/test/java/org/opensearch/knn/index/IndexUtilTests.java index 7013ef261a..938376cefd 100644 --- a/src/test/java/org/opensearch/knn/index/IndexUtilTests.java +++ b/src/test/java/org/opensearch/knn/index/IndexUtilTests.java @@ -20,6 +20,8 @@ import org.opensearch.knn.KNNTestCase; import org.opensearch.knn.index.util.KNNEngine; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import static org.mockito.ArgumentMatchers.anyString; @@ -67,4 +69,26 @@ public void testGetLoadParameters() { assertEquals(spaceType2.getValue(), loadParameters.get(SPACE_TYPE)); assertEquals(efSearchValue, loadParameters.get(HNSW_ALGO_EF_SEARCH)); } + + public void testGetFieldMappingNonNestedField() { + Map properties = new HashMap<>(); + properties.put("top_level_field", "top_level_value"); + + Object result = IndexUtil.getFieldMapping(properties, "top_level_field"); + assertEquals("top_level_value", result); + } + + public void testGetFieldMappingNestedField() { + Map deepNestedProperties = new HashMap<>(); + deepNestedProperties.put("deep_inner_field", "deep_value"); + + Map nestedProperties = new HashMap<>(); + nestedProperties.put("nested", Collections.singletonMap("properties", deepNestedProperties)); + + Map properties = new HashMap<>(); + properties.put("top", Collections.singletonMap("properties", nestedProperties)); + + Object deepResult = IndexUtil.getFieldMapping(properties, "deep_inner_field"); + assertEquals("deep_value", deepResult); + } }