11/*
2- * Copyright 2019-2021 the original author or authors.
2+ * Copyright 2019-2022 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1717
1818import java .util .ArrayList ;
1919import java .util .List ;
20+ import java .util .concurrent .CompletableFuture ;
2021import java .util .function .Function ;
2122
23+ import org .apache .commons .logging .Log ;
24+ import org .apache .commons .logging .LogFactory ;
2225import org .apache .lucene .search .TotalHits ;
2326import org .elasticsearch .action .search .SearchResponse ;
2427import org .elasticsearch .common .text .Text ;
3841
3942/**
4043 * This represents the complete search response from Elasticsearch, including the returned documents. Instances must be
41- * created with the {@link #from(SearchResponse,Function )} method.
44+ * created with the {@link #from(SearchResponse, EntityCreator )} method.
4245 *
4346 * @author Peter-Josef Meisch
4447 * @since 4.0
4548 */
4649public class SearchDocumentResponse {
4750
51+ private static final Log LOGGER = LogFactory .getLog (SearchDocumentResponse .class );
52+
4853 private final long totalHits ;
4954 private final String totalHitsRelation ;
5055 private final float maxScore ;
@@ -98,12 +103,11 @@ public Suggest getSuggest() {
98103 * creates a SearchDocumentResponse from the {@link SearchResponse}
99104 *
100105 * @param searchResponse must not be {@literal null}
101- * @param suggestEntityCreator function to create an entity from a {@link SearchDocument}
106+ * @param entityCreator function to create an entity from a {@link SearchDocument}
102107 * @param <T> entity type
103108 * @return the SearchDocumentResponse
104109 */
105- public static <T > SearchDocumentResponse from (SearchResponse searchResponse ,
106- Function <SearchDocument , T > suggestEntityCreator ) {
110+ public static <T > SearchDocumentResponse from (SearchResponse searchResponse , EntityCreator <T > entityCreator ) {
107111
108112 Assert .notNull (searchResponse , "searchResponse must not be null" );
109113
@@ -112,7 +116,7 @@ public static <T> SearchDocumentResponse from(SearchResponse searchResponse,
112116 Aggregations aggregations = searchResponse .getAggregations ();
113117 org .elasticsearch .search .suggest .Suggest suggest = searchResponse .getSuggest ();
114118
115- return from (searchHits , scrollId , aggregations , suggest , suggestEntityCreator );
119+ return from (searchHits , scrollId , aggregations , suggest , entityCreator );
116120 }
117121
118122 /**
@@ -122,14 +126,14 @@ public static <T> SearchDocumentResponse from(SearchResponse searchResponse,
122126 * @param scrollId scrollId
123127 * @param aggregations aggregations
124128 * @param suggestES the suggestion response from Elasticsearch
125- * @param suggestEntityCreator function to create an entity from a {@link SearchDocument}
129+ * @param entityCreator function to create an entity from a {@link SearchDocument}
126130 * @param <T> entity type
127131 * @return the {@link SearchDocumentResponse}
128132 * @since 4.3
129133 */
130134 public static <T > SearchDocumentResponse from (SearchHits searchHits , @ Nullable String scrollId ,
131135 @ Nullable Aggregations aggregations , @ Nullable org .elasticsearch .search .suggest .Suggest suggestES ,
132- Function < SearchDocument , T > suggestEntityCreator ) {
136+ EntityCreator < T > entityCreator ) {
133137
134138 TotalHits responseTotalHits = searchHits .getTotalHits ();
135139
@@ -153,14 +157,14 @@ public static <T> SearchDocumentResponse from(SearchHits searchHits, @Nullable S
153157 }
154158 }
155159
156- Suggest suggest = suggestFrom (suggestES , suggestEntityCreator );
160+ Suggest suggest = suggestFrom (suggestES , entityCreator );
157161 return new SearchDocumentResponse (totalHits , totalHitsRelation , maxScore , scrollId , searchDocuments , aggregations ,
158162 suggest );
159163 }
160164
161165 @ Nullable
162166 private static <T > Suggest suggestFrom (@ Nullable org .elasticsearch .search .suggest .Suggest suggestES ,
163- Function < SearchDocument , T > entityCreator ) {
167+ EntityCreator < T > entityCreator ) {
164168
165169 if (suggestES == null ) {
166170 return null ;
@@ -219,7 +223,19 @@ private static <T> Suggest suggestFrom(@Nullable org.elasticsearch.search.sugges
219223 List <CompletionSuggestion .Entry .Option <T >> options = new ArrayList <>();
220224 for (org .elasticsearch .search .suggest .completion .CompletionSuggestion .Entry .Option optionES : entryES ) {
221225 SearchDocument searchDocument = optionES .getHit () != null ? DocumentAdapters .from (optionES .getHit ()) : null ;
222- T hitEntity = searchDocument != null ? entityCreator .apply (searchDocument ) : null ;
226+
227+ T hitEntity = null ;
228+
229+ if (searchDocument != null ) {
230+ try {
231+ hitEntity = entityCreator .apply (searchDocument ).get ();
232+ } catch (Exception e ) {
233+ if (LOGGER .isWarnEnabled ()) {
234+ LOGGER .warn ("Error creating entity from SearchDocument" );
235+ }
236+ }
237+ }
238+
223239 options .add (new CompletionSuggestion .Entry .Option <T >(textToString (optionES .getText ()),
224240 textToString (optionES .getHighlighted ()), optionES .getScore (), optionES .collateMatch (),
225241 optionES .getContexts (), scoreDocFrom (optionES .getDoc ()), searchDocument , hitEntity ));
@@ -254,4 +270,14 @@ private static ScoreDoc scoreDocFrom(@Nullable org.apache.lucene.search.ScoreDoc
254270 private static String textToString (@ Nullable Text text ) {
255271 return text != null ? text .string () : "" ;
256272 }
273+
274+ /**
275+ * A function to convert a {@link SearchDocument} async into an entity. Asynchronous so that it can be used from the
276+ * imperative and the reactive code.
277+ *
278+ * @param <T> the entity type
279+ */
280+ @ FunctionalInterface
281+ public interface EntityCreator <T > extends Function <SearchDocument , CompletableFuture <T >> {}
282+
257283}
0 commit comments