Skip to content

Commit 7f4146d

Browse files
meili-bors[bot]cyprxsanders41
authored
Merge #839
839: Support search in facet values r=sanders41 a=cyprx # Pull Request ## Related issue Fixes #830 ## What does this PR do? - Add function `facet_search` which performs search in facet values - Add code samples - Add integration tests ## 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: cyprx <[email protected]> Co-authored-by: Paul Sanders <[email protected]>
2 parents 81e61ea + 565bfd2 commit 7f4146d

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

.code-samples.meilisearch.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,3 +695,9 @@ date_guide_sort_1: |-
695695
client.index('games').search('', {
696696
'sort': ['release_timestamp:desc']
697697
})
698+
facet_search_1: |-
699+
client.index('books').facet_search('fiction', 'genres', {
700+
'filter': 'rating > 3'
701+
})
702+
facet_search_3: |-
703+
client.index('books').facet_search('c', 'genres')

meilisearch/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Paths:
1616
task = "tasks"
1717
stat = "stats"
1818
search = "search"
19+
facet_search = "facet-search"
1920
multi_search = "multi-search"
2021
document = "documents"
2122
setting = "settings"

meilisearch/index.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,39 @@ def search(self, query: str, opt_params: Optional[Dict[str, Any]] = None) -> Dic
279279
body=body,
280280
)
281281

282+
@version_error_hint_message
283+
def facet_search(
284+
self,
285+
facet_name: str,
286+
facet_query: Optional[str] = None,
287+
opt_params: Optional[Dict[str, Any]] = None,
288+
) -> Dict[str, Any]:
289+
"""
290+
Perform a facet search based on the given facet query and facet name.
291+
292+
Parameters
293+
----------
294+
facet_name:
295+
String containing the name of the facet on which the search is performed.
296+
facet_query (optional):
297+
String containing the searched words
298+
opt_params (optional):
299+
Dictionary containing optional query parameters.
300+
301+
Returns
302+
-------
303+
results:
304+
Dictionary with facetHits, processingTime and initial facet query
305+
306+
"""
307+
if opt_params is None:
308+
opt_params = {}
309+
body = {"facetName": facet_name, "facetQuery": facet_query, **opt_params}
310+
return self.http.post(
311+
f"{self.config.paths.index}/{self.uid}/{self.config.paths.facet_search}",
312+
body=body,
313+
)
314+
282315
def get_document(
283316
self, document_id: Union[str, int], parameters: Optional[Dict[str, Any]] = None
284317
) -> Document:

tests/conftest.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ def index_maker(index_uid=common.INDEX_UID, documents=small_movies):
140140
return index_maker
141141

142142

143+
@fixture(scope="function")
144+
def index_with_documents_and_facets(empty_index, small_movies):
145+
def index_maker(index_uid=common.INDEX_UID, documents=small_movies):
146+
index = empty_index(index_uid)
147+
task_1 = index.update_filterable_attributes(["genre"])
148+
index.wait_for_task(task_1.task_uid)
149+
task_2 = index.add_documents(documents)
150+
index.wait_for_task(task_2.task_uid)
151+
return index
152+
153+
return index_maker
154+
155+
143156
@fixture(scope="function")
144157
def test_key(client):
145158
key_info = {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# pylint: disable=invalid-name
2+
3+
4+
def test_basic_facet_search(index_with_documents_and_facets):
5+
"""Tests facet search with a simple query."""
6+
response = index_with_documents_and_facets().facet_search("genre", "cartoon")
7+
assert isinstance(response, dict)
8+
assert response["facetHits"][0]["count"] == 3
9+
assert response["facetQuery"] == "cartoon"
10+
11+
12+
def test_facet_search_with_empty_query(index_with_documents_and_facets):
13+
"""Tests facet search with a empty query."""
14+
response = index_with_documents_and_facets().facet_search("genre")
15+
assert isinstance(response, dict)
16+
assert len(response["facetHits"]) == 4
17+
assert response["facetHits"][0]["value"] == "action"
18+
assert response["facetHits"][1]["count"] == 3
19+
assert response["facetQuery"] is None
20+
21+
22+
def test_facet_search_with_q(index_with_documents_and_facets):
23+
"""Tests facet search with a keyword query q."""
24+
response = index_with_documents_and_facets().facet_search("genre", "cartoon", {"q": "dragon"})
25+
assert isinstance(response, dict)
26+
assert response["facetHits"][0]["count"] == 1
27+
assert response["facetQuery"] == "cartoon"
28+
29+
30+
def test_facet_search_with_filter(index_with_documents_and_facets):
31+
"""Tests facet search with a filter."""
32+
index = index_with_documents_and_facets()
33+
task = index.update_filterable_attributes(["genre", "release_date"])
34+
index.wait_for_task(task.task_uid)
35+
response = index.facet_search("genre", "cartoon", {"filter": "release_date > 1149728400"})
36+
assert isinstance(response, dict)
37+
assert response["facetHits"][0]["count"] == 2
38+
assert response["facetQuery"] == "cartoon"
39+
40+
41+
def test_facet_search_with_attributes_to_search_on(index_with_documents_and_facets):
42+
"""Tests facet search with optional parameter attributesToSearchOn."""
43+
response = index_with_documents_and_facets().facet_search(
44+
"genre", "action", {"q": "aquaman", "attributesToSearchOn": ["overview"]}
45+
)
46+
assert isinstance(response, dict)
47+
assert len(response["facetHits"]) == 0
48+
assert response["facetQuery"] == "action"

0 commit comments

Comments
 (0)