Skip to content

Commit 05ca2f9

Browse files
authored
Back porting Completion types with multi-fields support (#34081) (#34228)
Mappings with completion type and multi-fields, were not able to index array or object format on completion fields. Only string format was supported. This is fixed by providing multiField parser with externalValueContext with already parsed object * Adapt test after backport of #34081 closes #15115
1 parent f2a2766 commit 05ca2f9

File tree

3 files changed

+724
-12
lines changed

3 files changed

+724
-12
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
2+
---
3+
"Search by suggestion and by keyword sub-field should work":
4+
5+
- skip:
6+
version: " - 6.4.99"
7+
reason: "Search by suggestion with multi-fields was introduced 7.0.0"
8+
9+
- do:
10+
indices.create:
11+
index: completion_with_sub_keyword
12+
body:
13+
mappings:
14+
test:
15+
"properties":
16+
"suggest_1":
17+
"type" : "completion"
18+
"fields":
19+
"text_raw":
20+
"type" : "keyword"
21+
22+
- do:
23+
index:
24+
index: completion_with_sub_keyword
25+
type: test
26+
id: 1
27+
body:
28+
suggest_1: "bar"
29+
30+
- do:
31+
index:
32+
index: completion_with_sub_keyword
33+
type: test
34+
id: 2
35+
body:
36+
suggest_1: "baz"
37+
38+
- do:
39+
indices.refresh: {}
40+
41+
- do:
42+
search:
43+
index: completion_with_sub_keyword
44+
body:
45+
suggest:
46+
result:
47+
text: "b"
48+
completion:
49+
field: suggest_1
50+
51+
- length: { suggest.result: 1 }
52+
- length: { suggest.result.0.options: 2 }
53+
54+
55+
- do:
56+
search:
57+
index: completion_with_sub_keyword
58+
body:
59+
query: { term: { suggest_1.text_raw: "bar" }}
60+
61+
- match: { hits.total: 1 }
62+
63+
64+
65+
---
66+
"Search by suggestion on sub field should work":
67+
68+
- skip:
69+
version: " - 6.4.99"
70+
reason: "Search by suggestion with multi-fields was introduced 7.0.0"
71+
72+
- do:
73+
indices.create:
74+
index: completion_with_sub_completion
75+
body:
76+
mappings:
77+
test:
78+
"properties":
79+
"suggest_1":
80+
"type": "completion"
81+
"fields":
82+
"suggest_2":
83+
"type": "completion"
84+
85+
- do:
86+
index:
87+
index: completion_with_sub_completion
88+
type: test
89+
id: 1
90+
body:
91+
suggest_1: "bar"
92+
93+
- do:
94+
index:
95+
index: completion_with_sub_completion
96+
type: test
97+
id: 2
98+
body:
99+
suggest_1: "baz"
100+
101+
- do:
102+
indices.refresh: {}
103+
104+
- do:
105+
search:
106+
index: completion_with_sub_completion
107+
body:
108+
suggest:
109+
result:
110+
text: "b"
111+
completion:
112+
field: suggest_1.suggest_2
113+
114+
- length: { suggest.result: 1 }
115+
- length: { suggest.result.0.options: 2 }
116+
117+
---
118+
"Search by suggestion on sub field with context should work":
119+
120+
- skip:
121+
version: " - 6.4.99"
122+
reason: "Search by suggestion with multi-fields was introduced 7.0.0"
123+
124+
- do:
125+
indices.create:
126+
index: completion_with_context
127+
body:
128+
mappings:
129+
test:
130+
"properties":
131+
"suggest_1":
132+
"type": "completion"
133+
"contexts":
134+
-
135+
"name": "color"
136+
"type": "category"
137+
"fields":
138+
"suggest_2":
139+
"type": "completion"
140+
"contexts":
141+
-
142+
"name": "color"
143+
"type": "category"
144+
145+
146+
- do:
147+
index:
148+
index: completion_with_context
149+
type: test
150+
id: 1
151+
body:
152+
suggest_1:
153+
input: "foo red"
154+
contexts:
155+
color: "red"
156+
157+
- do:
158+
index:
159+
index: completion_with_context
160+
type: test
161+
id: 2
162+
body:
163+
suggest_1:
164+
input: "foo blue"
165+
contexts:
166+
color: "blue"
167+
168+
- do:
169+
indices.refresh: {}
170+
171+
- do:
172+
search:
173+
index: completion_with_context
174+
body:
175+
suggest:
176+
result:
177+
prefix: "foo"
178+
completion:
179+
field: suggest_1.suggest_2
180+
contexts:
181+
color: "red"
182+
183+
- length: { suggest.result: 1 }
184+
- length: { suggest.result.0.options: 1 }
185+
- match: { suggest.result.0.options.0.text: "foo red" }
186+
187+
188+
---
189+
"Search by suggestion on sub field with weight should work":
190+
191+
- skip:
192+
version: " - 6.4.99"
193+
reason: "Search by suggestion with multi-fields was introduced 7.0.0"
194+
195+
- do:
196+
indices.create:
197+
index: completion_with_weight
198+
body:
199+
mappings:
200+
test:
201+
"properties":
202+
"suggest_1":
203+
"type": "completion"
204+
"fields":
205+
"suggest_2":
206+
"type": "completion"
207+
208+
- do:
209+
index:
210+
index: completion_with_weight
211+
type: test
212+
id: 1
213+
body:
214+
suggest_1:
215+
input: "bar"
216+
weight: 2
217+
218+
- do:
219+
index:
220+
index: completion_with_weight
221+
type: test
222+
id: 2
223+
body:
224+
suggest_1:
225+
input: "baz"
226+
weight: 3
227+
228+
- do:
229+
indices.refresh: {}
230+
231+
- do:
232+
search:
233+
index: completion_with_weight
234+
body:
235+
suggest:
236+
result:
237+
text: "b"
238+
completion:
239+
field: suggest_1.suggest_2
240+
241+
- length: { suggest.result: 1 }
242+
- length: { suggest.result.0.options: 2 }
243+
- match: { suggest.result.0.options.0.text: "baz" }
244+
- match: { suggest.result.0.options.1.text: "bar" }
245+
246+
---
247+
"Search by suggestion on geofield-hash on sub field should work":
248+
249+
- skip:
250+
version: " - 6.4.99"
251+
reason: "Search by suggestion with multi-fields was introduced 7.0.0"
252+
253+
- do:
254+
indices.create:
255+
index: geofield_with_completion
256+
body:
257+
mappings:
258+
test:
259+
"properties":
260+
"geofield":
261+
"type": "geo_point"
262+
"fields":
263+
"suggest_1":
264+
"type": "completion"
265+
266+
- do:
267+
index:
268+
index: geofield_with_completion
269+
type: test
270+
id: 1
271+
body:
272+
geofield: "hgjhrwysvqw7"
273+
#41.12,-72.34,12
274+
275+
- do:
276+
index:
277+
index: geofield_with_completion
278+
type: test
279+
id: 1
280+
body:
281+
geofield: "hgm4psywmkn7"
282+
#41.12,-71.34,12
283+
284+
- do:
285+
indices.refresh: {}
286+
287+
- do:
288+
search:
289+
index: geofield_with_completion
290+
body:
291+
suggest:
292+
result:
293+
prefix: "hgm"
294+
completion:
295+
field: geofield.suggest_1
296+
297+
298+
- length: { suggest.result: 1 }
299+
- length: { suggest.result.0.options: 1 }

server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,9 @@ public void parse(ParseContext context) throws IOException {
436436
Token token = parser.currentToken();
437437
Map<String, CompletionInputMetaData> inputMap = new HashMap<>(1);
438438

439-
// ignore null values
440-
if (token == Token.VALUE_NULL) {
439+
if (context.externalValueSet()) {
440+
inputMap = getInputMapFromExternalValue(context);
441+
} else if (token == Token.VALUE_NULL) { // ignore null values
441442
return;
442443
} else if (token == Token.START_ARRAY) {
443444
while ((token = parser.nextToken()) != Token.END_ARRAY) {
@@ -471,12 +472,33 @@ public void parse(ParseContext context) throws IOException {
471472
context.doc().add(new SuggestField(fieldType().name(), input, metaData.weight));
472473
}
473474
}
475+
474476
List<IndexableField> fields = new ArrayList<>(1);
475477
createFieldNamesField(context, fields);
476478
for (IndexableField field : fields) {
477479
context.doc().add(field);
478480
}
479-
multiFields.parse(this, context);
481+
482+
for (CompletionInputMetaData metaData: inputMap.values()) {
483+
ParseContext externalValueContext = context.createExternalValueContext(metaData);
484+
multiFields.parse(this, externalValueContext);
485+
}
486+
}
487+
488+
private Map<String, CompletionInputMetaData> getInputMapFromExternalValue(ParseContext context) {
489+
Map<String, CompletionInputMetaData> inputMap;
490+
if (isExternalValueOfClass(context, CompletionInputMetaData.class)) {
491+
CompletionInputMetaData inputAndMeta = (CompletionInputMetaData) context.externalValue();
492+
inputMap = Collections.singletonMap(inputAndMeta.input, inputAndMeta);
493+
} else {
494+
String fieldName = context.externalValue().toString();
495+
inputMap = Collections.singletonMap(fieldName, new CompletionInputMetaData(fieldName, Collections.emptyMap(), 1));
496+
}
497+
return inputMap;
498+
}
499+
500+
private boolean isExternalValueOfClass(ParseContext context, Class<?> clazz) {
501+
return context.externalValue().getClass().equals(clazz);
480502
}
481503

482504
/**
@@ -487,7 +509,7 @@ public void parse(ParseContext context) throws IOException {
487509
private void parse(ParseContext parseContext, Token token, XContentParser parser, Map<String, CompletionInputMetaData> inputMap) throws IOException {
488510
String currentFieldName = null;
489511
if (token == Token.VALUE_STRING) {
490-
inputMap.put(parser.text(), new CompletionInputMetaData(Collections.<String, Set<CharSequence>>emptyMap(), 1));
512+
inputMap.put(parser.text(), new CompletionInputMetaData(parser.text(), Collections.emptyMap(), 1));
491513
} else if (token == Token.START_OBJECT) {
492514
Set<String> inputs = new HashSet<>();
493515
int weight = 1;
@@ -561,7 +583,7 @@ private void parse(ParseContext parseContext, Token token, XContentParser parser
561583
}
562584
for (String input : inputs) {
563585
if (inputMap.containsKey(input) == false || inputMap.get(input).weight < weight) {
564-
inputMap.put(input, new CompletionInputMetaData(contextsMap, weight));
586+
inputMap.put(input, new CompletionInputMetaData(input, contextsMap, weight));
565587
}
566588
}
567589
} else {
@@ -570,13 +592,20 @@ private void parse(ParseContext parseContext, Token token, XContentParser parser
570592
}
571593

572594
static class CompletionInputMetaData {
595+
public final String input;
573596
public final Map<String, Set<CharSequence>> contexts;
574597
public final int weight;
575598

576-
CompletionInputMetaData(Map<String, Set<CharSequence>> contexts, int weight) {
599+
CompletionInputMetaData(String input, Map<String, Set<CharSequence>> contexts, int weight) {
600+
this.input = input;
577601
this.contexts = contexts;
578602
this.weight = weight;
579603
}
604+
605+
@Override
606+
public String toString() {
607+
return input;
608+
}
580609
}
581610

582611
@Override

0 commit comments

Comments
 (0)