Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,9 @@ update_sortable_attributes_1: |-
reset_sortable_attributes_1: |-
client.index('books').reset_sortable_attributes()
get_index_stats_1: |-
client.index('movies').get_stats()
client.index('movies').get_stats(show_internal_database_sizes=True, size_format='human')
get_indexes_stats_1: |-
client.get_all_stats()
client.get_all_stats(show_internal_database_sizes=True, size_format='human')
get_health_1: |-
client.health()
get_version_1: |-
Expand Down
30 changes: 28 additions & 2 deletions meilisearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
MeilisearchError,
)
from meilisearch.index import Index
from meilisearch.models.index import SizeFormat
from meilisearch.models.key import Key, KeysResults
from meilisearch.models.task import Batch, BatchResults, Task, TaskInfo, TaskResults
from meilisearch.models.webhook import Webhook, WebhooksResults
Expand Down Expand Up @@ -322,12 +323,26 @@ def update_documents_by_function(
body=dict(queries),
)

def get_all_stats(self) -> Dict[str, Any]:
def get_all_stats(
self,
*,
show_internal_database_sizes: Optional[bool] = None,
size_format: Optional[Union[SizeFormat, str]] = None,
) -> Dict[str, Any]:
"""Get all stats of Meilisearch

Get information about database size and all indexes
https://www.meilisearch.com/docs/reference/api/stats

Parameters
----------
show_internal_database_sizes (optional):
When true, index stat objects contain an additional internalDatabaseSizes key
with the size of each internal database. Defaults to false.
size_format (optional):
When set to "human", database sizes are returned as strings with units (e.g. "1.5 GiB").
When set to "raw" or omitted, sizes are returned as numbers in bytes.

Returns
-------
stats:
Expand All @@ -338,7 +353,18 @@ def get_all_stats(self) -> Dict[str, Any]:
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.config.paths.stat)
params: Dict[str, Any] = {}
if show_internal_database_sizes is not None:
params["showInternalDatabaseSizes"] = str(show_internal_database_sizes).lower()
if size_format is not None:
params["sizeFormat"] = (
size_format.value if isinstance(size_format, SizeFormat) else size_format
)

path = self.config.paths.stat
if params:
path = f"{path}?{parse.urlencode(params)}"
return self.http.get(path)

def health(self) -> Dict[str, str]:
"""Get health of the Meilisearch server.
Expand Down
30 changes: 28 additions & 2 deletions meilisearch/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
Pagination,
PrefixSearch,
ProximityPrecision,
SizeFormat,
TypoTolerance,
)
from meilisearch.models.task import Task, TaskInfo, TaskResults
Expand Down Expand Up @@ -313,12 +314,26 @@ def wait_for_task(
"""
return self.task_handler.wait_for_task(uid, timeout_in_ms, interval_in_ms)

def get_stats(self) -> IndexStats:
def get_stats(
self,
*,
show_internal_database_sizes: Optional[bool] = None,
size_format: Optional[Union[SizeFormat, str]] = None,
) -> IndexStats:
"""Get stats of the index.

Get information about the number of documents, field frequencies, ...
https://www.meilisearch.com/docs/reference/api/stats

Parameters
----------
show_internal_database_sizes (optional):
When true, the response contains an additional internalDatabaseSizes key
with the size of each internal database. Defaults to false.
size_format (optional):
When set to "human", database sizes are returned as strings with units (e.g. "1.5 GiB").
When set to "raw" or omitted, sizes are returned as numbers in bytes.

Returns
-------
stats:
Expand All @@ -329,7 +344,18 @@ def get_stats(self) -> IndexStats:
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
"""
stats = self.http.get(f"{self.config.paths.index}/{self.uid}/{self.config.paths.stat}")
params: Dict[str, Any] = {}
if show_internal_database_sizes is not None:
params["showInternalDatabaseSizes"] = str(show_internal_database_sizes).lower()
if size_format is not None:
params["sizeFormat"] = (
size_format.value if isinstance(size_format, SizeFormat) else size_format
)

path = f"{self.config.paths.index}/{self.uid}/{self.config.paths.stat}"
if params:
path = f"{path}?{parse.urlencode(params)}"
stats = self.http.get(path)
return IndexStats(**stats)

@version_error_hint_message
Expand Down
6 changes: 6 additions & 0 deletions meilisearch/models/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ def __iter__(self) -> Iterator:
return iter(self.__dict__.items())


class SizeFormat(str, Enum):
RAW = "raw"
HUMAN = "human"


class IndexStats(CamelBase):
model_config = ConfigDict(arbitrary_types_allowed=True)

number_of_documents: int
is_indexing: bool
field_distribution: FieldDistribution
internal_database_sizes: Optional[Dict[str, Any]] = None

@field_validator("field_distribution", mode="before")
@classmethod
Expand Down
56 changes: 56 additions & 0 deletions tests/client/test_client_stats_meilisearch.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import re

import pytest

from meilisearch.models.index import SizeFormat

HUMAN_SIZE_PATTERN = re.compile(r"^\d+(\.\d+)?\s+(B|KiB|MiB|GiB|TiB)$")


@pytest.mark.usefixtures("indexes_sample")
def test_get_all_stats(client):
Expand All @@ -12,3 +18,53 @@ def test_get_all_stats(client):
assert "indexes" in response
assert "indexUID" in response["indexes"]
assert "indexUID2" in response["indexes"]


@pytest.mark.usefixtures("indexes_sample")
def test_get_all_stats_with_internal_database_sizes(client):
"""Tests getting all stats with showInternalDatabaseSizes parameter."""
response = client.get_all_stats(show_internal_database_sizes=True)
assert isinstance(response, dict)
assert isinstance(response["databaseSize"], int)
assert any("internalDatabaseSizes" in index_stats for index_stats in response["indexes"].values())
for index_stats in response["indexes"].values():
if "internalDatabaseSizes" in index_stats:
assert isinstance(index_stats["internalDatabaseSizes"], dict)
assert len(index_stats["internalDatabaseSizes"]) > 0
assert all(
isinstance(value, int) for value in index_stats["internalDatabaseSizes"].values()
)


@pytest.mark.usefixtures("indexes_sample")
def test_get_all_stats_with_size_format(client):
"""Tests getting all stats with sizeFormat parameter."""
response = client.get_all_stats(
show_internal_database_sizes=True,
size_format=SizeFormat.HUMAN,
)
assert isinstance(response, dict)
assert isinstance(response["databaseSize"], str)
assert HUMAN_SIZE_PATTERN.match(response["databaseSize"])
assert any(
"internalDatabaseSizes" in index_stats for index_stats in response["indexes"].values()
)
for index_stats in response["indexes"].values():
if "internalDatabaseSizes" in index_stats:
assert all(
isinstance(value, str) and HUMAN_SIZE_PATTERN.match(value)
for value in index_stats["internalDatabaseSizes"].values()
)


@pytest.mark.usefixtures("indexes_sample")
def test_get_all_stats_with_all_params(client):
"""Tests getting all stats with both query parameters."""
response = client.get_all_stats(
show_internal_database_sizes=True,
size_format="human",
)
assert isinstance(response, dict)
assert isinstance(response["databaseSize"], str)
assert "indexes" in response
assert any("internalDatabaseSizes" in index_stats for index_stats in response["indexes"].values())
42 changes: 41 additions & 1 deletion tests/index/test_index_stats_meilisearch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from meilisearch.models.index import IndexStats
import re

from meilisearch.models.index import IndexStats, SizeFormat

HUMAN_SIZE_PATTERN = re.compile(r"^\d+(\.\d+)?\s+(B|KiB|MiB|GiB|TiB)$")


def test_get_stats(empty_index):
Expand All @@ -15,3 +19,39 @@ def test_get_stats_default(index_with_documents):
assert response.number_of_documents == 31
assert hasattr(response.field_distribution, "genre")
assert response.field_distribution.genre == 11


def test_get_stats_with_internal_database_sizes(index_with_documents):
"""Tests getting stats with showInternalDatabaseSizes parameter."""
response = index_with_documents().get_stats(show_internal_database_sizes=True)
assert isinstance(response, IndexStats)
assert response.internal_database_sizes is not None
assert isinstance(response.internal_database_sizes, dict)
assert len(response.internal_database_sizes) > 0
assert all(isinstance(value, int) for value in response.internal_database_sizes.values())


def test_get_stats_with_size_format(index_with_documents):
"""Tests getting stats with sizeFormat parameter."""
response = index_with_documents().get_stats(
show_internal_database_sizes=True,
size_format=SizeFormat.HUMAN,
)
assert isinstance(response, IndexStats)
assert response.internal_database_sizes is not None
assert all(
isinstance(value, str) and HUMAN_SIZE_PATTERN.match(value)
for value in response.internal_database_sizes.values()
)


def test_get_stats_with_all_params(index_with_documents):
"""Tests getting stats with both query parameters."""
response = index_with_documents().get_stats(
show_internal_database_sizes=True,
size_format="human",
)
assert isinstance(response, IndexStats)
assert response.number_of_documents == 31
assert response.internal_database_sizes is not None
assert all(isinstance(value, str) for value in response.internal_database_sizes.values())