Skip to content

Commit

Permalink
Merge #735
Browse files Browse the repository at this point in the history
735: implement facet search r=curquiza a=the-sinner

# Pull Request

## Related issue
Fixes #635 

## What does this PR do?
- implement facet search

## PR checklist
Please check if your PR fulfills the following requirements:
- [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
- [x] Have you read the contributing guidelines?
- [x] Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!

Co-authored-by: Shalabh Agarwal <shalabhagarwal1024@gmail.com>
Co-authored-by: Clémentine <clementine@meilisearch.com>
  • Loading branch information
3 people authored May 23, 2024
2 parents 1f47bef + 7a332dc commit 49919bd
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,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();
}

0 comments on commit 49919bd

Please sign in to comment.