@@ -135,6 +135,30 @@ public JSONObject searchSync(@NonNull Query query) throws AlgoliaException {
135135 return search (query );
136136 }
137137
138+ /**
139+ * Run multiple queries on this index with one API call.
140+ * A variant of {@link Client#multipleQueriesAsync(List, Client.MultipleQueriesStrategy, CompletionHandler)}
141+ * where the targeted index is always the receiver.
142+ *
143+ * @param queries The queries to run.
144+ * @param strategy The strategy to use.
145+ * @param completionHandler The listener that will be notified of the request's outcome.
146+ * @return A cancellable request.
147+ */
148+ public Request multipleQueriesAsync (final @ NonNull List <Query > queries , final Client .MultipleQueriesStrategy strategy , @ NonNull CompletionHandler completionHandler ) {
149+ final List <Query > queriesCopy = new ArrayList <>(queries .size ());
150+ for (Query query : queries ) {
151+ queriesCopy .add (new Query (query ));
152+ }
153+ return getClient ().new AsyncTaskRequest (completionHandler ) {
154+ @ NonNull
155+ @ Override
156+ JSONObject run () throws AlgoliaException {
157+ return multipleQueries (queriesCopy , strategy == null ? null : strategy .toString ());
158+ }
159+ }.start ();
160+ }
161+
138162 /**
139163 * Search inside this index synchronously.
140164 *
@@ -153,20 +177,22 @@ protected byte[] searchSyncRaw(@NonNull Query query) throws AlgoliaException {
153177 * @param completionHandler The listener that will be notified of the request's outcome.
154178 * @return A cancellable request.
155179 */
156- public Request searchDisjunctiveFacetingAsync (@ NonNull Query query , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements , @ NonNull CompletionHandler completionHandler ) {
157- final Query queryCopy = new Query (query );
158- final List <String > disjunctiveFacetsCopy = new ArrayList <>(disjunctiveFacets );
159- final Map <String , List <String >> refinementsCopy = new HashMap <>();
160- for (Map .Entry <String , List <String >> entry : refinements .entrySet ()) {
161- refinementsCopy .put (entry .getKey (), new ArrayList <String >(entry .getValue ()));
162- }
163- return getClient ().new AsyncTaskRequest (completionHandler ) {
164- @ NonNull
180+ public Request searchDisjunctiveFacetingAsync (@ NonNull Query query , @ NonNull final List <String > disjunctiveFacets , @ NonNull final Map <String , List <String >> refinements , @ NonNull final CompletionHandler completionHandler ) {
181+ final List <Query > queries = computeDisjunctiveFacetingQueries (query , disjunctiveFacets , refinements );
182+ return multipleQueriesAsync (queries , null , new CompletionHandler () {
165183 @ Override
166- JSONObject run () throws AlgoliaException {
167- return searchDisjunctiveFaceting (queryCopy , disjunctiveFacetsCopy , refinementsCopy );
184+ public void requestCompleted (JSONObject content , AlgoliaException error ) {
185+ JSONObject aggregatedResults = null ;
186+ try {
187+ if (content != null ) {
188+ aggregatedResults = aggregateDisjunctiveFacetingResults (content , disjunctiveFacets , refinements );
189+ }
190+ } catch (AlgoliaException e ) {
191+ error = e ;
192+ }
193+ completionHandler .requestCompleted (aggregatedResults , error );
168194 }
169- }. start ( );
195+ });
170196 }
171197
172198 /**
@@ -957,25 +983,38 @@ protected JSONObject clearIndex() throws AlgoliaException {
957983 }
958984
959985 /**
960- * Perform a search with disjunctive facets generating as many queries as number of disjunctive facets
986+ * Filter disjunctive refinements from generic refinements and a list of disjunctive facets.
961987 *
962- * @param query the query
963988 * @param disjunctiveFacets the array of disjunctive facets
964989 * @param refinements Map representing the current refinements
965- * @throws AlgoliaException
990+ * @return The disjunctive refinements
966991 */
967- protected JSONObject searchDisjunctiveFaceting ( @ NonNull Query query , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) throws AlgoliaException {
968- // Retain only refinements corresponding to the disjunctive facets.
992+ private @ NonNull Map < String , List < String >> computeDisjunctiveRefinements ( @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements )
993+ {
969994 Map <String , List <String >> disjunctiveRefinements = new HashMap <>();
970995 for (Map .Entry <String , List <String >> elt : refinements .entrySet ()) {
971996 if (disjunctiveFacets .contains (elt .getKey ())) {
972997 disjunctiveRefinements .put (elt .getKey (), elt .getValue ());
973998 }
974999 }
1000+ return disjunctiveRefinements ;
1001+ }
1002+
1003+ /**
1004+ * Compute the queries to run to implement disjunctive faceting.
1005+ *
1006+ * @param query The query.
1007+ * @param disjunctiveFacets List of disjunctive facets.
1008+ * @param refinements The current refinements, mapping facet names to a list of values.
1009+ * @return A list of queries suitable for {@link Index#multipleQueries}.
1010+ */
1011+ private @ NonNull List <Query > computeDisjunctiveFacetingQueries (@ NonNull Query query , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) {
1012+ // Retain only refinements corresponding to the disjunctive facets.
1013+ Map <String , List <String >> disjunctiveRefinements = computeDisjunctiveRefinements (disjunctiveFacets , refinements );
9751014
9761015 // build queries
9771016 // TODO: Refactor using JSON array notation: safer and clearer.
978- List <IndexQuery > queries = new ArrayList <>();
1017+ List <Query > queries = new ArrayList <>();
9791018 // hits + regular facets query
9801019 StringBuilder filters = new StringBuilder ();
9811020 boolean first_global = true ;
@@ -1010,7 +1049,7 @@ protected JSONObject searchDisjunctiveFaceting(@NonNull Query query, @NonNull Li
10101049 }
10111050 }
10121051
1013- queries .add (new IndexQuery ( this . indexName , new Query (query ).set ("facetFilters" , filters .toString () )));
1052+ queries .add (new Query (query ).set ("facetFilters" , filters .toString ()));
10141053 // one query per disjunctive facet (use all refinements but the current one + hitsPerPage=1 + single facet
10151054 for (String disjunctiveFacet : disjunctiveFacets ) {
10161055 filters = new StringBuilder ();
@@ -1049,11 +1088,25 @@ protected JSONObject searchDisjunctiveFaceting(@NonNull Query query, @NonNull Li
10491088 }
10501089 }
10511090 String [] facets = new String []{disjunctiveFacet };
1052- queries .add (new IndexQuery ( this . indexName , new Query (query ).setHitsPerPage (0 ).setAnalytics (false )
1091+ queries .add (new Query (query ).setHitsPerPage (0 ).setAnalytics (false )
10531092 .setAttributesToRetrieve ().setAttributesToHighlight ().setAttributesToSnippet ()
1054- .setFacets (facets ).set ("facetFilters" , filters .toString ()))) ;
1093+ .setFacets (facets ).set ("facetFilters" , filters .toString ()));
10551094 }
1056- JSONObject answers = this .client .multipleQueries (queries , null );
1095+ return queries ;
1096+ }
1097+
1098+ /**
1099+ * Aggregate results from multiple queries into disjunctive faceting results.
1100+ *
1101+ * @param answers The response from the multiple queries.
1102+ * @param disjunctiveFacets List of disjunctive facets.
1103+ * @param refinements Facet refinements.
1104+ * @return The aggregated results.
1105+ * @throws AlgoliaException
1106+ */
1107+ private JSONObject aggregateDisjunctiveFacetingResults (@ NonNull JSONObject answers , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) throws AlgoliaException
1108+ {
1109+ Map <String , List <String >> disjunctiveRefinements = computeDisjunctiveRefinements (disjunctiveFacets , refinements );
10571110
10581111 // aggregate answers
10591112 // first answer stores the hits + regular facets
@@ -1099,4 +1152,21 @@ protected JSONObject browseFrom(@NonNull String cursor) throws AlgoliaException
10991152 throw new Error (e ); // Should never happen: UTF-8 is always supported.
11001153 }
11011154 }
1155+
1156+ /**
1157+ * Run multiple queries on this index with one API call.
1158+ * A variant of {@link Client#multipleQueries(List, String)} where all queries target this index.
1159+ *
1160+ * @param queries Queries to run.
1161+ * @param strategy Strategy to use.
1162+ * @return The JSON results returned by the server.
1163+ * @throws AlgoliaException
1164+ */
1165+ protected JSONObject multipleQueries (@ NonNull List <Query > queries , String strategy ) throws AlgoliaException {
1166+ List <IndexQuery > requests = new ArrayList <>(queries .size ());
1167+ for (Query query : queries ) {
1168+ requests .add (new IndexQuery (this , query ));
1169+ }
1170+ return client .multipleQueries (requests , strategy );
1171+ }
11021172}
0 commit comments