Browse Source

Fix bug where field is not returned if it has the same prefix as a nested field (#82922)

We currently only check if a field starts with the same characters as a nested prefix but we do not check that the next
character of the field is a path separator ('.'). This commit updates the check to make sure we distinguish between a 
nested path and a field with the same nested prefix.
Ignacio Vera 3 years ago
parent
commit
036eb8055d

+ 3 - 1
server/src/main/java/org/elasticsearch/search/fetch/subphase/FieldFetcher.java

@@ -87,7 +87,9 @@ public class FieldFetcher {
                 if (nestedParentPaths.isEmpty() == false) {
                     // try to find the shortest nested parent path for this field
                     for (String nestedFieldPath : nestedParentPaths) {
-                        if (field.startsWith(nestedFieldPath)) {
+                        if (field.startsWith(nestedFieldPath)
+                            && field.length() > nestedFieldPath.length()
+                            && field.charAt(nestedFieldPath.length()) == '.') {
                             nestedParentPath = nestedFieldPath;
                             break;
                         }

+ 27 - 0
server/src/test/java/org/elasticsearch/search/fetch/subphase/FieldFetcherTests.java

@@ -1002,6 +1002,33 @@ public class FieldFetcherTests extends MapperServiceTestCase {
         assertThat(fields.get("date_field").getValues().get(1), equalTo("12"));
     }
 
+    public void testNestedPrefix() throws IOException {
+        String mapping = """
+            {
+              "_doc": {
+                "properties" : {
+                  "foo" : {
+                    "type" : "nested",
+                    "properties" : {
+                      "nested_field" : {
+                        "type" : "keyword"
+                      }
+                    }
+                  },
+                  "foo_bar" : {
+                    "type" : "double"
+                  }
+                }
+              }
+            }
+            """;
+        MapperService mapperService = createMapperService(mapping);
+        XContentBuilder source = XContentFactory.jsonBuilder().startObject().field("foo_bar", 3.1).endObject();
+        // the field should be returned
+        Map<String, DocumentField> fields = fetchFields(mapperService, source, "foo_bar");
+        assertThat(fields.get("foo_bar").getValues().size(), equalTo(1));
+    }
+
     /**
      * Field patterns retrieved with "include_unmapped" use an automaton with a maximal allowed size internally.
      * This test checks we have a bound in place to avoid misuse of this with exceptionally large field patterns