Skip to content

Commit fdff8f3

Browse files
Do NOT allow termvectors on nested fields (elastic#32728)
Requesting _termvectors on a nested field or any sub-fields of a nested field returns empty results. Closes elastic#21625
1 parent 8f8d3a5 commit fdff8f3

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

docs/reference/docs/termvectors.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ in similar way to the <<query-dsl-multi-match-query,multi match query>>
3030
[WARNING]
3131
Note that the usage of `/_termvector` is deprecated in 2.0, and replaced by `/_termvectors`.
3232

33+
[WARNING]
34+
Term Vectors API doesn't work on nested fields. `/_termvectors` on a nested
35+
field and any sub-fields of a nested field returns empty results.
36+
3337
[float]
3438
=== Return values
3539

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
setup:
2+
- do:
3+
indices.create:
4+
index: testidx
5+
body:
6+
mappings:
7+
_doc:
8+
properties:
9+
nested1:
10+
type : nested
11+
properties:
12+
nested1-text:
13+
type: text
14+
object1:
15+
properties:
16+
object1-text:
17+
type: text
18+
object1-nested1:
19+
type: nested
20+
properties:
21+
object1-nested1-text:
22+
type: text
23+
- do:
24+
index:
25+
index: testidx
26+
type: _doc
27+
id: 1
28+
body:
29+
"nested1" : [{ "nested1-text": "text1" }]
30+
"object1" : [{ "object1-text": "text2" }, "object1-nested1" : [{"object1-nested1-text" : "text3"}]]
31+
32+
- do:
33+
indices.refresh: {}
34+
35+
---
36+
"Termvectors on nested fields should return empty results":
37+
38+
- do:
39+
termvectors:
40+
index: testidx
41+
type: _doc
42+
id: 1
43+
fields: ["nested1", "nested1.nested1-text", "object1.object1-nested1", "object1.object1-nested1.object1-nested1-text", "object1.object1-text"]
44+
45+
- is_false: term_vectors.nested1
46+
- is_false: term_vectors.nested1\.nested1-text # escaping as the field name contains dot
47+
- is_false: term_vectors.object1\.object1-nested1
48+
- is_false: term_vectors.object1\.object1-nested1\.object1-nested1-text
49+
- is_true: term_vectors.object1\.object1-text

server/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.elasticsearch.index.mapper.KeywordFieldMapper;
4646
import org.elasticsearch.index.mapper.MappedFieldType;
4747
import org.elasticsearch.index.mapper.MapperService;
48+
import org.elasticsearch.index.mapper.ObjectMapper;
4849
import org.elasticsearch.index.mapper.ParseContext;
4950
import org.elasticsearch.index.mapper.ParsedDocument;
5051
import org.elasticsearch.index.mapper.SourceFieldMapper;
@@ -160,7 +161,7 @@ private static void handleFieldWildcards(IndexShard indexShard, TermVectorsReque
160161
request.selectedFields(fieldNames.toArray(Strings.EMPTY_ARRAY));
161162
}
162163

163-
private static boolean isValidField(MappedFieldType fieldType) {
164+
private static boolean isValidField(MappedFieldType fieldType, IndexShard indexShard) {
164165
// must be a string
165166
if (fieldType instanceof StringFieldType == false) {
166167
return false;
@@ -169,6 +170,16 @@ private static boolean isValidField(MappedFieldType fieldType) {
169170
if (fieldType.indexOptions() == IndexOptions.NONE) {
170171
return false;
171172
}
173+
// and must not be under nested field
174+
int dotIndex = fieldType.name().indexOf('.');
175+
while (dotIndex > -1) {
176+
String parentField = fieldType.name().substring(0, dotIndex);
177+
ObjectMapper mapper = indexShard.mapperService().getObjectMapper(parentField);
178+
if (mapper != null && mapper.nested().isNested()) {
179+
return false;
180+
}
181+
dotIndex = fieldType.name().indexOf('.', dotIndex + 1);
182+
}
172183
return true;
173184
}
174185

@@ -177,7 +188,7 @@ private static Fields addGeneratedTermVectors(IndexShard indexShard, Engine.GetR
177188
Set<String> validFields = new HashSet<>();
178189
for (String field : selectedFields) {
179190
MappedFieldType fieldType = indexShard.mapperService().fullName(field);
180-
if (!isValidField(fieldType)) {
191+
if (isValidField(fieldType, indexShard) == false) {
181192
continue;
182193
}
183194
// already retrieved, only if the analyzer hasn't been overridden at the field
@@ -284,7 +295,7 @@ private static Fields generateTermVectorsFromDoc(IndexShard indexShard, TermVect
284295
Collection<DocumentField> documentFields = new HashSet<>();
285296
for (IndexableField field : doc.getFields()) {
286297
MappedFieldType fieldType = indexShard.mapperService().fullName(field.name());
287-
if (!isValidField(fieldType)) {
298+
if (isValidField(fieldType, indexShard) == false) {
288299
continue;
289300
}
290301
if (request.selectedFields() != null && !request.selectedFields().contains(field.name())) {

0 commit comments

Comments
 (0)