Browse Source

Do NOT allow termvectors on nested fields (#32728)

Requesting _termvectors on a nested field or any sub-fields of a nested field
returns empty results.

Closes #21625
Mayya Sharipova 7 years ago
parent
commit
fdff8f3db0

+ 4 - 0
docs/reference/docs/termvectors.asciidoc

@@ -30,6 +30,10 @@ in similar way to the <<query-dsl-multi-match-query,multi match query>>
 [WARNING]
 Note that the usage of `/_termvector` is deprecated in 2.0, and replaced by `/_termvectors`.
 
+[WARNING]
+Term Vectors API doesn't work on nested fields. `/_termvectors` on a nested
+field and any sub-fields of a nested field returns empty results.
+
 [float]
 === Return values
 

+ 49 - 0
rest-api-spec/src/main/resources/rest-api-spec/test/termvectors/50_nested.yml

@@ -0,0 +1,49 @@
+setup:
+  - do:
+      indices.create:
+        index: testidx
+        body:
+          mappings:
+            _doc:
+              properties:
+                nested1:
+                  type : nested
+                  properties:
+                    nested1-text:
+                      type: text
+                object1:
+                  properties:
+                    object1-text:
+                      type: text
+                    object1-nested1:
+                      type: nested
+                      properties:
+                        object1-nested1-text:
+                          type: text
+  - do:
+      index:
+        index: testidx
+        type:  _doc
+        id:    1
+        body:
+          "nested1" : [{ "nested1-text": "text1" }]
+          "object1" : [{ "object1-text": "text2" }, "object1-nested1" : [{"object1-nested1-text" : "text3"}]]
+
+  - do:
+      indices.refresh: {}
+
+---
+"Termvectors on nested fields should return empty results":
+
+  - do:
+      termvectors:
+        index: testidx
+        type:  _doc
+        id: 1
+        fields: ["nested1", "nested1.nested1-text", "object1.object1-nested1", "object1.object1-nested1.object1-nested1-text", "object1.object1-text"]
+
+  - is_false: term_vectors.nested1
+  - is_false: term_vectors.nested1\.nested1-text # escaping as the field name contains dot
+  - is_false: term_vectors.object1\.object1-nested1
+  - is_false: term_vectors.object1\.object1-nested1\.object1-nested1-text
+  - is_true: term_vectors.object1\.object1-text

+ 14 - 3
server/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java

@@ -45,6 +45,7 @@ import org.elasticsearch.index.mapper.DocumentMapperForType;
 import org.elasticsearch.index.mapper.KeywordFieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.MapperService;
+import org.elasticsearch.index.mapper.ObjectMapper;
 import org.elasticsearch.index.mapper.ParseContext;
 import org.elasticsearch.index.mapper.ParsedDocument;
 import org.elasticsearch.index.mapper.SourceFieldMapper;
@@ -160,7 +161,7 @@ public class TermVectorsService  {
         request.selectedFields(fieldNames.toArray(Strings.EMPTY_ARRAY));
     }
 
-    private static boolean isValidField(MappedFieldType fieldType) {
+    private static boolean isValidField(MappedFieldType fieldType, IndexShard indexShard) {
         // must be a string
         if (fieldType instanceof StringFieldType == false) {
             return false;
@@ -169,6 +170,16 @@ public class TermVectorsService  {
         if (fieldType.indexOptions() == IndexOptions.NONE) {
             return false;
         }
+        // and must not be under nested field
+        int dotIndex = fieldType.name().indexOf('.');
+        while (dotIndex > -1) {
+            String parentField = fieldType.name().substring(0, dotIndex);
+            ObjectMapper mapper = indexShard.mapperService().getObjectMapper(parentField);
+            if (mapper != null && mapper.nested().isNested()) {
+                return false;
+            }
+            dotIndex = fieldType.name().indexOf('.', dotIndex + 1);
+        }
         return true;
     }
 
@@ -177,7 +188,7 @@ public class TermVectorsService  {
         Set<String> validFields = new HashSet<>();
         for (String field : selectedFields) {
             MappedFieldType fieldType = indexShard.mapperService().fullName(field);
-            if (!isValidField(fieldType)) {
+            if (isValidField(fieldType, indexShard) == false) {
                 continue;
             }
             // already retrieved, only if the analyzer hasn't been overridden at the field
@@ -284,7 +295,7 @@ public class TermVectorsService  {
         Collection<DocumentField> documentFields = new HashSet<>();
         for (IndexableField field : doc.getFields()) {
             MappedFieldType fieldType = indexShard.mapperService().fullName(field.name());
-            if (!isValidField(fieldType)) {
+            if (isValidField(fieldType, indexShard) == false) {
                 continue;
             }
             if (request.selectedFields() != null && !request.selectedFields().contains(field.name())) {