diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 836fbdf6..87f6f8c2 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -629,6 +629,12 @@ update_sortable_attributes_1: |- client.index("books").updateSortableAttributesSettings(new String[] {"price", "author"}); reset_sortable_attributes_1: |- client.index("books").resetSortableAttributesSettings(); +facet_search_1: |- + FacetSearchRequest fsr = FacetSearchRequest.builder().facetName("genres").facetQuery("fiction").filter(new String[]{"rating > 3"}).build(); + client.index("books").facetSearch(fsr); +facet_search_3: |- + FacetSearchRequest fsr = FacetSearchRequest.builder().facetName("genres").facetQuery("c").build(); + client.index("books").facetSearch(fsr); search_parameter_guide_sort_1: |- SearchRequest searchRequest = SearchRequest.builder().q("science fiction").sort(new String[] {"price:asc"}).build(); client.index("search_parameter_guide_sort_1").search(searchRequest); diff --git a/src/main/java/com/meilisearch/sdk/FacetSearch.java b/src/main/java/com/meilisearch/sdk/FacetSearch.java new file mode 100644 index 00000000..c1774bb7 --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/FacetSearch.java @@ -0,0 +1,43 @@ +package com.meilisearch.sdk; + +import com.meilisearch.sdk.exceptions.MeilisearchException; +import com.meilisearch.sdk.model.FacetSearchResult; +import com.meilisearch.sdk.model.FacetSearchable; + +/** + * Class used for performing facet searching on Meilisearch indexes + * + * @see API specification + */ +public class FacetSearch { + private final HttpClient httpClient; + + /** + * Constructor for the Meilisearch Facet Search object + * + * @param config Meilisearch configuration + */ + protected FacetSearch(Config config) { + httpClient = config.httpClient; + } + + /** + * Performs a facet search on a given index with a given query + * + * @param uid Index identifier + * @param fsr FacetSearchRequest to search on index + * @return search results, as raw data + * @throws MeilisearchException Search Exception or Client Error + */ + String rawSearch(String uid, FacetSearchRequest fsr) throws MeilisearchException { + String requestQuery = "/indexes/" + uid + "/facet-search"; + if (fsr.getFacetName() == null) { + throw new MeilisearchException("Facet name is required for a facet search"); + } + return httpClient.post(requestQuery, fsr.toString(), String.class); + } + + FacetSearchable facetSearch(String uid, FacetSearchRequest fsr) throws MeilisearchException { + return httpClient.jsonHandler.decode(rawSearch(uid, fsr), FacetSearchResult.class); + } +} diff --git a/src/main/java/com/meilisearch/sdk/FacetSearchRequest.java b/src/main/java/com/meilisearch/sdk/FacetSearchRequest.java new file mode 100644 index 00000000..c9955586 --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/FacetSearchRequest.java @@ -0,0 +1,76 @@ +package com.meilisearch.sdk; + +import com.meilisearch.sdk.model.MatchingStrategy; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.json.JSONObject; + +/** Facet search request query string builder */ +@Builder +@AllArgsConstructor(access = AccessLevel.PACKAGE) +@NoArgsConstructor(access = AccessLevel.PACKAGE) +@Getter +@Setter +@Accessors(chain = true) +public class FacetSearchRequest { + private String facetName; + private String facetQuery; + private String q; + private MatchingStrategy matchingStrategy; + private String[] attributesToSearchOn; + private String[] filter; + private String[][] filterArray; + + /** + * Constructor for FacetSearchRequest for building facet search queries with the default values: + * facetQuery: null, query: null, matchingStrategy: null, attributesToSearchOn: null, filter: + * null + * + * @param facetName FacetName String + */ + public FacetSearchRequest(String facetName) { + this(); + this.facetName = facetName; + } + + /** + * Method to set the Query String + * + *

This method is an alias of setQ() + * + * @param q Query String + * @return SearchRequest + */ + public FacetSearchRequest setQuery(String q) { + return setQ(q); + } + + /** + * Method that returns the JSON String of the SearchRequest + * + * @return JSON String of the SearchRequest query + */ + @Override + public String toString() { + JSONObject jsonObject = + new JSONObject() + .put("facetName", this.facetName) + .put("facetQuery", this.facetQuery) + .put("q", this.q) + .put( + "matchingStrategy", + this.matchingStrategy == null + ? null + : this.matchingStrategy.toString()) + .putOpt("attributesToSearchOn", this.attributesToSearchOn) + .putOpt("filter", this.filter) + .putOpt("filter", this.filterArray); + + return jsonObject.toString(); + } +} diff --git a/src/main/java/com/meilisearch/sdk/Index.java b/src/main/java/com/meilisearch/sdk/Index.java index cdf415ff..f7c557b0 100644 --- a/src/main/java/com/meilisearch/sdk/Index.java +++ b/src/main/java/com/meilisearch/sdk/Index.java @@ -1,7 +1,21 @@ package com.meilisearch.sdk; import com.meilisearch.sdk.exceptions.MeilisearchException; -import com.meilisearch.sdk.model.*; +import com.meilisearch.sdk.model.DocumentQuery; +import com.meilisearch.sdk.model.DocumentsQuery; +import com.meilisearch.sdk.model.FacetSearchable; +import com.meilisearch.sdk.model.Faceting; +import com.meilisearch.sdk.model.IndexStats; +import com.meilisearch.sdk.model.Pagination; +import com.meilisearch.sdk.model.Results; +import com.meilisearch.sdk.model.SearchResult; +import com.meilisearch.sdk.model.Searchable; +import com.meilisearch.sdk.model.Settings; +import com.meilisearch.sdk.model.Task; +import com.meilisearch.sdk.model.TaskInfo; +import com.meilisearch.sdk.model.TasksQuery; +import com.meilisearch.sdk.model.TasksResults; +import com.meilisearch.sdk.model.TypoTolerance; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -23,6 +37,7 @@ public class Index implements Serializable { @ToString.Exclude protected transient Documents documents; @ToString.Exclude protected transient TasksHandler tasksHandler; @ToString.Exclude protected transient Search search; + @ToString.Exclude protected transient FacetSearch facetSearch; @ToString.Exclude protected transient SettingsHandler settingsHandler; @ToString.Exclude protected transient InstanceHandler instanceHandler; @@ -36,6 +51,7 @@ void setConfig(Config config) { this.documents = new Documents(config); this.tasksHandler = new TasksHandler(config); this.search = new Search(config); + this.facetSearch = new FacetSearch(config); this.settingsHandler = new SettingsHandler(config); this.instanceHandler = new InstanceHandler(config); } @@ -411,6 +427,32 @@ public Searchable search(SearchRequest searchRequest) throws MeilisearchExceptio return this.search.search(this.uid, searchRequest); } + /** + * Performs a Facet Search in the index + * + *

Ensure that FacetName is set in the FacetSearchRequest and note that facet search requires + * attributes to the filterableAttributes list. + * + * @param facetSearchRequest FacetSearchRequest FacetSearchRequest + * @return Meilisearch API response + * @throws MeilisearchException if an error occurs + * @see API + * specification + * @see Index#getFilterableAttributesSettings() getFilterableAttributesSettings + * @see Index#updateFilterableAttributesSettings(String[]) updateFilterableAttributesSettings + * @since 1.3 + */ + public FacetSearchable facetSearch(FacetSearchRequest facetSearchRequest) + throws MeilisearchException { + return this.facetSearch.facetSearch(this.uid, facetSearchRequest); + } + + public String rawFacetSearch(FacetSearchRequest facetSearchRequest) + throws MeilisearchException { + return this.facetSearch.rawSearch(this.uid, facetSearchRequest); + } + public String rawSearch(String query) throws MeilisearchException { return this.search.rawSearch(this.uid, query); } diff --git a/src/main/java/com/meilisearch/sdk/model/FacetSearchResult.java b/src/main/java/com/meilisearch/sdk/model/FacetSearchResult.java new file mode 100644 index 00000000..53f2b1dd --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/model/FacetSearchResult.java @@ -0,0 +1,22 @@ +package com.meilisearch.sdk.model; + +import java.util.ArrayList; +import java.util.HashMap; +import lombok.Getter; +import lombok.ToString; + +/** + * Meilisearch facet search response data structure + * + * @see API + * specification + */ +@Getter +@ToString +public class FacetSearchResult implements FacetSearchable { + ArrayList> facetHits; + int processingTimeMs; + String facetQuery; + + public FacetSearchResult() {} +} diff --git a/src/main/java/com/meilisearch/sdk/model/FacetSearchable.java b/src/main/java/com/meilisearch/sdk/model/FacetSearchable.java new file mode 100644 index 00000000..0f0ea2d3 --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/model/FacetSearchable.java @@ -0,0 +1,17 @@ +package com.meilisearch.sdk.model; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Meilisearch facet search response data structure + * + * @see API specification + */ +public interface FacetSearchable { + ArrayList> getFacetHits(); + + int getProcessingTimeMs(); + + String getFacetQuery(); +}