diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index b5b82ec5..2ef437e7 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -331,9 +331,15 @@ update_search_cutoff_1: |- reset_search_cutoff_1: |- client.index("movies").resetSearchCutoffMsSettings(); get_index_stats_1: |- - client.index("movies").getStats(); + StatsQuery statsQuery = new StatsQuery() + .setShowInternalDatabaseSizes(true) + .setSizeFormat("human"); + client.index("movies").getStats(statsQuery); get_indexes_stats_1: |- - client.getStats(); + StatsQuery statsQuery = new StatsQuery() + .setShowInternalDatabaseSizes(true) + .setSizeFormat("human"); + client.getStats(statsQuery); get_health_1: |- client.health(); get_version_1: |- diff --git a/src/main/java/com/meilisearch/sdk/Client.java b/src/main/java/com/meilisearch/sdk/Client.java index 37e250eb..ac55ff4c 100644 --- a/src/main/java/com/meilisearch/sdk/Client.java +++ b/src/main/java/com/meilisearch/sdk/Client.java @@ -274,6 +274,19 @@ public Stats getStats() throws MeilisearchException { return this.instanceHandler.getStats(); } + /** + * Gets extended information and metrics about indexes and the Meilisearch database + * + * @param params query parameters accepted by the stats route + * @return StatsWithSizeFormat instance from Meilisearch API response + * @throws MeilisearchException if an error occurs + * @see API + * specification + */ + public StatsWithSizeFormat getStats(StatsQuery params) throws MeilisearchException { + return this.instanceHandler.getStats(params); + } + /** * Gets the version of Meilisearch instance * diff --git a/src/main/java/com/meilisearch/sdk/Index.java b/src/main/java/com/meilisearch/sdk/Index.java index 97d397b7..ce33d104 100644 --- a/src/main/java/com/meilisearch/sdk/Index.java +++ b/src/main/java/com/meilisearch/sdk/Index.java @@ -1265,6 +1265,19 @@ public IndexStats getStats() throws MeilisearchException { return this.instanceHandler.getIndexStats(this.uid); } + /** + * Gets extended information and metrics about indexes and the Meilisearch database + * + * @param params query parameters accepted by the stats route + * @return Meilisearch API response + * @throws MeilisearchException if an error occurs + * @see API + * specification + */ + public IndexStatsWithSizeFormat getStats(StatsQuery params) throws MeilisearchException { + return this.instanceHandler.getIndexStats(this.uid, params); + } + /** * Retrieves an index tasks by its uid * diff --git a/src/main/java/com/meilisearch/sdk/InstanceHandler.java b/src/main/java/com/meilisearch/sdk/InstanceHandler.java index eea457b5..a4094d4e 100644 --- a/src/main/java/com/meilisearch/sdk/InstanceHandler.java +++ b/src/main/java/com/meilisearch/sdk/InstanceHandler.java @@ -1,8 +1,12 @@ package com.meilisearch.sdk; import com.meilisearch.sdk.exceptions.MeilisearchException; +import com.meilisearch.sdk.http.URLBuilder; import com.meilisearch.sdk.model.IndexStats; +import com.meilisearch.sdk.model.IndexStatsWithSizeFormat; import com.meilisearch.sdk.model.Stats; +import com.meilisearch.sdk.model.StatsQuery; +import com.meilisearch.sdk.model.StatsWithSizeFormat; /** Class providing information on the Meilisearch instance */ public class InstanceHandler { @@ -55,6 +59,22 @@ Stats getStats() throws MeilisearchException { return httpClient.get("/stats", Stats.class); } + /** + * Gets extended information and metrics about indexes and the Meilisearch database + * + * @param params query parameters accepted by the stats route + * @return Meilisearch API response + * @throws MeilisearchException if an error occurs + * @see API specification + */ + StatsWithSizeFormat getStats(StatsQuery params) throws MeilisearchException { + URLBuilder urlb = new URLBuilder("/stats"); + if (params != null) { + urlb.addQuery(params.toQuery()); + } + return httpClient.get(urlb.getURL(), StatsWithSizeFormat.class); + } + /** * Gets extended information and metrics about indexes and the Meilisearch database * @@ -68,6 +88,24 @@ IndexStats getIndexStats(String uid) throws MeilisearchException { return httpClient.get(requestQuery, IndexStats.class); } + /** + * Gets extended information and metrics about an index and the Meilisearch database + * + * @param uid Index identifier to the requested + * @param params query parameters accepted by the stats route + * @return Meilisearch API response + * @throws MeilisearchException if an error occurs + * @see API specification + */ + IndexStatsWithSizeFormat getIndexStats(String uid, StatsQuery params) + throws MeilisearchException { + URLBuilder urlb = new URLBuilder("/indexes").addSubroute(uid).addSubroute("stats"); + if (params != null) { + urlb.addQuery(params.toQuery()); + } + return httpClient.get(urlb.getURL(), IndexStatsWithSizeFormat.class); + } + /** * Gets the version of Meilisearch instance * diff --git a/src/main/java/com/meilisearch/sdk/model/IndexStatsWithSizeFormat.java b/src/main/java/com/meilisearch/sdk/model/IndexStatsWithSizeFormat.java new file mode 100644 index 00000000..7abf1708 --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/model/IndexStatsWithSizeFormat.java @@ -0,0 +1,47 @@ +package com.meilisearch.sdk.model; + +import java.util.Map; +import lombok.Getter; + +/** + * Stats data structure of a Meilisearch Index when database sizes may be raw bytes or human-readable + * strings. + * + * @see API + * specification + */ +@Getter +public class IndexStatsWithSizeFormat { + protected long numberOfDocuments; + protected boolean isIndexing; + protected Map fieldDistribution; + protected Object rawDocumentDbSize; + protected Object avgDocumentSize; + protected Object maxDocumentSize; + protected Long numberOfEmbeddedDocuments; + protected Long numberOfEmbeddings; + protected Map internalDatabaseSizes; + + public IndexStatsWithSizeFormat() {} + + public IndexStatsWithSizeFormat( + long numberOfDocuments, + boolean isIndexing, + Map fieldDistribution, + Object rawDocumentDbSize, + Object avgDocumentSize, + Object maxDocumentSize, + Long numberOfEmbeddedDocuments, + Long numberOfEmbeddings, + Map internalDatabaseSizes) { + this.numberOfDocuments = numberOfDocuments; + this.isIndexing = isIndexing; + this.fieldDistribution = fieldDistribution; + this.rawDocumentDbSize = rawDocumentDbSize; + this.avgDocumentSize = avgDocumentSize; + this.maxDocumentSize = maxDocumentSize; + this.numberOfEmbeddedDocuments = numberOfEmbeddedDocuments; + this.numberOfEmbeddings = numberOfEmbeddings; + this.internalDatabaseSizes = internalDatabaseSizes; + } +} diff --git a/src/main/java/com/meilisearch/sdk/model/StatsQuery.java b/src/main/java/com/meilisearch/sdk/model/StatsQuery.java new file mode 100644 index 00000000..2e61685f --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/model/StatsQuery.java @@ -0,0 +1,31 @@ +package com.meilisearch.sdk.model; + +import com.meilisearch.sdk.http.URLBuilder; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + * Data structure of the query parameters for the stats routes. + * + * @see API specification + */ +@Setter +@Getter +@Accessors(chain = true) +public class StatsQuery { + private Boolean showInternalDatabaseSizes; + private String sizeFormat; + + public StatsQuery() {} + + public String toQuery() { + URLBuilder urlb = + new URLBuilder() + .addParameter( + "showInternalDatabaseSizes", + this.getShowInternalDatabaseSizes()) + .addParameter("sizeFormat", this.getSizeFormat()); + return urlb.getURL(); + } +} diff --git a/src/main/java/com/meilisearch/sdk/model/StatsWithSizeFormat.java b/src/main/java/com/meilisearch/sdk/model/StatsWithSizeFormat.java new file mode 100644 index 00000000..9a788f93 --- /dev/null +++ b/src/main/java/com/meilisearch/sdk/model/StatsWithSizeFormat.java @@ -0,0 +1,31 @@ +package com.meilisearch.sdk.model; + +import java.util.Date; +import java.util.Map; +import lombok.Getter; + +/** + * Meilisearch stats data structure when database sizes may be raw bytes or human-readable strings. + * + * @see API specification + */ +@Getter +public class StatsWithSizeFormat { + protected Object databaseSize; + protected Date lastUpdate; + protected Map indexes; + protected Object usedDatabaseSize; + + public StatsWithSizeFormat( + Object databaseSize, + Date lastUpdate, + Map indexes, + Object usedDatabaseSize) { + this.databaseSize = databaseSize; + this.lastUpdate = lastUpdate; + this.indexes = indexes; + this.usedDatabaseSize = usedDatabaseSize; + } + + public StatsWithSizeFormat() {} +} diff --git a/src/test/java/com/meilisearch/sdk/StatsTest.java b/src/test/java/com/meilisearch/sdk/StatsTest.java new file mode 100644 index 00000000..5a267954 --- /dev/null +++ b/src/test/java/com/meilisearch/sdk/StatsTest.java @@ -0,0 +1,121 @@ +package com.meilisearch.sdk; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import com.meilisearch.sdk.model.IndexStatsWithSizeFormat; +import com.meilisearch.sdk.model.StatsQuery; +import com.meilisearch.sdk.model.StatsWithSizeFormat; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StatsTest { + + private MockWebServer server; + private Client client; + + @BeforeEach + void setup() throws Exception { + server = new MockWebServer(); + server.start(); + + client = new Client(new Config(server.url("/").toString(), "masterKey")); + } + + @AfterEach + void teardown() throws Exception { + server.shutdown(); + } + + @Test + void getStatsWithQueryParameters() throws Exception { + String json = + """ + { + "databaseSize": "1.2 KiB", + "usedDatabaseSize": "1 KiB", + "lastUpdate": "2019-11-20T09:40:33.711324Z", + "indexes": { + "movies": { + "numberOfDocuments": 10, + "rawDocumentDbSize": "100 B", + "maxDocumentSize": "16 B", + "avgDocumentSize": "10 B", + "isIndexing": true, + "fieldDistribution": { + "genre": 10 + }, + "internalDatabaseSizes": { + "documents": "100 B" + } + } + } + } + """; + StatsQuery query = + new StatsQuery().setShowInternalDatabaseSizes(true).setSizeFormat("human"); + + server.enqueue(new MockResponse().setResponseCode(200).setBody(json)); + + StatsWithSizeFormat stats = client.getStats(query); + + assertThat( + server.takeRequest().getPath(), + is("//stats?showInternalDatabaseSizes=true&sizeFormat=human")); + assertThat(stats.getDatabaseSize(), is("1.2 KiB")); + assertThat(stats.getUsedDatabaseSize(), is("1 KiB")); + assertThat(stats.getIndexes().get("movies").getRawDocumentDbSize(), is("100 B")); + assertThat( + stats.getIndexes().get("movies").getInternalDatabaseSizes().get("documents"), + is("100 B")); + } + + @Test + void getIndexStatsWithQueryParameters() throws Exception { + String json = + """ + { + "numberOfDocuments": 10, + "rawDocumentDbSize": "100 B", + "maxDocumentSize": "16 B", + "avgDocumentSize": "10 B", + "numberOfEmbeddings": 2, + "numberOfEmbeddedDocuments": 1, + "isIndexing": false, + "fieldDistribution": { + "genre": 10 + }, + "internalDatabaseSizes": { + "documents": "100 B" + } + } + """; + StatsQuery query = + new StatsQuery().setShowInternalDatabaseSizes(true).setSizeFormat("human"); + + server.enqueue(new MockResponse().setResponseCode(200).setBody(json)); + + IndexStatsWithSizeFormat stats = client.index("movies").getStats(query); + + assertThat( + server.takeRequest().getPath(), + is("//indexes/movies/stats?showInternalDatabaseSizes=true&sizeFormat=human")); + assertThat(stats.getRawDocumentDbSize(), is("100 B")); + assertThat(stats.getAvgDocumentSize(), is("10 B")); + assertThat(stats.getMaxDocumentSize(), is("16 B")); + assertThat(stats.getInternalDatabaseSizes().get("documents"), is("100 B")); + assertThat(stats.getNumberOfEmbeddings(), is(2L)); + assertThat(stats.getNumberOfEmbeddedDocuments(), is(1L)); + } + + @Test + void statsQuerySerializesParameters() { + StatsQuery query = + new StatsQuery().setShowInternalDatabaseSizes(true).setSizeFormat("raw"); + + assertThat(query.toQuery(), is("?showInternalDatabaseSizes=true&sizeFormat=raw")); + } +}