Skip to content
This repository was archived by the owner on Jan 31, 2022. It is now read-only.

Commit 180366a

Browse files
authored
Index: Implement search in facets (#163)
* Index: Implement search in facets * Index: Overload searchFacet for query-less usage * Index.searchFacet: Add NonNull annotations, more explicit code/parameter name * Index.searchForFacetValues: Rename from searchFacet * Travis: use travis_wait to investigate CI failures * IndexTest: Fix typo [ci skip]
1 parent 4bcac3c commit 180366a

File tree

2 files changed

+127
-4
lines changed

2 files changed

+127
-4
lines changed

algoliasearch/src/main/java/com/algolia/search/saas/Index.java

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,47 @@ protected Request multipleQueriesAsync(@NonNull List<Query> queries, @NonNull Co
181181
}.searchDisjunctiveFacetingAsync(query, disjunctiveFacets, refinements, completionHandler);
182182
}
183183

184+
/**
185+
* Search for some text in a facet values.
186+
*
187+
* @param facetName The name of the facet to search. It must have been declared in the index's `attributesForFaceting` setting with the `searchable()` modifier.
188+
* @param text The text to search for in the facet's values.
189+
* @param handler A Completion handler that will be notified of the request's outcome.
190+
* @return A cancellable request.
191+
*/
192+
public Request searchForFacetValues(@NonNull String facetName, @NonNull String text, @NonNull final CompletionHandler handler) throws AlgoliaException {
193+
return searchForFacetValues(facetName, text, null, handler);
194+
}
195+
196+
/**
197+
* Search for some text in a facet values, optionally restricting the returned values to those contained in objects matching other (regular) search criteria.
198+
*
199+
* @param facetName The name of the facet to search. It must have been declared in the index's `attributesForFaceting` setting with the `searchable()` modifier.
200+
* @param facetText The text to search for in the facet's values.
201+
* @param query An optional query to take extra search parameters into account. There parameters apply to index objects like in a regular search query. Only facet values contained in the matched objects will be returned
202+
* @param handler A Completion handler that will be notified of the request's outcome.
203+
* @return A cancellable request.
204+
*/
205+
public Request searchForFacetValues(@NonNull String facetName, @NonNull String facetText, @Nullable Query query, @NonNull final CompletionHandler handler) throws AlgoliaException {
206+
try {
207+
final String path = "/1/indexes/" + getEncodedIndexName() + "/facets/" + URLEncoder.encode(facetName, "UTF-8") + "/query";
208+
final Query params = (query != null ? new Query(query) : new Query());
209+
params.set("facetQuery", facetText);
210+
final JSONObject requestBody = new JSONObject().put("params", params.build());
211+
212+
final Client client = getClient();
213+
return client.new AsyncTaskRequest(handler) {
214+
@NonNull
215+
@Override
216+
protected JSONObject run() throws AlgoliaException {
217+
return client.postRequest(path, requestBody.toString(), true);
218+
}
219+
}.start();
220+
} catch (UnsupportedEncodingException | JSONException e) {
221+
throw new AlgoliaException(e.getMessage());
222+
}
223+
}
224+
184225
/**
185226
* Add an object to this index (asynchronously).
186227
* <p>
@@ -274,7 +315,7 @@ public Request saveObjectsAsync(final @NonNull JSONArray objects, @NonNull Compl
274315

275316
/**
276317
* Partially update an object (asynchronously).
277-
*
318+
* <p>
278319
* **Note:** This method will create the object if it does not exist already. If you don't wish to, you can use
279320
* {@link #partialUpdateObjectAsync(JSONObject, String, boolean, CompletionHandler)} and specify `false` for the
280321
* `createIfNotExists` argument.
@@ -313,7 +354,7 @@ public Request partialUpdateObjectAsync(final @NonNull JSONObject partialObject,
313354

314355
/**
315356
* Partially update several objects (asynchronously).
316-
*
357+
* <p>
317358
* **Note:** This method will create the objects if they do not exist already. If you don't wish to, you can use
318359
* {@link #partialUpdateObjectsAsync(JSONArray, boolean, CompletionHandler)} and specify `false` for the
319360
* `createIfNotExists` argument.
@@ -500,7 +541,7 @@ public Request getSettingsAsync(@NonNull CompletionHandler completionHandler) {
500541

501542
/**
502543
* Set this index's settings (asynchronously).
503-
*
544+
* <p>
504545
* Please refer to our <a href="https://www.algolia.com/doc/android#index-settings">API documentation</a> for the
505546
* list of supported settings.
506547
*
@@ -1029,7 +1070,7 @@ protected JSONObject setSettings(JSONObject settings) throws AlgoliaException {
10291070
/**
10301071
* Set settings for this index.
10311072
*
1032-
* @param settings the settings object.
1073+
* @param settings the settings object.
10331074
* @param forwardToReplicas if true, the new settings will be forwarded to replica indices.
10341075
* @throws AlgoliaException
10351076
*/

algoliasearch/src/test/java/com/algolia/search/saas/IndexTest.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,4 +1031,86 @@ public void doRequestCompleted(JSONObject content, AlgoliaException error) {
10311031
}
10321032
});
10331033
}
1034+
1035+
@Test
1036+
public void searchForFacFacetValues() throws Exception {
1037+
final JSONObject setSettingsTask = index.setSettings(new JSONObject()
1038+
.put("attributesForFaceting", new JSONArray()
1039+
.put("searchable(series)")
1040+
.put("kind"))
1041+
);
1042+
1043+
final JSONObject addObjectsResult = index.addObjects(new JSONArray()
1044+
.put(new JSONObject()
1045+
.put("objectID", "1")
1046+
.put("name", "Snoopy")
1047+
.put("kind", new JSONArray().put("dog").put("animal"))
1048+
.put("born", 1950)
1049+
.put("series", "Peanuts"))
1050+
.put(new JSONObject()
1051+
.put("objectID", "2")
1052+
.put("name", "Woodstock")
1053+
.put("kind", new JSONArray().put("bird").put("animal"))
1054+
.put("born", 1960)
1055+
.put("series", "Peanuts"))
1056+
.put(new JSONObject()
1057+
.put("objectID", "3")
1058+
.put("name", "Charlie Brown")
1059+
.put("kind", new JSONArray().put("human"))
1060+
.put("born", 1950)
1061+
.put("series", "Peanuts"))
1062+
.put(new JSONObject()
1063+
.put("objectID", "4")
1064+
.put("name", "Hobbes")
1065+
.put("kind", new JSONArray().put("tiger").put("animal").put("teddy"))
1066+
.put("born", 1985)
1067+
.put("series", "Calvin & Hobbes"))
1068+
.put(new JSONObject()
1069+
.put("objectID", "5")
1070+
.put("name", "Calvin")
1071+
.put("kind", new JSONArray().put("human"))
1072+
.put("born", 1985)
1073+
.put("series", "Calvin & Hobbes"))
1074+
);
1075+
1076+
index.waitTask(setSettingsTask.getString("taskID"));
1077+
index.waitTask(addObjectsResult.getString("taskID"));
1078+
1079+
index.searchForFacetValues("series", "Hobb", null, new AssertCompletionHandler() {
1080+
@Override
1081+
public void doRequestCompleted(JSONObject content, AlgoliaException error) {
1082+
assertNull("There should be no error", error);
1083+
final JSONArray facetHits = content.optJSONArray("facetHits");
1084+
assertTrue("The response should have facetHits.", facetHits != null);
1085+
try {
1086+
assertEquals("There should be one facet match.", 1, facetHits.length());
1087+
JSONObject result = facetHits.getJSONObject(0);
1088+
assertEquals("The serie should be Calvin & Hobbes.", "Calvin & Hobbes", result.getString("value"));
1089+
assertEquals("Two results should have matched.", 2, result.getInt("count"));
1090+
} catch (JSONException e) {
1091+
fail(e.toString());
1092+
}
1093+
}
1094+
});
1095+
1096+
Query query = new Query()
1097+
.setFacetFilters(new JSONArray().put("kind:animal"))
1098+
.setNumericFilters(new JSONArray().put("born >= 1955"));
1099+
index.searchForFacetValues("series", "Peanutz", query, new AssertCompletionHandler() {
1100+
@Override
1101+
public void doRequestCompleted(JSONObject content, AlgoliaException error) {
1102+
assertNull("There should be no error", error);
1103+
final JSONArray facetHits = content.optJSONArray("facetHits");
1104+
assertTrue("The response should have facetHits.", facetHits != null);
1105+
try {
1106+
assertEquals("There should be one facet match.", 1, facetHits.length());
1107+
JSONObject result = facetHits.getJSONObject(0);
1108+
assertEquals("The serie should be Peanuts.", "Peanuts", result.getString("value"));
1109+
assertEquals("Two results should have matched.", 1, result.getInt("count"));
1110+
} catch (JSONException e) {
1111+
fail(e.getMessage());
1112+
}
1113+
}
1114+
});
1115+
}
10341116
}

0 commit comments

Comments
 (0)