From 1c5b0a177984a35e5ca5288cf57b335a85348b5a Mon Sep 17 00:00:00 2001 From: Thiago Colares Date: Fri, 24 Jan 2025 16:06:41 -0500 Subject: [PATCH 1/4] Handle body as boolean for POST HTTP requests Required for facet-search settings and possibly others. --- meilisearch/_httprequests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meilisearch/_httprequests.py b/meilisearch/_httprequests.py index 6db5eb96..fa4ccda7 100644 --- a/meilisearch/_httprequests.py +++ b/meilisearch/_httprequests.py @@ -33,6 +33,7 @@ def send_request( Mapping[str, Any], Sequence[Mapping[str, Any]], List[str], + bool, bytes, str, int, @@ -64,7 +65,7 @@ def send_request( serialize_body = isinstance(body, dict) or body data = ( json.dumps(body, cls=serializer) - if serialize_body + if isinstance(body, bool) or serialize_body else "" if body == "" else "null" ) @@ -111,6 +112,7 @@ def put( Mapping[str, Any], Sequence[Mapping[str, Any]], List[str], + bool, bytes, str, int, From 4bc697d3a0d157b003d2160cf31b1ace39b6cc36 Mon Sep 17 00:00:00 2001 From: Thiago Colares Date: Fri, 24 Jan 2025 13:45:50 -0500 Subject: [PATCH 2/4] Add methods for Facet Search settings requests --- .code-samples.meilisearch.yaml | 6 +++ meilisearch/index.py | 52 +++++++++++++++++++- tests/settings/test_settings_facet_search.py | 38 ++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 tests/settings/test_settings_facet_search.py diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index e7eb46ce..a6895bd4 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -634,6 +634,12 @@ update_pagination_settings_1: |- client.index('books').update_pagination_settings({'maxTotalHits': 100}) reset_pagination_settings_1: |- client.index('books').reset_pagination_settings() +get_facet_search_settings_1: |- + client.index('books').get_facet_search_settings() +update_facet_search_settings_1: |- + client.index('books').update_facet_search_settings(False) +reset_facet_search_settings_1: |- + client.index('books').reset_facet_search_settings() get_faceting_settings_1: |- client.index('books').get_faceting_settings() update_faceting_settings_1: |- diff --git a/meilisearch/index.py b/meilisearch/index.py index 7504e722..5c4967c5 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -1628,6 +1628,57 @@ def reset_pagination_settings(self) -> TaskInfo: return TaskInfo(**task) + def get_facet_search_settings(self) -> bool: + """Get the facet search settings of an index. + + Returns + ------- + bool: + True if facet search is enabled, False if disabled. + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + """ + + return self.http.get(self.__settings_url_for(self.config.paths.facet_search)) + + def update_facet_search_settings(self, body: Union[bool, None]) -> TaskInfo: + """Update the facet search settings of the index. + + Parameters + ---------- + body: bool + True to enable facet search, False to disable it. + + Returns + ------- + task_info: + TaskInfo instance containing information about a task to track the progress of an asynchronous process. + https://www.meilisearch.com/docs/reference/api/tasks#get-one-task + + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + """ + task = self.http.put(self.__settings_url_for(self.config.paths.facet_search), body=body) + + return TaskInfo(**task) + + def reset_facet_search_settings(self) -> TaskInfo: + """Reset facet search settings of the index to default values. + + Returns + ------- + task_info: + TaskInfo instance containing information about a task to track the progress of an asynchronous process. + https://www.meilisearch.com/docs/reference/api/tasks + """ + task = self.http.delete(self.__settings_url_for(self.config.paths.facet_search)) + + return TaskInfo(**task) + def get_faceting_settings(self) -> Faceting: """Get the faceting settings of an index. @@ -1641,7 +1692,6 @@ def get_faceting_settings(self) -> Faceting: MeilisearchApiError An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors """ - faceting = self.http.get(self.__settings_url_for(self.config.paths.faceting)) return Faceting(**faceting) diff --git a/tests/settings/test_settings_facet_search.py b/tests/settings/test_settings_facet_search.py new file mode 100644 index 00000000..00ab6040 --- /dev/null +++ b/tests/settings/test_settings_facet_search.py @@ -0,0 +1,38 @@ +DEFAULT_FACET_SEARCH_SETTINGS_STATUS = True +ENABLED_FACET_SEARCH_SETTINGS_STATUS = True +DISABLED_FACET_SEARCH_SETTINGS_STATUS = False + + +def test_get_facet_search_settings(empty_index): + response = empty_index().get_facet_search_settings() + + assert DEFAULT_FACET_SEARCH_SETTINGS_STATUS == response + + +def test_update_facet_search_settings(empty_index): + index = empty_index() + + response = index.update_facet_search_settings(DISABLED_FACET_SEARCH_SETTINGS_STATUS) + index.wait_for_task(response.task_uid) + response = index.get_facet_search_settings() + assert DISABLED_FACET_SEARCH_SETTINGS_STATUS == response + + response = index.update_facet_search_settings(ENABLED_FACET_SEARCH_SETTINGS_STATUS) + index.wait_for_task(response.task_uid) + response = index.get_facet_search_settings() + assert ENABLED_FACET_SEARCH_SETTINGS_STATUS == response + + +def test_reset_facet_search_settings(empty_index): + index = empty_index() + + response = index.update_facet_search_settings(DISABLED_FACET_SEARCH_SETTINGS_STATUS) + index.wait_for_task(response.task_uid) + response = index.get_facet_search_settings() + assert DISABLED_FACET_SEARCH_SETTINGS_STATUS == response + assert DEFAULT_FACET_SEARCH_SETTINGS_STATUS != response + + response = index.reset_facet_search_settings() + index.wait_for_task(response.task_uid) + response = index.get_facet_search_settings() + assert DEFAULT_FACET_SEARCH_SETTINGS_STATUS == response From cdbbdc1d982d21e7e9b8c90d1e5f74bbd6d939c6 Mon Sep 17 00:00:00 2001 From: Thiago Colares Date: Sat, 25 Jan 2025 07:41:52 -0500 Subject: [PATCH 3/4] Add methods for Prefix Search settings requests --- .code-samples.meilisearch.yaml | 6 +++ meilisearch/_httprequests.py | 3 +- meilisearch/config.py | 1 + meilisearch/index.py | 53 +++++++++++++++++++ meilisearch/models/index.py | 12 +++++ tests/settings/test_settings_prefix_search.py | 39 ++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/settings/test_settings_prefix_search.py diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index a6895bd4..166449e1 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -730,6 +730,12 @@ update_search_cutoff_1: |- client.index('movies').update_search_cutoff_ms(150) reset_search_cutoff_1: |- client.index('movies').reset_search_cutoff_ms() +get_prefix_search_settings_1: |- + client.index('books').get_prefix_search() +update_prefix_search_settings_1: |- + client.index('books').update_prefix_search(PrefixSearch.DISABLED) +reset_prefix_search_settings_1: |- + client.index('books').reset_prefix_search() get_proximity_precision_settings_1: |- client.index('books').get_proximity_precision() update_proximity_precision_settings_1: |- diff --git a/meilisearch/_httprequests.py b/meilisearch/_httprequests.py index fa4ccda7..92a69079 100644 --- a/meilisearch/_httprequests.py +++ b/meilisearch/_httprequests.py @@ -12,7 +12,7 @@ MeilisearchCommunicationError, MeilisearchTimeoutError, ) -from meilisearch.models.index import ProximityPrecision +from meilisearch.models.index import PrefixSearch, ProximityPrecision from meilisearch.version import qualified_version @@ -116,6 +116,7 @@ def put( bytes, str, int, + PrefixSearch, ProximityPrecision, ] ] = None, diff --git a/meilisearch/config.py b/meilisearch/config.py index 1d40a694..d0f9ff48 100644 --- a/meilisearch/config.py +++ b/meilisearch/config.py @@ -42,6 +42,7 @@ class Paths: swap = "swap-indexes" embedders = "embedders" search_cutoff_ms = "search-cutoff-ms" + prefix_search = "prefix-search" proximity_precision = "proximity-precision" localized_attributes = "localized-attributes" diff --git a/meilisearch/index.py b/meilisearch/index.py index 5c4967c5..f2cbedb4 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -32,6 +32,7 @@ LocalizedAttributes, OpenAiEmbedder, Pagination, + PrefixSearch, ProximityPrecision, TypoTolerance, UserProvidedEmbedder, @@ -2056,6 +2057,58 @@ def reset_search_cutoff_ms(self) -> TaskInfo: return TaskInfo(**task) + # PREFIX SEARCH + + def get_prefix_search(self) -> PrefixSearch: + """Get the prefix search settings of an index. + + Returns + ------- + settings: + The prefix search settings of the index. + + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + """ + prefix_search = self.http.get(self.__settings_url_for(self.config.paths.prefix_search)) + + return PrefixSearch[to_snake(prefix_search).upper()] + + def update_prefix_search(self, body: Union[PrefixSearch, None]) -> TaskInfo: + """Update the prefix search settings of the index. + + Parameters + ---------- + body: + Prefix search settings + + Returns + ------- + task_info: + TaskInfo instance containing information about a task to track the progress of an asynchronous process. + https://www.meilisearch.com/docs/reference/api/tasks + """ + task = self.http.put(self.__settings_url_for(self.config.paths.prefix_search), body) + + return TaskInfo(**task) + + def reset_prefix_search(self) -> TaskInfo: + """Reset the prefix search settings of the index + + Returns + ------- + task_info: + TaskInfo instance containing information about a task to track the progress of an asynchronous process. + https://www.meilisearch.com/docs/reference/api/tasks + """ + task = self.http.delete( + self.__settings_url_for(self.config.paths.prefix_search), + ) + + return TaskInfo(**task) + # PROXIMITY PRECISION SETTINGS def get_proximity_precision(self) -> ProximityPrecision: diff --git a/meilisearch/models/index.py b/meilisearch/models/index.py index bee521ed..7a5e9f8b 100644 --- a/meilisearch/models/index.py +++ b/meilisearch/models/index.py @@ -49,6 +49,18 @@ class TypoTolerance(CamelBase): min_word_size_for_typos: Optional[MinWordSizeForTypos] = None +class PrefixSearch(str, Enum): + INDEXING_TIME = "indexingTime" + """ + Calculate prefix search during indexing. This is the default behavior. + """ + + DISABLED = "disabled" + """ + Do not calculate prefix search. May speed up indexing, but will severely impact search result relevancy. + """ + + class ProximityPrecision(str, Enum): BY_WORD = "byWord" BY_ATTRIBUTE = "byAttribute" diff --git a/tests/settings/test_settings_prefix_search.py b/tests/settings/test_settings_prefix_search.py new file mode 100644 index 00000000..6a0a9766 --- /dev/null +++ b/tests/settings/test_settings_prefix_search.py @@ -0,0 +1,39 @@ +from meilisearch.models.index import PrefixSearch + + +DEFAULT_PREFIX_SEARCH_SETTINGS = PrefixSearch.INDEXING_TIME + + +def test_get_prefix_search(empty_index): + response = empty_index().get_prefix_search() + + assert DEFAULT_PREFIX_SEARCH_SETTINGS == response + + +def test_update_prefix_search(empty_index): + index = empty_index() + + response = index.update_prefix_search(PrefixSearch.DISABLED) + index.wait_for_task(response.task_uid) + response = index.get_prefix_search() + assert PrefixSearch.DISABLED == response + + response = index.update_prefix_search(PrefixSearch.INDEXING_TIME) + index.wait_for_task(response.task_uid) + response = index.get_prefix_search() + assert PrefixSearch.INDEXING_TIME == response + + +def test_reset_prefix_search(empty_index): + index = empty_index() + + response = index.update_prefix_search(PrefixSearch.DISABLED) + index.wait_for_task(response.task_uid) + response = index.get_prefix_search() + assert PrefixSearch.DISABLED == response + assert DEFAULT_PREFIX_SEARCH_SETTINGS != response + + response = index.reset_prefix_search() + index.wait_for_task(response.task_uid) + response = index.get_prefix_search() + assert DEFAULT_PREFIX_SEARCH_SETTINGS == response From de723faab35b4d2174321a1d3301363a28c9df94 Mon Sep 17 00:00:00 2001 From: Thiago Colares Date: Thu, 30 Jan 2025 08:48:56 -0500 Subject: [PATCH 4/4] Fix lint errors --- meilisearch/index.py | 2 +- tests/settings/test_settings_prefix_search.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/meilisearch/index.py b/meilisearch/index.py index f2cbedb4..35bd8a31 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -1677,7 +1677,7 @@ def reset_facet_search_settings(self) -> TaskInfo: https://www.meilisearch.com/docs/reference/api/tasks """ task = self.http.delete(self.__settings_url_for(self.config.paths.facet_search)) - + return TaskInfo(**task) def get_faceting_settings(self) -> Faceting: diff --git a/tests/settings/test_settings_prefix_search.py b/tests/settings/test_settings_prefix_search.py index 6a0a9766..eb1efa23 100644 --- a/tests/settings/test_settings_prefix_search.py +++ b/tests/settings/test_settings_prefix_search.py @@ -1,6 +1,5 @@ from meilisearch.models.index import PrefixSearch - DEFAULT_PREFIX_SEARCH_SETTINGS = PrefixSearch.INDEXING_TIME