diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 530085b3..bc3cefd0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -29,7 +29,7 @@ jobs:
- name: Meilisearch (latest) setup with Docker
run: docker run -d -p 7700:7700 getmeili/meilisearch:latest meilisearch --master-key=masterKey --no-analytics
- name: Build and run unit and integration tests
- run: ./gradlew build integrationTest
+ run: ./gradlew build integrationTest --info
- name: Archive test report
uses: actions/upload-artifact@v4
if: failure()
diff --git a/src/main/java/com/meilisearch/sdk/Index.java b/src/main/java/com/meilisearch/sdk/Index.java
index ee0431a4..828fbe68 100644
--- a/src/main/java/com/meilisearch/sdk/Index.java
+++ b/src/main/java/com/meilisearch/sdk/Index.java
@@ -1249,4 +1249,42 @@ public SimilarDocumentsResults searchSimilarDocuments(SimilarDocumentRequest que
query,
SimilarDocumentsResults.class);
}
+
+ /**
+ * Gets the embedders settings of the index
+ *
+ * @return a Map that contains all embedders settings
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public Map getEmbeddersSettings() throws MeilisearchException {
+ return this.settingsHandler.getEmbedders(this.uid);
+ }
+
+ /**
+ * Updates the embedders settings of the index
+ *
+ * @param embedders a Map that contains the new embedders settings
+ * @return TaskInfo instance
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo updateEmbeddersSettings(Map embedders)
+ throws MeilisearchException {
+ return this.settingsHandler.updateEmbedders(this.uid, embedders);
+ }
+
+ /**
+ * Resets the embedders settings of the index
+ *
+ * @return TaskInfo instance
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo resetEmbeddersSettings() throws MeilisearchException {
+ return this.settingsHandler.resetEmbedders(this.uid);
+ }
}
diff --git a/src/main/java/com/meilisearch/sdk/IndexSearchRequest.java b/src/main/java/com/meilisearch/sdk/IndexSearchRequest.java
index 3ba8eef4..8e35ab3e 100644
--- a/src/main/java/com/meilisearch/sdk/IndexSearchRequest.java
+++ b/src/main/java/com/meilisearch/sdk/IndexSearchRequest.java
@@ -38,13 +38,14 @@ public class IndexSearchRequest {
private FederationOptions federationOptions;
protected String[] locales;
protected String distinct;
+ protected Boolean retrieveVectors;
/**
* Constructor for MultiSearchRequest for building search queries with the default values:
* offset: 0, limit: 20, attributesToRetrieve: ["*"], attributesToCrop: null, cropLength: 200,
* attributesToHighlight: null, filter: null, showMatchesPosition: false, facets: null, sort:
* null, showRankingScore: false, showRankingScoreDetails: false, rankingScoreThreshold: null
- * distinct: null
+ * distinct: null, retrieveVectors: false
*
* @param indexUid uid of the requested index String
*/
@@ -106,7 +107,8 @@ public String toString() {
.putOpt("rankingScoreThreshold", this.rankingScoreThreshold)
.putOpt("attributesToSearchOn", this.attributesToSearchOn)
.putOpt("locales", this.locales)
- .putOpt("distinct", this.distinct);
+ .putOpt("distinct", this.distinct)
+ .putOpt("retrieveVectors", this.retrieveVectors);
return jsonObject.toString();
}
diff --git a/src/main/java/com/meilisearch/sdk/SearchRequest.java b/src/main/java/com/meilisearch/sdk/SearchRequest.java
index 77650ad5..43e043cc 100644
--- a/src/main/java/com/meilisearch/sdk/SearchRequest.java
+++ b/src/main/java/com/meilisearch/sdk/SearchRequest.java
@@ -1,5 +1,6 @@
package com.meilisearch.sdk;
+import com.meilisearch.sdk.model.Hybrid;
import com.meilisearch.sdk.model.MatchingStrategy;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
@@ -42,12 +43,15 @@ public class SearchRequest {
protected Double rankingScoreThreshold;
protected String[] locales;
protected String distinct;
-
+ protected Hybrid hybrid;
+ protected Double[] vector;
+ protected Boolean retrieveVectors;
/**
* Constructor for SearchRequest for building search queries with the default values: offset: 0,
* limit: 20, attributesToRetrieve: ["*"], attributesToCrop: null, cropLength: 200,
* attributesToHighlight: null, filter: null, showMatchesPosition: false, facets: null, sort:
- * null, showRankingScore: false, showRankingScoreDetails: false, rankingScoreThreshold: null
+ * null, showRankingScore: false, showRankingScoreDetails: false, rankingScoreThreshold: null,
+ * retrieveVectors: false
*
* @param q Query String
*/
@@ -104,7 +108,13 @@ public String toString() {
.putOpt("showRankingScoreDetails", this.showRankingScoreDetails)
.putOpt("rankingScoreThreshold", this.rankingScoreThreshold)
.putOpt("locales", this.locales)
- .putOpt("distinct", this.distinct);
+ .putOpt("distinct", this.distinct)
+ .putOpt("vector", this.vector)
+ .putOpt("retrieveVectors", this.retrieveVectors);
+
+ if (this.hybrid != null) {
+ jsonObject.put("hybrid", this.hybrid.toJSONObject());
+ }
return jsonObject.toString();
}
diff --git a/src/main/java/com/meilisearch/sdk/SettingsHandler.java b/src/main/java/com/meilisearch/sdk/SettingsHandler.java
index c70f9f80..9ee73a3a 100644
--- a/src/main/java/com/meilisearch/sdk/SettingsHandler.java
+++ b/src/main/java/com/meilisearch/sdk/SettingsHandler.java
@@ -2,6 +2,7 @@
import com.meilisearch.sdk.exceptions.MeilisearchException;
import com.meilisearch.sdk.http.URLBuilder;
+import com.meilisearch.sdk.model.Embedder;
import com.meilisearch.sdk.model.Faceting;
import com.meilisearch.sdk.model.LocalizedAttribute;
import com.meilisearch.sdk.model.Pagination;
@@ -769,4 +770,47 @@ public TaskInfo resetNonSeparatorTokensSettings(String uid) {
return httpClient.delete(
settingsPath(uid).addSubroute("non-separator-tokens").getURL(), TaskInfo.class);
}
+
+ /**
+ * Gets the embedders settings of the index
+ *
+ * @param uid Index identifier
+ * @return a Map that contains all embedders settings
+ * @throws MeilisearchException if an error occurs
+ */
+ Map getEmbedders(String uid) throws MeilisearchException {
+ return httpClient.get(
+ settingsPath(uid).addSubroute("embedders").getURL(),
+ Map.class,
+ String.class,
+ Embedder.class);
+ }
+
+ /**
+ * Updates the embedders settings of the index
+ *
+ * @param uid Index identifier
+ * @param embedders a Map that contains the new embedders settings
+ * @return TaskInfo instance
+ * @throws MeilisearchException if an error occurs
+ */
+ TaskInfo updateEmbedders(String uid, Map embedders)
+ throws MeilisearchException {
+ return httpClient.patch(
+ settingsPath(uid).addSubroute("embedders").getURL(),
+ embedders == null ? null : httpClient.jsonHandler.encode(embedders),
+ TaskInfo.class);
+ }
+
+ /**
+ * Resets the embedders settings of the index
+ *
+ * @param uid Index identifier
+ * @return TaskInfo instance
+ * @throws MeilisearchException if an error occurs
+ */
+ TaskInfo resetEmbedders(String uid) throws MeilisearchException {
+ return httpClient.delete(
+ settingsPath(uid).addSubroute("embedders").getURL(), TaskInfo.class);
+ }
}
diff --git a/src/main/java/com/meilisearch/sdk/SimilarDocumentRequest.java b/src/main/java/com/meilisearch/sdk/SimilarDocumentRequest.java
index 99ad5f46..a8dc1191 100644
--- a/src/main/java/com/meilisearch/sdk/SimilarDocumentRequest.java
+++ b/src/main/java/com/meilisearch/sdk/SimilarDocumentRequest.java
@@ -31,18 +31,17 @@ public SimilarDocumentRequest() {}
@Override
public String toString() {
- JSONObject jsonObject =
- new JSONObject()
- .put("id", this.id)
- .put("embedder", this.embedder)
- .put("attributesToRetrieve", this.attributesToRetrieve)
- .put("offset", this.offset)
- .put("limit", this.limit)
- .put("filter", this.filter)
- .put("showRankingScore", this.showRankingScore)
- .put("showRankingScoreDetails", this.showRankingScoreDetails)
- .put("rankingScoreThreshold", this.rankingScoreThreshold)
- .put("retrieveVectors", this.retrieveVectors);
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.putOpt("id", this.id);
+ jsonObject.putOpt("embedder", this.embedder);
+ jsonObject.putOpt("attributesToRetrieve", this.attributesToRetrieve);
+ jsonObject.putOpt("offset", this.offset);
+ jsonObject.putOpt("limit", this.limit);
+ jsonObject.putOpt("filter", this.filter);
+ jsonObject.putOpt("showRankingScore", this.showRankingScore);
+ jsonObject.putOpt("showRankingScoreDetails", this.showRankingScoreDetails);
+ jsonObject.putOpt("rankingScoreThreshold", this.rankingScoreThreshold);
+ jsonObject.putOpt("retrieveVectors", this.retrieveVectors);
return jsonObject.toString();
}
diff --git a/src/main/java/com/meilisearch/sdk/model/Embedder.java b/src/main/java/com/meilisearch/sdk/model/Embedder.java
new file mode 100644
index 00000000..7179428d
--- /dev/null
+++ b/src/main/java/com/meilisearch/sdk/model/Embedder.java
@@ -0,0 +1,73 @@
+package com.meilisearch.sdk.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import lombok.*;
+import lombok.experimental.Accessors;
+
+@Builder
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+@Getter
+@Setter
+@Accessors(chain = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Embedder {
+ /** Source of the embedder. Accepts: ollama, rest, openAI, huggingFace and userProvided */
+ protected EmbedderSource source;
+
+ /**
+ * API key for authentication with the embedder service. Optional: Only applicable for openAi,
+ * ollama, and rest sources.
+ */
+ protected String apiKey;
+
+ /**
+ * Model to use for generating embeddings. Optional: Only applicable for ollama, openAI, and
+ * huggingFace sources.
+ */
+ protected String model;
+
+ /** Template for document embedding. Optional. */
+ protected String documentTemplate;
+
+ /**
+ * Dimensions of the embedding vectors. Optional: Only applicable for openAi, huggingFace,
+ * ollama, and rest sources.
+ */
+ protected Integer dimensions;
+
+ /** Distribution configuration. Optional. */
+ protected EmbedderDistribution distribution;
+
+ /** Request configuration. Mandatory only when using rest embedder, optional otherwise. */
+ protected Map request;
+
+ /** Response configuration. Mandatory only when using rest embedder, optional otherwise. */
+ protected Map response;
+
+ /** Maximum bytes for document template. Optional. */
+ protected Integer documentTemplateMaxBytes;
+
+ /** Revision identifier. Optional: Only applicable for huggingFace. */
+ protected String revision;
+
+ /** HTTP headers. Optional: Only applicable for rest. */
+ protected Map headers;
+
+ /** Whether to use binary quantization. Optional. */
+ protected Boolean binaryQuantized;
+
+ /** URL for the embedder service. Optional. */
+ protected String url;
+
+ /** Input fields for the embedder. Optional. */
+ protected String[] inputField;
+
+ /** Type of input for the embedder. Optional. */
+ protected EmbedderInputType inputType;
+
+ /** Query for the embedder. Optional. */
+ protected String query;
+
+ public Embedder() {}
+}
diff --git a/src/main/java/com/meilisearch/sdk/model/EmbedderDistribution.java b/src/main/java/com/meilisearch/sdk/model/EmbedderDistribution.java
new file mode 100644
index 00000000..e99480bb
--- /dev/null
+++ b/src/main/java/com/meilisearch/sdk/model/EmbedderDistribution.java
@@ -0,0 +1,56 @@
+package com.meilisearch.sdk.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * Describes the natural distribution of search results for embedders. Contains mean and sigma
+ * values, each between 0 and 1.
+ */
+@Builder
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+@NoArgsConstructor(access = AccessLevel.PUBLIC)
+@Getter
+@Setter
+@Accessors(chain = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class EmbedderDistribution {
+ /** Mean value of the distribution, between 0 and 1 */
+ private Double mean;
+
+ /** Sigma (standard deviation) value of the distribution, between 0 and 1 */
+ private Double sigma;
+
+ /**
+ * Creates a uniform distribution with default values
+ *
+ * @return An EmbedderDistribution instance with mean=0.5 and sigma=0.5
+ */
+ public static EmbedderDistribution uniform() {
+ return new EmbedderDistribution().setMean(0.5).setSigma(0.5);
+ }
+
+ /**
+ * Creates a custom distribution with specified mean and sigma values
+ *
+ * @param mean Mean value between 0 and 1
+ * @param sigma Sigma value between 0 and 1
+ * @return An EmbedderDistribution instance with the specified values
+ * @throws IllegalArgumentException if mean or sigma are outside the valid range
+ */
+ public static EmbedderDistribution custom(double mean, double sigma) {
+ if (mean < 0 || mean > 1) {
+ throw new IllegalArgumentException("Mean must be between 0 and 1");
+ }
+ if (sigma < 0 || sigma > 1) {
+ throw new IllegalArgumentException("Sigma must be between 0 and 1");
+ }
+ return new EmbedderDistribution().setMean(mean).setSigma(sigma);
+ }
+}
diff --git a/src/main/java/com/meilisearch/sdk/model/Embedders.java b/src/main/java/com/meilisearch/sdk/model/Embedders.java
deleted file mode 100644
index 99fa7408..00000000
--- a/src/main/java/com/meilisearch/sdk/model/Embedders.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.meilisearch.sdk.model;
-
-import lombok.*;
-import lombok.experimental.Accessors;
-
-@Builder
-@AllArgsConstructor(access = AccessLevel.PACKAGE)
-@Getter
-@Setter
-@Accessors(chain = true)
-public class Embedders {
- protected EmbedderSource source;
- protected String url;
- protected String apiKey;
- protected String model;
- protected String documentTemplate;
- protected Integer dimensions;
- protected String revision;
- protected String[] inputField;
- protected EmbedderInputType inputType;
- protected String query;
-
- public Embedders() {}
-}
diff --git a/src/main/java/com/meilisearch/sdk/model/Hybrid.java b/src/main/java/com/meilisearch/sdk/model/Hybrid.java
new file mode 100644
index 00000000..62cdd1bb
--- /dev/null
+++ b/src/main/java/com/meilisearch/sdk/model/Hybrid.java
@@ -0,0 +1,48 @@
+package com.meilisearch.sdk.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.json.JSONObject;
+
+/** Hybrid search configuration */
+@Builder
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+@NoArgsConstructor(access = AccessLevel.PACKAGE)
+@Getter
+@Setter
+@Accessors(chain = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Hybrid {
+ /** Semantic ratio for hybrid search (between 0 and 1) */
+ private Double semanticRatio;
+
+ /** Embedder to use for hybrid search (mandatory if hybrid is set) */
+ private String embedder;
+
+ /**
+ * Method that returns the JSON representation of the Hybrid object
+ *
+ * @return JSONObject representation of the Hybrid object
+ */
+ public JSONObject toJSONObject() {
+ return new JSONObject()
+ .putOpt("semanticRatio", this.semanticRatio)
+ .putOpt("embedder", this.embedder);
+ }
+
+ /**
+ * Method that returns the JSON String of the Hybrid object
+ *
+ * @return JSON String of the Hybrid object
+ */
+ @Override
+ public String toString() {
+ return toJSONObject().toString();
+ }
+}
diff --git a/src/main/java/com/meilisearch/sdk/model/SearchResult.java b/src/main/java/com/meilisearch/sdk/model/SearchResult.java
index a77f30a5..ef8c424a 100644
--- a/src/main/java/com/meilisearch/sdk/model/SearchResult.java
+++ b/src/main/java/com/meilisearch/sdk/model/SearchResult.java
@@ -22,6 +22,7 @@ public class SearchResult implements Searchable {
int offset;
int limit;
int estimatedTotalHits;
+ HashMap _vectors;
public SearchResult() {}
}
diff --git a/src/main/java/com/meilisearch/sdk/model/Settings.java b/src/main/java/com/meilisearch/sdk/model/Settings.java
index 2a4233b6..419bd09f 100644
--- a/src/main/java/com/meilisearch/sdk/model/Settings.java
+++ b/src/main/java/com/meilisearch/sdk/model/Settings.java
@@ -31,7 +31,7 @@ public class Settings {
protected Integer searchCutoffMs;
protected String[] separatorTokens;
protected String[] nonSeparatorTokens;
- protected HashMap embedders;
+ protected HashMap embedders;
protected LocalizedAttribute[] localizedAttributes;
public Settings() {}
diff --git a/src/test/java/com/meilisearch/integration/SearchTest.java b/src/test/java/com/meilisearch/integration/SearchTest.java
index 86c17d92..c89a752d 100644
--- a/src/test/java/com/meilisearch/integration/SearchTest.java
+++ b/src/test/java/com/meilisearch/integration/SearchTest.java
@@ -1090,9 +1090,9 @@ public void testMultiSearchWithMergeFacets() {
public void testSimilarDocuments() throws Exception {
String indexUid = "SimilarDocuments";
Index index = client.index(indexUid);
- HashMap embedders = new HashMap<>();
+ HashMap embedders = new HashMap<>();
embedders.put(
- "manual", new Embedders().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
+ "manual", new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
Settings settings = new Settings();
settings.setEmbedders(embedders);
@@ -1116,6 +1116,81 @@ public void testSimilarDocuments() throws Exception {
assertThat(hits.get(3).get("title"), is("Shazam!"));
}
+ /** Test vector search */
+ @Test
+ public void testVectorSearch() throws Exception {
+ String indexUid = "testVectorSearch";
+ Index index = client.index(indexUid);
+ HashMap embedders = new HashMap<>();
+ embedders.put(
+ "manual", new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
+
+ Settings settings = new Settings();
+ settings.setEmbedders(embedders);
+
+ index.updateSettings(settings);
+
+ TestData testData = this.getTestData(VECTOR_MOVIES, Movie.class);
+ TaskInfo task = index.addDocuments(testData.getRaw());
+
+ index.waitForTask(task.getTaskUid());
+
+ SearchRequest searchRequest =
+ SearchRequest.builder()
+ .vector(new Double[] {0.1, 0.6, 0.8})
+ .hybrid(Hybrid.builder().semanticRatio(0.5).embedder("manual").build())
+ .build();
+
+ SearchResult searchResult = (SearchResult) index.search(searchRequest);
+
+ assertThat(searchResult.getHits(), hasSize(5));
+ // The most similar document should be "Escape Room" since its vector [0.1, 0.6, 0.8]
+ assertThat(searchResult.getHits().get(0).get("id"), is("522681"));
+ assertThat(searchResult.getHits().get(0).get("title"), is("Escape Room"));
+ }
+
+ /** Test vector search with retrieveVectors option */
+ @Test
+ public void testVectorSearchWithRetrieveVectors() throws Exception {
+ String indexUid = "testVectorSearchWithRetrieveVectors";
+ Index index = client.index(indexUid);
+ HashMap embedders = new HashMap<>();
+ embedders.put(
+ "manual", new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
+
+ Settings settings = new Settings();
+ settings.setEmbedders(embedders);
+
+ index.updateSettings(settings);
+
+ TestData testData = this.getTestData(VECTOR_MOVIES, Movie.class);
+ TaskInfo task = index.addDocuments(testData.getRaw());
+
+ index.waitForTask(task.getTaskUid());
+
+ SearchRequest searchRequest =
+ SearchRequest.builder()
+ .vector(new Double[] {0.1, 0.6, 0.8})
+ .hybrid(Hybrid.builder().semanticRatio(0.5).embedder("manual").build())
+ .retrieveVectors(true)
+ .build();
+
+ SearchResult searchResult = (SearchResult) index.search(searchRequest);
+
+ assertThat(searchResult.getHits(), hasSize(5));
+ // The most similar document should be "Escape Room" since its vector [0.1, 0.6, 0.8]
+ assertThat(searchResult.getHits().get(0).get("id"), is("522681"));
+ assertThat(searchResult.getHits().get(0).get("title"), is("Escape Room"));
+
+ // Verify that vectors are returned in the response
+ Map escapeRoomHit = searchResult.getHits().get(0);
+ assertThat(escapeRoomHit.containsKey("_vectors"), is(true));
+
+ @SuppressWarnings("unchecked")
+ Map vectors = (Map) escapeRoomHit.get("_vectors");
+ assertThat(vectors.containsKey("manual"), is(true));
+ }
+
/** Test Search with locales */
@Test
public void testSearchWithLocales() throws Exception {
@@ -1191,4 +1266,45 @@ public void testMultiSearchWithLocales() throws Exception {
assertThat(results[0].getHits().size(), is(7));
assertThat(results[1].getHits().size(), is(2));
}
+
+ /** Test search with retrieveVectors parameter */
+ @Test
+ public void testSearchWithRetrieveVectors() throws Exception {
+ String indexUid = "testSearchWithRetrieveVectors";
+ Index index = client.index(indexUid);
+ HashMap embedders = new HashMap<>();
+ embedders.put(
+ "manual", new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
+
+ Settings settings = new Settings();
+ settings.setEmbedders(embedders);
+
+ index.updateSettings(settings);
+
+ TestData testData = this.getTestData(VECTOR_MOVIES, Movie.class);
+ TaskInfo task = index.addDocuments(testData.getRaw());
+
+ index.waitForTask(task.getTaskUid());
+
+ // First search without retrieveVectors
+ SearchRequest searchRequestWithout = SearchRequest.builder().q("").build();
+ SearchResult searchResultWithout = (SearchResult) index.search(searchRequestWithout);
+
+ assertThat(searchResultWithout.getHits(), hasSize(5));
+ Map hitWithout = searchResultWithout.getHits().get(0);
+ assertThat(hitWithout.containsKey("_vectors"), is(false));
+
+ // Then search with retrieveVectors
+ SearchRequest searchRequestWith =
+ SearchRequest.builder().q("").retrieveVectors(true).build();
+ SearchResult searchResultWith = (SearchResult) index.search(searchRequestWith);
+
+ assertThat(searchResultWith.getHits(), hasSize(5));
+ Map hitWith = searchResultWith.getHits().get(0);
+ assertThat(hitWith.containsKey("_vectors"), is(true));
+
+ @SuppressWarnings("unchecked")
+ Map vectors = (Map) hitWith.get("_vectors");
+ assertThat(vectors.containsKey("manual"), is(true));
+ }
}
diff --git a/src/test/java/com/meilisearch/integration/SettingsTest.java b/src/test/java/com/meilisearch/integration/SettingsTest.java
index b345bdac..10979242 100644
--- a/src/test/java/com/meilisearch/integration/SettingsTest.java
+++ b/src/test/java/com/meilisearch/integration/SettingsTest.java
@@ -16,6 +16,8 @@
import com.meilisearch.integration.classes.AbstractIT;
import com.meilisearch.integration.classes.TestData;
import com.meilisearch.sdk.Index;
+import com.meilisearch.sdk.model.Embedder;
+import com.meilisearch.sdk.model.EmbedderSource;
import com.meilisearch.sdk.model.FacetSortValue;
import com.meilisearch.sdk.model.Faceting;
import com.meilisearch.sdk.model.LocalizedAttribute;
@@ -1465,4 +1467,59 @@ public void testResetNonSeparatorTokensSettings() throws Exception {
nonSeparatorTokensAfterReset, is(arrayWithSize(initialNonSeparatorTokens.length)));
assertThat(nonSeparatorTokensAfterReset, is(equalTo(initialNonSeparatorTokens)));
}
+
+ @Test
+ @DisplayName("Test get embedders settings by uid")
+ public void testGetEmbeddersSettings() throws Exception {
+ Index index = createIndex("testGetEmbeddersSettings");
+ Settings initialSettings = index.getSettings();
+ Map initialEmbedders = index.getEmbeddersSettings();
+
+ assertThat(initialEmbedders, is(equalTo(initialSettings.getEmbedders())));
+ }
+
+ @Test
+ @DisplayName("Test update embedders settings")
+ public void testUpdateEmbeddersSettings() throws Exception {
+ Index index = createEmptyIndex("testUpdateEmbeddersSettings");
+
+ // Update settings
+ HashMap newEmbedders = new HashMap<>();
+ Embedder userProvidedEmbedder =
+ new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(768);
+ newEmbedders.put("custom", userProvidedEmbedder);
+ TaskInfo task = index.updateEmbeddersSettings(newEmbedders);
+ index.waitForTask(task.getTaskUid());
+
+ // Verify results
+ Map updatedEmbedders = index.getEmbeddersSettings();
+ assertThat(updatedEmbedders.size(), is(equalTo(1)));
+ Embedder retrievedUser = updatedEmbedders.get("custom");
+ assertThat(retrievedUser.getSource(), is(equalTo(EmbedderSource.USER_PROVIDED)));
+ assertThat(retrievedUser.getDimensions(), is(equalTo(768)));
+ }
+
+ @Test
+ @DisplayName("Test reset embedders settings")
+ public void testResetEmbeddersSettings() throws Exception {
+ // Create and set new embedders
+ Index index = createEmptyIndex("testResetEmbeddersSettings");
+ HashMap embedders = new HashMap<>();
+ Embedder userProvidedEmbedder =
+ new Embedder().setSource(EmbedderSource.USER_PROVIDED).setDimensions(768);
+ embedders.put("custom", userProvidedEmbedder);
+
+ // Update settings
+ TaskInfo updateTask = index.updateEmbeddersSettings(embedders);
+ index.waitForTask(updateTask.getTaskUid());
+ Map updatedEmbedders = index.getEmbeddersSettings();
+ assertThat(updatedEmbedders.size(), is(equalTo(1)));
+ assertThat(updatedEmbedders.containsKey("custom"), is(true));
+
+ // Reset settings
+ TaskInfo resetTask = index.resetEmbeddersSettings();
+ index.waitForTask(resetTask.getTaskUid());
+ Map resetEmbedders = index.getEmbeddersSettings();
+ assertThat(resetEmbedders.size(), is(equalTo(0)));
+ }
}
diff --git a/src/test/java/com/meilisearch/integration/TasksTest.java b/src/test/java/com/meilisearch/integration/TasksTest.java
index 0eec58d1..2690c8d9 100644
--- a/src/test/java/com/meilisearch/integration/TasksTest.java
+++ b/src/test/java/com/meilisearch/integration/TasksTest.java
@@ -138,6 +138,22 @@ public void testClientGetTaskErrorWhenAddingDocuments() throws Exception {
/** Test Get Tasks with limit and from */
@Test
public void testClientGetTasksLimitAndFrom() throws Exception {
+ // Create several indexes to make sure we have enough tasks
+ String indexUid1 = "GetClientTasksLimitFrom1";
+ String indexUid2 = "GetClientTasksLimitFrom2";
+ String indexUid3 = "GetClientTasksLimitFrom3";
+ String indexUid4 = "GetClientTasksLimitFrom4";
+
+ // Create indexes to generate tasks
+ TaskInfo response1 = client.createIndex(indexUid1);
+ client.waitForTask(response1.getTaskUid());
+ TaskInfo response2 = client.createIndex(indexUid2);
+ client.waitForTask(response2.getTaskUid());
+ TaskInfo response3 = client.createIndex(indexUid3);
+ client.waitForTask(response3.getTaskUid());
+ TaskInfo response4 = client.createIndex(indexUid4);
+ client.waitForTask(response4.getTaskUid());
+
int limit = 2;
int from = 2;
TasksQuery query = new TasksQuery().setLimit(limit).setFrom(from);
@@ -147,7 +163,7 @@ public void testClientGetTasksLimitAndFrom() throws Exception {
assertThat(result.getFrom(), is(equalTo(from)));
assertThat(result.getFrom(), is(notNullValue()));
assertThat(result.getNext(), is(notNullValue()));
- assertThat(result.getResults().length, is(notNullValue()));
+ assertThat(result.getResults().length, is(equalTo(limit)));
}
/** Test Get Tasks with uid as filter */
diff --git a/src/test/java/com/meilisearch/sdk/SearchRequestTest.java b/src/test/java/com/meilisearch/sdk/SearchRequestTest.java
index 6eb9f850..ca004a30 100644
--- a/src/test/java/com/meilisearch/sdk/SearchRequestTest.java
+++ b/src/test/java/com/meilisearch/sdk/SearchRequestTest.java
@@ -5,7 +5,9 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
+import com.meilisearch.sdk.model.Hybrid;
import com.meilisearch.sdk.model.MatchingStrategy;
+import org.json.JSONObject;
import org.junit.jupiter.api.Test;
class SearchRequestTest {
@@ -363,4 +365,73 @@ void toStringEveryParametersWithArrayMatchingStrategyNull() {
assertThat(classToTest.getDistinct(), is(equalTo("distinct")));
assertThat(classToTest.toString(), is(equalTo(expectedToString)));
}
+
+ @Test
+ void toStringWithHybrid() {
+ Hybrid hybrid = Hybrid.builder().semanticRatio(0.5).embedder("default").build();
+
+ SearchRequest classToTest = new SearchRequest("This is a Test").setHybrid(hybrid);
+
+ String expected =
+ "{\"q\":\"This is a Test\",\"hybrid\":{\"semanticRatio\":0.5,\"embedder\":\"default\"}}";
+ assertThat(classToTest.toString(), is(equalTo(expected)));
+
+ // Verify getters
+ assertThat(classToTest.getHybrid().getSemanticRatio(), is(equalTo(0.5)));
+ assertThat(classToTest.getHybrid().getEmbedder(), is(equalTo("default")));
+ }
+
+ @Test
+ void toStringWithHybridUsingBuilder() {
+ SearchRequest classToTest =
+ SearchRequest.builder()
+ .q("This is a Test")
+ .hybrid(Hybrid.builder().semanticRatio(0.5).embedder("default").build())
+ .build();
+
+ String expected =
+ "{\"q\":\"This is a Test\",\"hybrid\":{\"semanticRatio\":0.5,\"embedder\":\"default\"}}";
+ assertThat(classToTest.toString(), is(equalTo(expected)));
+
+ // Verify getters
+ assertThat(classToTest.getHybrid().getSemanticRatio(), is(equalTo(0.5)));
+ assertThat(classToTest.getHybrid().getEmbedder(), is(equalTo("default")));
+ }
+
+ @Test
+ void toStringWithHybridAndOtherParameters() {
+ SearchRequest classToTest =
+ SearchRequest.builder()
+ .q("This is a Test")
+ .offset(200)
+ .limit(900)
+ .hybrid(
+ Hybrid.builder()
+ .semanticRatio(0.7)
+ .embedder("custom-embedder")
+ .build())
+ .build();
+
+ String expected =
+ "{\"q\":\"This is a Test\",\"hybrid\":{\"semanticRatio\":0.7,\"embedder\":\"custom-embedder\"},\"offset\":200,\"limit\":900}";
+ assertThat(classToTest.toString(), is(equalTo(expected)));
+ }
+
+ @Test
+ void toStringWithHybridOnlyEmbedder() {
+ SearchRequest classToTest =
+ new SearchRequest("This is a Test")
+ .setHybrid(Hybrid.builder().embedder("default").build());
+
+ String expected = "{\"q\":\"This is a Test\",\"hybrid\":{\"embedder\":\"default\"}}";
+ assertThat(classToTest.toString(), is(equalTo(expected)));
+ }
+
+ @Test
+ void toStringWithRetrieveVectors() {
+ SearchRequest searchRequest = new SearchRequest("test").setRetrieveVectors(true);
+ String result = searchRequest.toString();
+ JSONObject json = new JSONObject(result);
+ assertThat(json.getBoolean("retrieveVectors"), is(true));
+ }
}
diff --git a/src/test/java/com/meilisearch/sdk/SimilarDocumentRequestTest.java b/src/test/java/com/meilisearch/sdk/SimilarDocumentRequestTest.java
new file mode 100644
index 00000000..52435b82
--- /dev/null
+++ b/src/test/java/com/meilisearch/sdk/SimilarDocumentRequestTest.java
@@ -0,0 +1,184 @@
+package com.meilisearch.sdk;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+
+class SimilarDocumentRequestTest {
+
+ @Test
+ void toStringSimpleRequest() {
+ SimilarDocumentRequest classToTest = new SimilarDocumentRequest().setId("123");
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ }
+
+ @Test
+ void toStringWithEmbedder() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setEmbedder("custom");
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getString("embedder"), is(equalTo("custom")));
+ }
+
+ @Test
+ void toStringWithAttributesToRetrieve() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest()
+ .setId("123")
+ .setAttributesToRetrieve(new String[] {"title", "description"});
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(
+ jsonObject.getJSONArray("attributesToRetrieve").getString(0), is(equalTo("title")));
+ assertThat(
+ jsonObject.getJSONArray("attributesToRetrieve").getString(1),
+ is(equalTo("description")));
+ }
+
+ @Test
+ void toStringWithOffsetAndLimit() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setOffset(10).setLimit(20);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getInt("offset"), is(equalTo(10)));
+ assertThat(jsonObject.getInt("limit"), is(equalTo(20)));
+ }
+
+ @Test
+ void toStringWithFilter() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setFilter("genre = 'action'");
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getString("filter"), is(equalTo("genre = 'action'")));
+ }
+
+ @Test
+ void toStringWithShowRankingScore() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setShowRankingScore(true);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getBoolean("showRankingScore"), is(equalTo(true)));
+ }
+
+ @Test
+ void toStringWithShowRankingScoreDetails() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setShowRankingScoreDetails(true);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getBoolean("showRankingScoreDetails"), is(equalTo(true)));
+ }
+
+ @Test
+ void toStringWithRankingScoreThreshold() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setRankingScoreThreshold(0.5);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getDouble("rankingScoreThreshold"), is(equalTo(0.5)));
+ }
+
+ @Test
+ void toStringWithRetrieveVectors() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest().setId("123").setRetrieveVectors(true);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getBoolean("retrieveVectors"), is(equalTo(true)));
+ }
+
+ @Test
+ void toStringWithAllParameters() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest()
+ .setId("123")
+ .setEmbedder("custom")
+ .setAttributesToRetrieve(new String[] {"title", "description"})
+ .setOffset(10)
+ .setLimit(20)
+ .setFilter("genre = 'action'")
+ .setShowRankingScore(true)
+ .setShowRankingScoreDetails(true)
+ .setRankingScoreThreshold(0.5)
+ .setRetrieveVectors(true);
+
+ JSONObject jsonObject = new JSONObject(classToTest.toString());
+ assertThat(jsonObject.getString("id"), is(equalTo("123")));
+ assertThat(jsonObject.getString("embedder"), is(equalTo("custom")));
+ assertThat(
+ jsonObject.getJSONArray("attributesToRetrieve").getString(0), is(equalTo("title")));
+ assertThat(
+ jsonObject.getJSONArray("attributesToRetrieve").getString(1),
+ is(equalTo("description")));
+ assertThat(jsonObject.getInt("offset"), is(equalTo(10)));
+ assertThat(jsonObject.getInt("limit"), is(equalTo(20)));
+ assertThat(jsonObject.getString("filter"), is(equalTo("genre = 'action'")));
+ assertThat(jsonObject.getBoolean("showRankingScore"), is(equalTo(true)));
+ assertThat(jsonObject.getBoolean("showRankingScoreDetails"), is(equalTo(true)));
+ assertThat(jsonObject.getDouble("rankingScoreThreshold"), is(equalTo(0.5)));
+ assertThat(jsonObject.getBoolean("retrieveVectors"), is(equalTo(true)));
+ }
+
+ @Test
+ void gettersAndSetters() {
+ SimilarDocumentRequest classToTest =
+ new SimilarDocumentRequest()
+ .setId("123")
+ .setEmbedder("custom")
+ .setAttributesToRetrieve(new String[] {"title", "description"})
+ .setOffset(10)
+ .setLimit(20)
+ .setFilter("genre = 'action'")
+ .setShowRankingScore(true)
+ .setShowRankingScoreDetails(true)
+ .setRankingScoreThreshold(0.5)
+ .setRetrieveVectors(true);
+
+ assertThat(classToTest.getId(), is(equalTo("123")));
+ assertThat(classToTest.getEmbedder(), is(equalTo("custom")));
+ assertThat(
+ classToTest.getAttributesToRetrieve(),
+ is(equalTo(new String[] {"title", "description"})));
+ assertThat(classToTest.getOffset(), is(equalTo(10)));
+ assertThat(classToTest.getLimit(), is(equalTo(20)));
+ assertThat(classToTest.getFilter(), is(equalTo("genre = 'action'")));
+ assertThat(classToTest.getShowRankingScore(), is(equalTo(true)));
+ assertThat(classToTest.getShowRankingScoreDetails(), is(equalTo(true)));
+ assertThat(classToTest.getRankingScoreThreshold(), is(equalTo(0.5)));
+ assertThat(classToTest.getRetrieveVectors(), is(equalTo(true)));
+ }
+
+ @Test
+ void defaultValues() {
+ SimilarDocumentRequest classToTest = new SimilarDocumentRequest();
+
+ assertThat(classToTest.getId(), is(nullValue()));
+ assertThat(classToTest.getEmbedder(), is(nullValue()));
+ assertThat(classToTest.getAttributesToRetrieve(), is(nullValue()));
+ assertThat(classToTest.getOffset(), is(nullValue()));
+ assertThat(classToTest.getLimit(), is(nullValue()));
+ assertThat(classToTest.getFilter(), is(nullValue()));
+ assertThat(classToTest.getShowRankingScore(), is(nullValue()));
+ assertThat(classToTest.getShowRankingScoreDetails(), is(nullValue()));
+ assertThat(classToTest.getRankingScoreThreshold(), is(nullValue()));
+ assertThat(classToTest.getRetrieveVectors(), is(nullValue()));
+ }
+}