Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add facet search support #735

Merged
merged 2 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/com/meilisearch/sdk/FacetSearch.java
Original file line number Diff line number Diff line change
@@ -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 <a href="https://www.meilisearch.com/docs/reference/api/facet_search">API specification</a>
*/
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);
}
}
76 changes: 76 additions & 0 deletions src/main/java/com/meilisearch/sdk/FacetSearchRequest.java
Original file line number Diff line number Diff line change
@@ -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
*
* <p>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();
}
}
44 changes: 43 additions & 1 deletion src/main/java/com/meilisearch/sdk/Index.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand All @@ -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);
}
Expand Down Expand Up @@ -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
*
* <p>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 <a
* href="https://www.meilisearch.com/docs/reference/api/facet_search#perform-a-facet-search">API
* specification</a>
* @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);
}
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/meilisearch/sdk/model/FacetSearchResult.java
Original file line number Diff line number Diff line change
@@ -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 <a href="https://www.meilisearch.com/docs/reference/api/facet_search#response">API
* specification</a>
*/
@Getter
@ToString
public class FacetSearchResult implements FacetSearchable {
ArrayList<HashMap<String, Object>> facetHits;
int processingTimeMs;
String facetQuery;

public FacetSearchResult() {}
}
17 changes: 17 additions & 0 deletions src/main/java/com/meilisearch/sdk/model/FacetSearchable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.meilisearch.sdk.model;

import java.util.ArrayList;
import java.util.HashMap;

/**
* Meilisearch facet search response data structure
*
* @see <a href="https://www.meilisearch.com/docs/reference/api/facet_search">API specification</a>
*/
public interface FacetSearchable {
ArrayList<HashMap<String, Object>> getFacetHits();

int getProcessingTimeMs();

String getFacetQuery();
}
Loading