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
@@ -88,7 +95,43 @@ public FieldTypeLookup copyAndAddAll(String type,
88
95
aliases = aliases .copyAndPut (aliasName , path );
89
96
}
90
97
91
- return new FieldTypeLookup (fullName , aliases , jsonMappers );
98
+ int maxFieldDepth = getMaxJsonFieldDepth (aliases , jsonMappers );
99
+
100
+ return new FieldTypeLookup (fullName , aliases , jsonMappers , maxFieldDepth );
101
+ }
102
+
103
+ private static int getMaxJsonFieldDepth (CopyOnWriteHashMap <String , String > aliases ,
104
+ CopyOnWriteHashMap <String , JsonFieldMapper > jsonMappers ) {
105
+ int maxFieldDepth = 0 ;
106
+ for (Map .Entry <String , String > entry : aliases .entrySet ()) {
107
+ String aliasName = entry .getKey ();
108
+ String path = entry .getValue ();
109
+ if (jsonMappers .containsKey (path )) {
110
+ maxFieldDepth = Math .max (maxFieldDepth , fieldDepth (aliasName ));
111
+ }
112
+ }
113
+
114
+ for (String fieldName : jsonMappers .keySet ()) {
115
+ if (jsonMappers .containsKey (fieldName )) {
116
+ maxFieldDepth = Math .max (maxFieldDepth , fieldDepth (fieldName ));
117
+ }
118
+ }
119
+
120
+ return maxFieldDepth ;
121
+ }
122
+
123
+ /**
124
+ * Computes the total depth of this field by counting the number of parent fields
125
+ * in its path. As an example, the field 'parent1.parent2.field' has depth 3.
126
+ */
127
+ private static int fieldDepth (String field ) {
128
+ int numDots = 0 ;
129
+ for (int i = 0 ; i < field .length (); ++i ) {
130
+ if (field .charAt (i ) == '.' ) {
131
+ numDots ++;
132
+ }
133
+ }
134
+ return numDots + 1 ;
92
135
}
93
136
94
137
@@ -107,9 +150,20 @@ public MappedFieldType get(String field) {
107
150
return !fullNameToJsonMapper .isEmpty () ? getKeyedJsonField (field ) : null ;
108
151
}
109
152
153
+ /**
154
+ * Check if the given field corresponds to a keyed JSON field of the form
155
+ * 'path_to_json_field.path_to_key'. If so, returns a field type that can
156
+ * be used to perform searches on this field.
157
+ */
110
158
private MappedFieldType getKeyedJsonField (String field ) {
111
159
int dotIndex = -1 ;
160
+ int fieldDepth = 0 ;
161
+
112
162
while (true ) {
163
+ if (++fieldDepth > maxJsonFieldDepth ) {
164
+ return null ;
165
+ }
166
+
113
167
dotIndex = field .indexOf ('.' , dotIndex + 1 );
114
168
if (dotIndex < 0 ) {
115
169
return null ;
@@ -148,4 +202,9 @@ public Collection<String> simpleMatchToFullName(String pattern) {
148
202
public Iterator <MappedFieldType > iterator () {
149
203
return fullNameToFieldType .values ().iterator ();
150
204
}
205
+
206
+ // Visible for testing.
207
+ int maxJsonFieldDepth () {
208
+ return maxJsonFieldDepth ;
209
+ }
151
210
}
0 commit comments