25
25
import java .util .Collection ;
26
26
import java .util .HashSet ;
27
27
import java .util .Iterator ;
28
+ import java .util .Map ;
28
29
import java .util .Objects ;
29
30
import java .util .Set ;
30
31
@@ -35,20 +36,25 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
35
36
36
37
final CopyOnWriteHashMap <String , MappedFieldType > fullNameToFieldType ;
37
38
private final CopyOnWriteHashMap <String , String > aliasToConcreteName ;
39
+
38
40
private final CopyOnWriteHashMap <String , JsonFieldMapper > fullNameToJsonMapper ;
41
+ private final int maxJsonFieldDepth ;
39
42
40
43
FieldTypeLookup () {
41
44
fullNameToFieldType = new CopyOnWriteHashMap <>();
42
45
aliasToConcreteName = new CopyOnWriteHashMap <>();
43
46
fullNameToJsonMapper = new CopyOnWriteHashMap <>();
47
+ maxJsonFieldDepth = 0 ;
44
48
}
45
49
46
50
private FieldTypeLookup (CopyOnWriteHashMap <String , MappedFieldType > fullNameToFieldType ,
47
51
CopyOnWriteHashMap <String , String > aliasToConcreteName ,
48
- CopyOnWriteHashMap <String , JsonFieldMapper > fullNameToJsonMapper ) {
52
+ CopyOnWriteHashMap <String , JsonFieldMapper > fullNameToJsonMapper ,
53
+ int maxJsonFieldDepth ) {
49
54
this .fullNameToFieldType = fullNameToFieldType ;
50
55
this .aliasToConcreteName = aliasToConcreteName ;
51
56
this .fullNameToJsonMapper = fullNameToJsonMapper ;
57
+ this .maxJsonFieldDepth = maxJsonFieldDepth ;
52
58
}
53
59
54
60
/**
@@ -70,6 +76,7 @@ public FieldTypeLookup copyAndAddAll(String type,
70
76
CopyOnWriteHashMap <String , JsonFieldMapper > jsonMappers = this .fullNameToJsonMapper ;
71
77
72
78
for (FieldMapper fieldMapper : fieldMappers ) {
79
+ String fieldName = fieldMapper .name ();
73
80
MappedFieldType fieldType = fieldMapper .fieldType ();
74
81
MappedFieldType fullNameFieldType = fullName .get (fieldType .name ());
75
82
@@ -78,7 +85,7 @@ public FieldTypeLookup copyAndAddAll(String type,
78
85
}
79
86
80
87
if (fieldMapper instanceof JsonFieldMapper ) {
81
- jsonMappers = fullNameToJsonMapper .copyAndPut (fieldType . name () , (JsonFieldMapper ) fieldMapper );
88
+ jsonMappers = fullNameToJsonMapper .copyAndPut (fieldName , (JsonFieldMapper ) fieldMapper );
82
89
}
83
90
}
84
91
@@ -92,7 +99,43 @@ public FieldTypeLookup copyAndAddAll(String type,
92
99
}
93
100
}
94
101
95
- return new FieldTypeLookup (fullName , aliases , jsonMappers );
102
+ int maxFieldDepth = getMaxJsonFieldDepth (aliases , jsonMappers );
103
+
104
+ return new FieldTypeLookup (fullName , aliases , jsonMappers , maxFieldDepth );
105
+ }
106
+
107
+ private static int getMaxJsonFieldDepth (CopyOnWriteHashMap <String , String > aliases ,
108
+ CopyOnWriteHashMap <String , JsonFieldMapper > jsonMappers ) {
109
+ int maxFieldDepth = 0 ;
110
+ for (Map .Entry <String , String > entry : aliases .entrySet ()) {
111
+ String aliasName = entry .getKey ();
112
+ String path = entry .getValue ();
113
+ if (jsonMappers .containsKey (path )) {
114
+ maxFieldDepth = Math .max (maxFieldDepth , fieldDepth (aliasName ));
115
+ }
116
+ }
117
+
118
+ for (String fieldName : jsonMappers .keySet ()) {
119
+ if (jsonMappers .containsKey (fieldName )) {
120
+ maxFieldDepth = Math .max (maxFieldDepth , fieldDepth (fieldName ));
121
+ }
122
+ }
123
+
124
+ return maxFieldDepth ;
125
+ }
126
+
127
+ /**
128
+ * Computes the total depth of this field by counting the number of parent fields
129
+ * in its path. As an example, the field 'parent1.parent2.field' has depth 3.
130
+ */
131
+ private static int fieldDepth (String field ) {
132
+ int numDots = 0 ;
133
+ for (int i = 0 ; i < field .length (); ++i ) {
134
+ if (field .charAt (i ) == '.' ) {
135
+ numDots ++;
136
+ }
137
+ }
138
+ return numDots + 1 ;
96
139
}
97
140
98
141
@@ -111,9 +154,20 @@ public MappedFieldType get(String field) {
111
154
return !fullNameToJsonMapper .isEmpty () ? getKeyedJsonField (field ) : null ;
112
155
}
113
156
157
+ /**
158
+ * Check if the given field corresponds to a keyed JSON field of the form
159
+ * 'path_to_json_field.path_to_key'. If so, returns a field type that can
160
+ * be used to perform searches on this field.
161
+ */
114
162
private MappedFieldType getKeyedJsonField (String field ) {
115
163
int dotIndex = -1 ;
164
+ int fieldDepth = 0 ;
165
+
116
166
while (true ) {
167
+ if (++fieldDepth > maxJsonFieldDepth ) {
168
+ return null ;
169
+ }
170
+
117
171
dotIndex = field .indexOf ('.' , dotIndex + 1 );
118
172
if (dotIndex < 0 ) {
119
173
return null ;
@@ -152,4 +206,9 @@ public Collection<String> simpleMatchToFullName(String pattern) {
152
206
public Iterator <MappedFieldType > iterator () {
153
207
return fullNameToFieldType .values ().iterator ();
154
208
}
209
+
210
+ // Visible for testing.
211
+ int maxJsonFieldDepth () {
212
+ return maxJsonFieldDepth ;
213
+ }
155
214
}
0 commit comments