Skip to content

Commit 96d0781

Browse files
authored
Parse returned suggest data using the new client.
Original Pull Request #2187 Closes #2154
1 parent 0a0fc75 commit 96d0781

14 files changed

+187
-45
lines changed

src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import co.elastic.clients.elasticsearch.core.MgetResponse;
2020
import co.elastic.clients.elasticsearch.core.explain.ExplanationDetail;
2121
import co.elastic.clients.elasticsearch.core.get.GetResult;
22+
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
2223
import co.elastic.clients.elasticsearch.core.search.Hit;
2324
import co.elastic.clients.elasticsearch.core.search.NestedIdentity;
2425
import co.elastic.clients.json.JsonData;
@@ -142,6 +143,21 @@ public static SearchDocument from(Hit<?> hit, JsonpMapper jsonpMapper) {
142143
highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
143144
}
144145

146+
public static SearchDocument from(CompletionSuggestOption<EntityAsMap> completionSuggestOption) {
147+
148+
Document document = completionSuggestOption.source() != null ? Document.from(completionSuggestOption.source())
149+
: Document.create();
150+
document.setIndex(completionSuggestOption.index());
151+
152+
if (completionSuggestOption.id() != null) {
153+
document.setId(completionSuggestOption.id());
154+
}
155+
156+
float score = completionSuggestOption.score() != null ? completionSuggestOption.score().floatValue() : Float.NaN;
157+
return new SearchDocumentAdapter(document, score, new Object[] {}, Collections.emptyMap(), Collections.emptyMap(),
158+
Collections.emptyMap(), null, null, null, completionSuggestOption.routing());
159+
}
160+
145161
@Nullable
146162
private static Explanation from(@Nullable co.elastic.clients.elasticsearch.core.explain.Explanation explanation) {
147163

src/main/java/org/springframework/data/elasticsearch/client/elc/SearchDocumentResponseBuilder.java

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,30 @@
1717

1818
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
1919
import co.elastic.clients.elasticsearch.core.SearchResponse;
20-
import co.elastic.clients.elasticsearch.core.search.Hit;
21-
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
22-
import co.elastic.clients.elasticsearch.core.search.ResponseBody;
23-
import co.elastic.clients.elasticsearch.core.search.Suggestion;
24-
import co.elastic.clients.elasticsearch.core.search.TotalHits;
20+
import co.elastic.clients.elasticsearch.core.search.*;
2521
import co.elastic.clients.json.JsonpMapper;
2622

2723
import java.util.ArrayList;
24+
import java.util.HashMap;
2825
import java.util.List;
2926
import java.util.Map;
27+
import java.util.Set;
28+
import java.util.stream.Collectors;
3029

30+
import org.apache.commons.logging.Log;
31+
import org.apache.commons.logging.LogFactory;
3132
import org.elasticsearch.search.SearchHits;
3233
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
3334
import org.springframework.data.elasticsearch.core.document.SearchDocument;
3435
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
36+
import org.springframework.data.elasticsearch.core.suggest.response.CompletionSuggestion;
37+
import org.springframework.data.elasticsearch.core.suggest.response.PhraseSuggestion;
3538
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
39+
import org.springframework.data.elasticsearch.core.suggest.response.TermSuggestion;
40+
import org.springframework.data.elasticsearch.support.ScoreDoc;
3641
import org.springframework.lang.Nullable;
3742
import org.springframework.util.Assert;
43+
import org.springframework.util.CollectionUtils;
3844

3945
/**
4046
* Factory class to create {@link SearchDocumentResponse} instances.
@@ -43,6 +49,9 @@
4349
* @since 4.4
4450
*/
4551
class SearchDocumentResponseBuilder {
52+
53+
private static final Log LOGGER = LogFactory.getLog(SearchDocumentResponseBuilder.class);
54+
4655
/**
4756
* creates a SearchDocumentResponse from the {@link SearchResponse}
4857
*
@@ -80,7 +89,7 @@ public static <T> SearchDocumentResponse from(ResponseBody<EntityAsMap> response
8089
* @return the {@link SearchDocumentResponse}
8190
*/
8291
public static <T> SearchDocumentResponse from(HitsMetadata<?> hitsMetadata, @Nullable String scrollId,
83-
Map<String, Aggregate> aggregations, Map<String, List<Suggestion<EntityAsMap>>> suggestES,
92+
@Nullable Map<String, Aggregate> aggregations, Map<String, List<Suggestion<EntityAsMap>>> suggestES,
8493
SearchDocumentResponse.EntityCreator<T> entityCreator, JsonpMapper jsonpMapper) {
8594

8695
Assert.notNull(hitsMetadata, "hitsMetadata must not be null");
@@ -116,10 +125,116 @@ public static <T> SearchDocumentResponse from(HitsMetadata<?> hitsMetadata, @Nul
116125
ElasticsearchAggregations aggregationsContainer = aggregations != null ? new ElasticsearchAggregations(aggregations)
117126
: null;
118127

119-
// todo #2154
120-
Suggest suggest = null;
128+
Suggest suggest = suggestFrom(suggestES, entityCreator);
121129

122130
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, scrollId, searchDocuments,
123131
aggregationsContainer, suggest);
124132
}
133+
134+
@Nullable
135+
private static <T> Suggest suggestFrom(Map<String, List<Suggestion<EntityAsMap>>> suggestES,
136+
SearchDocumentResponse.EntityCreator<T> entityCreator) {
137+
138+
if (CollectionUtils.isEmpty(suggestES)) {
139+
return null;
140+
}
141+
142+
List<Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>>> suggestions = new ArrayList<>();
143+
144+
suggestES.forEach((name, suggestionsES) -> {
145+
146+
if (!suggestionsES.isEmpty()) {
147+
// take the type from the first entry
148+
switch (suggestionsES.get(0)._kind()) {
149+
case Term: {
150+
suggestions.add(getTermSuggestion(name, suggestionsES));
151+
break;
152+
}
153+
case Phrase: {
154+
suggestions.add(getPhraseSuggestion(name, suggestionsES));
155+
break;
156+
}
157+
case Completion: {
158+
suggestions.add(getCompletionSuggestion(name, suggestionsES, entityCreator));
159+
break;
160+
}
161+
default:
162+
break;
163+
}
164+
}
165+
});
166+
167+
// todo: hasScoreDocs checks if any one
168+
boolean hasScoreDocs = false;
169+
170+
return new Suggest(suggestions, hasScoreDocs);
171+
}
172+
173+
private static TermSuggestion getTermSuggestion(String name, List<Suggestion<EntityAsMap>> suggestionsES) {
174+
175+
List<TermSuggestion.Entry> entries = new ArrayList<>();
176+
suggestionsES.forEach(suggestionES -> {
177+
TermSuggest termSuggest = suggestionES.term();
178+
179+
TermSuggestOption optionES = termSuggest.options();
180+
List<TermSuggestion.Entry.Option> options = new ArrayList<>();
181+
options.add(new TermSuggestion.Entry.Option(optionES.text(), null, optionES.score(), null,
182+
Math.toIntExact(optionES.freq())));
183+
entries.add(new TermSuggestion.Entry(termSuggest.text(), termSuggest.offset(), termSuggest.length(), options));
184+
});
185+
return new TermSuggestion(name, suggestionsES.size(), entries, null);
186+
}
187+
188+
private static PhraseSuggestion getPhraseSuggestion(String name, List<Suggestion<EntityAsMap>> suggestionsES) {
189+
190+
List<PhraseSuggestion.Entry> entries = new ArrayList<>();
191+
suggestionsES.forEach(suggestionES -> {
192+
PhraseSuggest phraseSuggest = suggestionES.phrase();
193+
PhraseSuggestOption optionES = phraseSuggest.options();
194+
List<PhraseSuggestion.Entry.Option> options = new ArrayList<>();
195+
options.add(new PhraseSuggestion.Entry.Option(optionES.text(), optionES.highlighted(), null, null));
196+
entries.add(new PhraseSuggestion.Entry(phraseSuggest.text(), phraseSuggest.offset(), phraseSuggest.length(),
197+
options, null));
198+
});
199+
return new PhraseSuggestion(name, suggestionsES.size(), entries);
200+
}
201+
202+
private static <T> CompletionSuggestion<T> getCompletionSuggestion(String name,
203+
List<Suggestion<EntityAsMap>> suggestionsES, SearchDocumentResponse.EntityCreator<T> entityCreator) {
204+
List<CompletionSuggestion.Entry<T>> entries = new ArrayList<>();
205+
suggestionsES.forEach(suggestionES -> {
206+
CompletionSuggest<EntityAsMap> completionSuggest = suggestionES.completion();
207+
List<CompletionSuggestion.Entry.Option<T>> options = new ArrayList<>();
208+
List<CompletionSuggestOption<EntityAsMap>> optionsES = completionSuggest.options();
209+
optionsES.forEach(optionES -> {
210+
SearchDocument searchDocument = (optionES.source() != null) ? DocumentAdapters.from(optionES) : null;
211+
T hitEntity = null;
212+
213+
if (searchDocument != null) {
214+
try {
215+
hitEntity = entityCreator.apply(searchDocument).get();
216+
} catch (Exception e) {
217+
if (LOGGER.isWarnEnabled()) {
218+
LOGGER.warn("Error creating entity from SearchDocument: " + e.getMessage());
219+
}
220+
}
221+
}
222+
223+
Map<String, Set<String>> contexts = new HashMap<>();
224+
optionES.contexts().forEach((key, contextList) -> contexts.put(key,
225+
contextList.stream().map(context -> context._get().toString()).collect(Collectors.toSet())));
226+
227+
// response from the new client does not have a doc and shardindex as the ScoreDoc from the old client responses
228+
229+
options.add(new CompletionSuggestion.Entry.Option<>(optionES.text(), null, optionES.score(),
230+
optionES.collateMatch() != null ? optionES.collateMatch() : false, contexts,
231+
new ScoreDoc(optionES.score() != null ? optionES.score() : Double.NaN, null, null), searchDocument,
232+
hitEntity));
233+
});
234+
235+
entries.add(new CompletionSuggestion.Entry<>(completionSuggest.text(), completionSuggest.offset(),
236+
completionSuggest.length(), options));
237+
});
238+
return new CompletionSuggestion<>(name, suggestionsES.size(), entries);
239+
}
125240
}

src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,9 +745,9 @@ public T doWith(@Nullable Document document) {
745745

746746
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of( //
747747
documentAfterLoad.hasId() ? documentAfterLoad.getId() : null, //
748-
documentAfterLoad.getSeqNo(), //
749-
documentAfterLoad.getPrimaryTerm(), //
750-
documentAfterLoad.getVersion()); //
748+
documentAfterLoad.hasSeqNo() ? documentAfterLoad.getSeqNo() : null, //
749+
documentAfterLoad.hasPrimaryTerm() ? documentAfterLoad.getPrimaryTerm() : null, //
750+
documentAfterLoad.hasVersion() ? documentAfterLoad.getVersion() : null); //
751751
entity = updateIndexedObject(entity, indexedObjectInformation);
752752

753753
return maybeCallbackAfterConvert(entity, documentAfterLoad, index);

src/main/java/org/springframework/data/elasticsearch/core/AbstractReactiveElasticsearchTemplate.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,9 @@ public Mono<T> toEntity(@Nullable Document document) {
549549

550550
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of( //
551551
documentAfterLoad.hasId() ? documentAfterLoad.getId() : null, //
552-
documentAfterLoad.getSeqNo(), //
553-
documentAfterLoad.getPrimaryTerm(), //
554-
documentAfterLoad.getVersion()); //
552+
documentAfterLoad.hasSeqNo() ? documentAfterLoad.getSeqNo() : null, //
553+
documentAfterLoad.hasPrimaryTerm() ? documentAfterLoad.getPrimaryTerm() : null, //
554+
documentAfterLoad.hasVersion() ? documentAfterLoad.getVersion() : null); //
555555
entity = updateIndexedObject(entity, indexedObjectInformation);
556556

557557
return maybeCallAfterConvert(entity, documentAfterLoad, index);

src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocumentResponseBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ private static <T> Suggest suggestFrom(@Nullable org.elasticsearch.search.sugges
156156
List<PhraseSuggestion.Entry.Option> options = new ArrayList<>();
157157
for (org.elasticsearch.search.suggest.phrase.PhraseSuggestion.Entry.Option optionES : entryES) {
158158
options.add(new PhraseSuggestion.Entry.Option(textToString(optionES.getText()),
159-
textToString(optionES.getHighlighted()), optionES.getScore(), optionES.collateMatch()));
159+
textToString(optionES.getHighlighted()), (double) optionES.getScore(), optionES.collateMatch()));
160160
}
161161

162162
entries.add(new PhraseSuggestion.Entry(textToString(entryES.getText()), entryES.getOffset(),
@@ -188,7 +188,7 @@ private static <T> Suggest suggestFrom(@Nullable org.elasticsearch.search.sugges
188188
}
189189

190190
options.add(new CompletionSuggestion.Entry.Option<>(textToString(optionES.getText()),
191-
textToString(optionES.getHighlighted()), optionES.getScore(), optionES.collateMatch(),
191+
textToString(optionES.getHighlighted()), (double) optionES.getScore(), optionES.collateMatch(),
192192
optionES.getContexts(), scoreDocFrom(optionES.getDoc()), searchDocument, hitEntity));
193193
}
194194

src/main/java/org/springframework/data/elasticsearch/core/suggest/response/CompletionSuggestion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static class Option<T> extends Suggest.Suggestion.Entry.Option {
4949
@Nullable private final T hitEntity;
5050
@Nullable private SearchHit<T> searchHit;
5151

52-
public Option(String text, String highlighted, float score, Boolean collateMatch,
52+
public Option(String text, @Nullable String highlighted, @Nullable Double score, Boolean collateMatch,
5353
Map<String, Set<String>> contexts, ScoreDoc scoreDoc, @Nullable SearchDocument searchDocument,
5454
@Nullable T hitEntity) {
5555
super(text, highlighted, score, collateMatch);

src/main/java/org/springframework/data/elasticsearch/core/suggest/response/PhraseSuggestion.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.suggest.response;
1717

18+
import org.springframework.lang.Nullable;
19+
1820
import java.util.List;
1921

2022
/**
@@ -29,20 +31,21 @@ public PhraseSuggestion(String name, int size, List<Entry> entries) {
2931

3032
public static class Entry extends Suggest.Suggestion.Entry<Entry.Option> {
3133

32-
private final double cutoffScore;
34+
@Nullable private final Double cutoffScore;
3335

34-
public Entry(String text, int offset, int length, List<Option> options, double cutoffScore) {
36+
public Entry(String text, int offset, int length, List<Option> options, @Nullable Double cutoffScore) {
3537
super(text, offset, length, options);
3638
this.cutoffScore = cutoffScore;
3739
}
3840

39-
public double getCutoffScore() {
41+
@Nullable
42+
public Double getCutoffScore() {
4043
return cutoffScore;
4144
}
4245

4346
public static class Option extends Suggest.Suggestion.Entry.Option {
4447

45-
public Option(String text, String highlighted, float score, Boolean collateMatch) {
48+
public Option(String text, String highlighted, @Nullable Double score, @Nullable Boolean collateMatch) {
4649
super(text, highlighted, score, collateMatch);
4750
}
4851
}

src/main/java/org/springframework/data/elasticsearch/core/suggest/response/Suggest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,12 @@ public List<O> getOptions() {
106106

107107
public abstract static class Option {
108108
private final String text;
109-
private final String highlighted;
110-
private final float score;
109+
@Nullable private final String highlighted;
110+
@Nullable private final Double score;
111111
@Nullable private final Boolean collateMatch;
112112

113-
public Option(String text, String highlighted, float score, @Nullable Boolean collateMatch) {
113+
public Option(String text, @Nullable String highlighted, @Nullable Double score,
114+
@Nullable Boolean collateMatch) {
114115
this.text = text;
115116
this.highlighted = highlighted;
116117
this.score = score;
@@ -121,11 +122,13 @@ public String getText() {
121122
return text;
122123
}
123124

125+
@Nullable
124126
public String getHighlighted() {
125127
return highlighted;
126128
}
127129

128-
public float getScore() {
130+
@Nullable
131+
public Double getScore() {
129132
return score;
130133
}
131134

src/main/java/org/springframework/data/elasticsearch/core/suggest/response/TermSuggestion.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,23 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.suggest.response;
1717

18+
import org.springframework.lang.Nullable;
19+
1820
import java.util.List;
1921

2022
/**
2123
* @author Peter-Josef Meisch
2224
*/
2325
public class TermSuggestion extends Suggest.Suggestion<TermSuggestion.Entry> {
2426

25-
private final SortBy sort;
27+
@Nullable private final SortBy sort;
2628

27-
public TermSuggestion(String name, int size, List<Entry> entries, SortBy sort) {
29+
public TermSuggestion(String name, int size, List<Entry> entries, @Nullable SortBy sort) {
2830
super(name, size, entries);
2931
this.sort = sort;
3032
}
3133

34+
@Nullable
3235
public SortBy getSort() {
3336
return sort;
3437
}
@@ -43,7 +46,7 @@ public static class Option extends Suggest.Suggestion.Entry.Option {
4346

4447
private final int freq;
4548

46-
public Option(String text, String highlighted, float score, Boolean collateMatch, int freq) {
49+
public Option(String text, @Nullable String highlighted, double score, @Nullable Boolean collateMatch, int freq) {
4750
super(text, highlighted, score, collateMatch);
4851
this.freq = freq;
4952
}

0 commit comments

Comments
 (0)