26
26
import android .support .annotation .NonNull ;
27
27
import android .support .annotation .Nullable ;
28
28
29
+ import com .algolia .search .saas .helpers .DisjunctiveFaceting ;
30
+
29
31
import org .json .JSONArray ;
30
32
import org .json .JSONException ;
31
33
import org .json .JSONObject ;
32
34
33
35
import java .io .UnsupportedEncodingException ;
34
36
import java .net .URLEncoder ;
35
37
import java .util .ArrayList ;
36
- import java .util .HashMap ;
37
- import java .util .Iterator ;
38
38
import java .util .List ;
39
39
import java .util .Map ;
40
40
41
41
/**
42
42
* A proxy to an Algolia index.
43
43
* <p>
44
- * You cannot construct this class directly. Please use {@link Client#initIndex (String)} to obtain an instance.
44
+ * You cannot construct this class directly. Please use {@link Client#getIndex (String)} to obtain an instance.
45
45
* </p>
46
46
* <p>
47
47
* WARNING: For performance reasons, arguments to asynchronous methods are not cloned. Therefore, you should not
@@ -173,21 +173,12 @@ protected byte[] searchSyncRaw(@NonNull Query query) throws AlgoliaException {
173
173
* @return A cancellable request.
174
174
*/
175
175
public Request searchDisjunctiveFacetingAsync (@ NonNull Query query , @ NonNull final List <String > disjunctiveFacets , @ NonNull final Map <String , List <String >> refinements , @ NonNull final CompletionHandler completionHandler ) {
176
- final List <Query > queries = computeDisjunctiveFacetingQueries (query , disjunctiveFacets , refinements );
177
- return multipleQueriesAsync (queries , null , new CompletionHandler () {
176
+ return new DisjunctiveFaceting () {
178
177
@ Override
179
- public void requestCompleted (JSONObject content , AlgoliaException error ) {
180
- JSONObject aggregatedResults = null ;
181
- try {
182
- if (content != null ) {
183
- aggregatedResults = aggregateDisjunctiveFacetingResults (content , disjunctiveFacets , refinements );
184
- }
185
- } catch (AlgoliaException e ) {
186
- error = e ;
187
- }
188
- completionHandler .requestCompleted (aggregatedResults , error );
178
+ protected Request multipleQueriesAsync (@ NonNull List <Query > queries , @ NonNull CompletionHandler completionHandler ) {
179
+ return Index .this .multipleQueriesAsync (queries , null , completionHandler );
189
180
}
190
- });
181
+ }. searchDisjunctiveFacetingAsync ( query , disjunctiveFacets , refinements , completionHandler );
191
182
}
192
183
193
184
/**
@@ -1056,142 +1047,6 @@ protected JSONObject clearIndex() throws AlgoliaException {
1056
1047
return client .postRequest ("/1/indexes/" + encodedIndexName + "/clear" , "" , false );
1057
1048
}
1058
1049
1059
- /**
1060
- * Filter disjunctive refinements from generic refinements and a list of disjunctive facets.
1061
- *
1062
- * @param disjunctiveFacets the array of disjunctive facets
1063
- * @param refinements Map representing the current refinements
1064
- * @return The disjunctive refinements
1065
- */
1066
- private
1067
- @ NonNull
1068
- Map <String , List <String >> computeDisjunctiveRefinements (@ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) {
1069
- Map <String , List <String >> disjunctiveRefinements = new HashMap <>();
1070
- for (Map .Entry <String , List <String >> elt : refinements .entrySet ()) {
1071
- if (disjunctiveFacets .contains (elt .getKey ())) {
1072
- disjunctiveRefinements .put (elt .getKey (), elt .getValue ());
1073
- }
1074
- }
1075
- return disjunctiveRefinements ;
1076
- }
1077
-
1078
- /**
1079
- * Compute the queries to run to implement disjunctive faceting.
1080
- *
1081
- * @param query The query.
1082
- * @param disjunctiveFacets List of disjunctive facets.
1083
- * @param refinements The current refinements, mapping facet names to a list of values.
1084
- * @return A list of queries suitable for {@link Index#multipleQueries}.
1085
- */
1086
- private @ NonNull
1087
- List <Query > computeDisjunctiveFacetingQueries (@ NonNull Query query , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) {
1088
- // Retain only refinements corresponding to the disjunctive facets.
1089
- Map <String , List <String >> disjunctiveRefinements = computeDisjunctiveRefinements (disjunctiveFacets , refinements );
1090
-
1091
- // build queries
1092
- List <Query > queries = new ArrayList <>();
1093
- // hits + regular facets query
1094
- JSONArray filters = new JSONArray ();
1095
- for (Map .Entry <String , List <String >> elt : refinements .entrySet ()) {
1096
- JSONArray or = new JSONArray ();
1097
- final boolean isDisjunctiveFacet = disjunctiveRefinements .containsKey (elt .getKey ());
1098
- for (String val : elt .getValue ()) {
1099
- if (isDisjunctiveFacet ) {
1100
- // disjunctive refinements are ORed
1101
- or .put (String .format ("%s:%s" , elt .getKey (), val ));
1102
- } else {
1103
- filters .put (String .format ("%s:%s" , elt .getKey (), val ));
1104
- }
1105
- }
1106
- // Add or
1107
- if (isDisjunctiveFacet ) {
1108
- filters .put (or );
1109
- }
1110
- }
1111
-
1112
- queries .add (new Query (query ).setFacetFilters (filters ));
1113
- // one query per disjunctive facet (use all refinements but the current one + hitsPerPage=1 + single facet
1114
- for (String disjunctiveFacet : disjunctiveFacets ) {
1115
- filters = new JSONArray ();
1116
-
1117
- for (Map .Entry <String , List <String >> elt : refinements .entrySet ()) {
1118
- if (disjunctiveFacet .equals (elt .getKey ())) {
1119
- continue ;
1120
- }
1121
- JSONArray or = new JSONArray ();
1122
- final boolean isDisjunctiveFacet = disjunctiveRefinements .containsKey (elt .getKey ());
1123
- for (String val : elt .getValue ()) {
1124
- if (isDisjunctiveFacet ) {
1125
- // disjunctive refinements are ORed
1126
- or .put (String .format ("%s:%s" , elt .getKey (), val ));
1127
- } else {
1128
- filters .put (String .format ("%s:%s" , elt .getKey (), val ));
1129
- }
1130
- }
1131
- // Add or
1132
- if (isDisjunctiveFacet ) {
1133
- filters .put (or );
1134
- }
1135
- }
1136
- String [] facets = new String []{disjunctiveFacet };
1137
- queries .add (new Query (query ).setHitsPerPage (0 ).setAnalytics (false )
1138
- .setAttributesToRetrieve ().setAttributesToHighlight ().setAttributesToSnippet ()
1139
- .setFacets (facets ).setFacetFilters (filters ));
1140
- }
1141
- return queries ;
1142
- }
1143
-
1144
- /**
1145
- * Aggregate results from multiple queries into disjunctive faceting results.
1146
- *
1147
- * @param answers The response from the multiple queries.
1148
- * @param disjunctiveFacets List of disjunctive facets.
1149
- * @param refinements Facet refinements.
1150
- * @return The aggregated results.
1151
- * @throws AlgoliaException
1152
- */
1153
- JSONObject aggregateDisjunctiveFacetingResults (@ NonNull JSONObject answers , @ NonNull List <String > disjunctiveFacets , @ NonNull Map <String , List <String >> refinements ) throws AlgoliaException {
1154
- Map <String , List <String >> disjunctiveRefinements = computeDisjunctiveRefinements (disjunctiveFacets , refinements );
1155
-
1156
- // aggregate answers
1157
- // first answer stores the hits + regular facets
1158
- try {
1159
- boolean nonExhaustiveFacetsCount = false ;
1160
- JSONArray results = answers .getJSONArray ("results" );
1161
- JSONObject aggregatedAnswer = results .getJSONObject (0 );
1162
- JSONObject disjunctiveFacetsJSON = new JSONObject ();
1163
- for (int i = 1 ; i < results .length (); ++i ) {
1164
- if (!results .getJSONObject (i ).optBoolean ("exhaustiveFacetsCount" )) {
1165
- nonExhaustiveFacetsCount = true ;
1166
- }
1167
- JSONObject facets = results .getJSONObject (i ).getJSONObject ("facets" );
1168
- @ SuppressWarnings ("unchecked" )
1169
- Iterator <String > keys = facets .keys ();
1170
- while (keys .hasNext ()) {
1171
- String key = keys .next ();
1172
- // Add the facet to the disjunctive facet hash
1173
- disjunctiveFacetsJSON .put (key , facets .getJSONObject (key ));
1174
- // concatenate missing refinements
1175
- if (!disjunctiveRefinements .containsKey (key )) {
1176
- continue ;
1177
- }
1178
- for (String refine : disjunctiveRefinements .get (key )) {
1179
- if (!disjunctiveFacetsJSON .getJSONObject (key ).has (refine )) {
1180
- disjunctiveFacetsJSON .getJSONObject (key ).put (refine , 0 );
1181
- }
1182
- }
1183
- }
1184
- }
1185
- aggregatedAnswer .put ("disjunctiveFacets" , disjunctiveFacetsJSON );
1186
- if (nonExhaustiveFacetsCount ) {
1187
- aggregatedAnswer .put ("exhaustiveFacetsCount" , false );
1188
- }
1189
- return aggregatedAnswer ;
1190
- } catch (JSONException e ) {
1191
- throw new AlgoliaException ("Failed to aggregate results" , e );
1192
- }
1193
- }
1194
-
1195
1050
protected JSONObject browse (@ NonNull Query query ) throws AlgoliaException {
1196
1051
return client .getRequest ("/1/indexes/" + encodedIndexName + "/browse?" + query .build (), true );
1197
1052
}
@@ -1220,4 +1075,4 @@ protected JSONObject multipleQueries(@NonNull List<Query> queries, String strate
1220
1075
}
1221
1076
return client .multipleQueries (requests , strategy );
1222
1077
}
1223
- }
1078
+ }
0 commit comments