Skip to content

Commit 7d15329

Browse files
authored
Merge branch 'main' into bump-meilisearch-v1.13
2 parents edd7b9f + dea0a54 commit 7d15329

9 files changed

+349
-118
lines changed

.code-samples.meilisearch.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -742,3 +742,14 @@ update_localized_attribute_settings_1: |-
742742
])
743743
reset_localized_attribute_settings_1: |-
744744
client.index('INDEX_NAME').reset_localized_attributes()
745+
multi_search_federated_1: |-
746+
client.multi_search(
747+
[{"indexUid": "movies", "q": "batman"}, {"indexUid": "comics", "q": "batman"}],
748+
{}
749+
)
750+
get_all_batches_1: |-
751+
client.get_batches()
752+
get_batch_1: |-
753+
client.get_batch(BATCH_UID)
754+
get_similar_post_1: |-
755+
client.index("INDEX_NAME").get_similar_documents({"id": "TARGET_DOCUMENT_ID", "embedder": "default"})

Pipfile.lock

+130-116
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

meilisearch/client.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from meilisearch.errors import MeilisearchError
1717
from meilisearch.index import Index
1818
from meilisearch.models.key import Key, KeysResults
19-
from meilisearch.models.task import Task, TaskInfo, TaskResults
19+
from meilisearch.models.task import Batch, BatchResults, Task, TaskInfo, TaskResults
2020
from meilisearch.task import TaskHandler
2121

2222

@@ -611,6 +611,46 @@ def wait_for_task(
611611
"""
612612
return self.task_handler.wait_for_task(uid, timeout_in_ms, interval_in_ms)
613613

614+
def get_batches(self, parameters: Optional[MutableMapping[str, Any]] = None) -> BatchResults:
615+
"""Get all batches.
616+
617+
Parameters
618+
----------
619+
parameters (optional):
620+
parameters accepted by the get batches route: https://www.meilisearch.com/docs/reference/api/batches#get-batches.
621+
622+
Returns
623+
-------
624+
batch:
625+
BatchResult instance containing limit, from, next and results containing a list of all batches.
626+
627+
Raises
628+
------
629+
MeilisearchApiError
630+
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
631+
"""
632+
return self.task_handler.get_batches(parameters=parameters)
633+
634+
def get_batch(self, uid: int) -> Batch:
635+
"""Get one tasks batch.
636+
637+
Parameters
638+
----------
639+
uid:
640+
Identifier of the batch.
641+
642+
Returns
643+
-------
644+
batch:
645+
Batch instance containing information about the progress of the asynchronous batch.
646+
647+
Raises
648+
------
649+
MeilisearchApiError
650+
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
651+
"""
652+
return self.task_handler.get_batch(uid)
653+
614654
def generate_tenant_token(
615655
self,
616656
api_key_uid: str,

meilisearch/config.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ class Paths:
1414
version = "version"
1515
index = "indexes"
1616
task = "tasks"
17+
batch = "batches"
1718
stat = "stats"
1819
search = "search"
1920
facet_search = "facet-search"
2021
multi_search = "multi-search"
2122
document = "documents"
23+
similar = "similar"
2224
setting = "settings"
2325
ranking_rules = "ranking-rules"
2426
distinct_attribute = "distinct-attribute"

meilisearch/index.py

+24
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,30 @@ def get_documents(
401401
)
402402
return DocumentsResults(response)
403403

404+
def get_similar_documents(self, parameters: Mapping[str, Any]) -> Dict[str, Any]:
405+
"""Get the documents similar to a document.
406+
407+
Parameters
408+
----------
409+
parameters:
410+
parameters accepted by the get similar documents route: https://www.meilisearch.com/docs/reference/api/similar#body
411+
"id" and "embedder" are required.
412+
413+
Returns
414+
-------
415+
results:
416+
Dictionary with hits, offset, limit, processingTimeMs, and id
417+
418+
Raises
419+
------
420+
MeilisearchApiError
421+
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
422+
"""
423+
return self.http.post(
424+
f"{self.config.paths.index}/{self.uid}/{self.config.paths.similar}",
425+
body=parameters,
426+
)
427+
404428
def add_documents(
405429
self,
406430
documents: Sequence[Mapping[str, Any]],

meilisearch/models/task.py

+43
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,46 @@ def __init__(self, resp: Dict[str, Any]) -> None:
113113
self.total: int = resp["total"]
114114
self.from_: int = resp["from"]
115115
self.next_: int = resp["next"]
116+
117+
118+
class Batch(CamelBase):
119+
uid: int
120+
details: Optional[Dict[str, Any]] = None
121+
stats: Optional[Dict[str, Union[int, Dict[str, Any]]]] = None
122+
duration: Optional[str] = None
123+
started_at: Optional[datetime] = None
124+
finished_at: Optional[datetime] = None
125+
progress: Optional[Dict[str, Union[float, List[Dict[str, Any]]]]] = None
126+
127+
if is_pydantic_2():
128+
129+
@pydantic.field_validator("started_at", mode="before") # type: ignore[attr-defined]
130+
@classmethod
131+
def validate_started_at(cls, v: str) -> Optional[datetime]: # pylint: disable=invalid-name
132+
return iso_to_date_time(v)
133+
134+
@pydantic.field_validator("finished_at", mode="before") # type: ignore[attr-defined]
135+
@classmethod
136+
def validate_finished_at(cls, v: str) -> Optional[datetime]: # pylint: disable=invalid-name
137+
return iso_to_date_time(v)
138+
139+
else: # pragma: no cover
140+
141+
@pydantic.validator("started_at", pre=True)
142+
@classmethod
143+
def validate_started_at(cls, v: str) -> Optional[datetime]: # pylint: disable=invalid-name
144+
return iso_to_date_time(v)
145+
146+
@pydantic.validator("finished_at", pre=True)
147+
@classmethod
148+
def validate_finished_at(cls, v: str) -> Optional[datetime]: # pylint: disable=invalid-name
149+
return iso_to_date_time(v)
150+
151+
152+
class BatchResults(CamelBase):
153+
results: List[Batch]
154+
total: int
155+
limit: int
156+
from_: int
157+
# None means last page
158+
next_: Optional[int]

meilisearch/task.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from meilisearch._httprequests import HttpRequests
99
from meilisearch.config import Config
1010
from meilisearch.errors import MeilisearchTimeoutError
11-
from meilisearch.models.task import Task, TaskInfo, TaskResults
11+
from meilisearch.models.task import Batch, BatchResults, Task, TaskInfo, TaskResults
1212

1313

1414
class TaskHandler:
@@ -27,6 +27,53 @@ def __init__(self, config: Config):
2727
self.config = config
2828
self.http = HttpRequests(config)
2929

30+
def get_batches(self, parameters: Optional[MutableMapping[str, Any]] = None) -> BatchResults:
31+
"""Get all task batches.
32+
33+
Parameters
34+
----------
35+
parameters (optional):
36+
parameters accepted by the get batches route: https://www.meilisearch.com/docs/reference/api/batches#get-batches.
37+
38+
Returns
39+
-------
40+
batch:
41+
BatchResults instance contining limit, from, next and results containing a list of all batches.
42+
43+
Raises
44+
------
45+
MeilisearchApiError
46+
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
47+
"""
48+
if parameters is None:
49+
parameters = {}
50+
for param in parameters:
51+
if isinstance(parameters[param], (list, tuple)):
52+
parameters[param] = ",".join(parameters[param])
53+
batches = self.http.get(f"{self.config.paths.batch}?{parse.urlencode(parameters)}")
54+
return BatchResults(**batches)
55+
56+
def get_batch(self, uid: int) -> Batch:
57+
"""Get one tasks batch.
58+
59+
Parameters
60+
----------
61+
uid:
62+
Identifier of the batch.
63+
64+
Returns
65+
-------
66+
task:
67+
Batch instance containing information about the progress of the asynchronous batch.
68+
69+
Raises
70+
------
71+
MeilisearchApiError
72+
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
73+
"""
74+
batch = self.http.get(f"{self.config.paths.batch}/{uid}")
75+
return Batch(**batch)
76+
3077
def get_tasks(self, parameters: Optional[MutableMapping[str, Any]] = None) -> TaskResults:
3178
"""Get all tasks.
3279

tests/client/test_client_task_meilisearch.py

+24
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,27 @@ def test_get_tasks_in_reverse(client):
165165
reverse_tasks = client.get_tasks({"reverse": "true"})
166166

167167
assert reverse_tasks.results[0] == tasks.results[-1]
168+
169+
170+
def test_get_batches_default(client):
171+
"""Tests getting the batches."""
172+
batches = client.get_batches()
173+
assert len(batches.results) >= 1
174+
175+
176+
@pytest.mark.usefixtures("create_tasks")
177+
def test_get_batches_with_parameters(client):
178+
"""Tests getting batches with a parameter (empty or otherwise)."""
179+
rev_batches = client.get_batches({"reverse": "true"})
180+
batches = client.get_batches({})
181+
182+
assert len(batches.results) > 1
183+
assert rev_batches.results[0].uid == batches.results[-1].uid
184+
185+
186+
def test_get_batch(client):
187+
"""Tests getting the details of a batch."""
188+
batches = client.get_batches({"limit": 1})
189+
uid = batches.results[0].uid
190+
batch = client.get_batch(uid)
191+
assert batch.uid == uid

tests/index/test_index_document_meilisearch.py

+26
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,32 @@ def test_get_documents_filter_with_fields(index_with_documents):
266266
assert next(iter(genres)) == "action"
267267

268268

269+
@pytest.mark.usefixtures("enable_vector_search")
270+
def test_get_similar_documents(empty_index):
271+
index = empty_index()
272+
index.update_embedders({"manual": {"source": "userProvided", "dimensions": 3}})
273+
274+
hp3 = {
275+
"id": 1,
276+
"title": "Harry Potter and the Prisoner of Azkaban",
277+
"_vectors": {"manual": [0.8, 0.8, 0.8]},
278+
}
279+
hp4 = {
280+
"id": 2,
281+
"title": "Harry Potter and the Goblet of Fire",
282+
"_vectors": {"manual": [0.7, 0.7, 0.9]},
283+
}
284+
lotr = {"id": 3, "title": "The Lord of the Rings", "_vectors": {"manual": [0.6, 0.5, 0.2]}}
285+
286+
addition = index.add_documents([hp3, hp4, lotr])
287+
index.wait_for_task(addition.task_uid)
288+
289+
similars = index.get_similar_documents({"id": hp4["id"], "embedder": "manual"})
290+
291+
assert similars["hits"][0]["id"] == hp3["id"]
292+
assert similars["hits"][1]["id"] == lotr["id"]
293+
294+
269295
def test_update_documents(index_with_documents, small_movies):
270296
"""Tests updating a single document and a set of documents."""
271297
index = index_with_documents()

0 commit comments

Comments
 (0)