diff --git a/meilisearch/index.py b/meilisearch/index.py index 6c65874a..814f6b3d 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -333,7 +333,12 @@ def get_stats(self) -> IndexStats: return IndexStats(**stats) @version_error_hint_message - def search(self, query: str, opt_params: Optional[Mapping[str, Any]] = None) -> Dict[str, Any]: + def search( + self, + query: str, + opt_params: Optional[Mapping[str, Any]] = None, + personalize: Optional[Dict[str, Any]] = None, + ) -> Dict[str, Any]: """Search in the index. https://www.meilisearch.com/docs/reference/api/search @@ -353,6 +358,9 @@ def search(self, query: str, opt_params: Optional[Mapping[str, Any]] = None) -> - offset: Number of documents to skip - showPerformanceDetails: If true, the response includes a performanceDetails object (raw data; fields may change in future API versions) + personalize (optional): + Dict with a 'userContext' string to personalize the search results + (experimental; requires Meilisearch >= v1.47). Returns ------- @@ -369,6 +377,8 @@ def search(self, query: str, opt_params: Optional[Mapping[str, Any]] = None) -> opt_params = {} body = {"q": query, **opt_params} + if personalize is not None: + body["personalize"] = personalize return self.http.post( f"{self.config.paths.index}/{self.uid}/{self.config.paths.search}", diff --git a/tests/index/test_index_search_meilisearch.py b/tests/index/test_index_search_meilisearch.py index 1bd6adb0..a6436a0f 100644 --- a/tests/index/test_index_search_meilisearch.py +++ b/tests/index/test_index_search_meilisearch.py @@ -1,6 +1,7 @@ # pylint: disable=invalid-name from collections import Counter +from unittest.mock import patch import pytest @@ -14,6 +15,17 @@ def test_basic_search(index_with_documents): assert "hitsPerPage" is not response +def test_search_serializes_personalize(client): + """The `personalize` parameter must be forwarded in the search request body.""" + index = client.index("books") + with patch.object(index.http, "post", return_value={"hits": []}) as mock_post: + index.search("prince", personalize={"userContext": "user-123"}) + + _, kwargs = mock_post.call_args + assert kwargs["body"]["q"] == "prince" + assert kwargs["body"]["personalize"] == {"userContext": "user-123"} + + def test_basic_search_with_empty_params(index_with_documents): """Tests search with a simple query and empty params.""" response = index_with_documents().search("How to Train Your Dragon", {})