Skip to content

Add AI-powered search features #827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d73b322
Initial devcontainer setup
Strift Mar 13, 2025
5ddb097
Use gradle inside devcontainer
Strift Mar 13, 2025
45026c8
Add embedders settings
Strift Mar 9, 2025
74ed1f2
Run spotless
Strift Mar 12, 2025
d47e0f6
Add hybrid parameter
Strift Mar 12, 2025
426f605
Fix null embedder test
Strift Mar 12, 2025
a209989
Remove devcontainer
Strift Mar 18, 2025
08a7684
Rename embedder and add EmbedderDistirbution class
Strift Mar 18, 2025
2ba68af
Update embedders distribution test
Strift Mar 18, 2025
807a2b6
Lint
Strift Mar 18, 2025
6b4a620
Update test
Strift Mar 18, 2025
de3a46d
Temporarily add more info to tests
Strift Mar 18, 2025
132e191
Remove document template edition
Strift Mar 18, 2025
405a0e9
Update reset embedder test
Strift Mar 18, 2025
c52fc85
Update rest embedder test
Strift Mar 18, 2025
5514722
Create RestEmbedder class
Strift Mar 18, 2025
930aa39
Delete RestEmbedder class for consistency
Strift Mar 18, 2025
dc7ba8d
Remove error prones embedders
Strift Mar 18, 2025
b7b8506
Clean up tests
Strift Mar 18, 2025
3c53bca
Lint
Strift Mar 18, 2025
6bb3106
Add vector search test
Strift Mar 18, 2025
9c76f88
Add hybrid
Strift Mar 18, 2025
40fa243
Fix tasks test
Strift Apr 8, 2025
cefaf25
Add retrieveVectors
Strift Apr 8, 2025
4306308
Spotless
Strift Apr 8, 2025
b8b3c88
Add check for optional _vectors
Strift Apr 8, 2025
22482fb
Add tests for similar documents
Strift Apr 8, 2025
3c93870
Merge branch 'main' into feat/add-ai-powered-search
Strift Apr 24, 2025
35d1ec7
Update src/main/java/com/meilisearch/sdk/SearchRequest.java
Strift Apr 24, 2025
93c73f5
Add javadoc
Strift Apr 24, 2025
875d73d
Remove unnecessary test
Strift May 15, 2025
fc83d3d
Replace repetitive code by loop
Strift May 15, 2025
44adc3f
Add comment on annotations
Strift May 15, 2025
b923f5e
id and embedder are not optional fields
Strift May 15, 2025
f873afe
Remove unnecessary tests
Strift May 15, 2025
af662a0
Lint
Strift May 15, 2025
8cef5d3
Lint
Strift May 15, 2025
f084169
Lint
Strift May 15, 2025
5e7a4d6
Merge branch 'main' into feat/add-ai-powered-search
Strift May 15, 2025
75c7d74
Use createIndex instead of createEmptyIndex
Strift May 15, 2025
10701ee
Remove comment
Strift May 15, 2025
5a29190
lint
Strift May 21, 2025
b91b92b
Merge branch 'main' into feat/add-ai-powered-search
Strift Jun 2, 2025
9272e76
Update tests to use empty index
Strift Jun 5, 2025
1b24185
Merge branch 'main' into feat/add-ai-powered-search
Strift Jun 5, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/com/meilisearch/sdk/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -1242,11 +1242,57 @@ public TaskInfo resetSearchCutoffMsSettings() throws MeilisearchException {
return this.settingsHandler.resetSearchCutoffMsSettings(this.uid);
}

/**
* Retrieves documents that are semantically similar to a given document
*
* @param query SimilarDocumentRequest containing parameters for the similar documents search
* @return SimilarDocumentsResults containing the search results
* @throws MeilisearchException if an error occurs
* @see <a href="https://www.meilisearch.com/docs/reference/api/similar">API specification</a>
*/
public SimilarDocumentsResults searchSimilarDocuments(SimilarDocumentRequest query)
throws MeilisearchException {
return this.config.httpClient.post(
new URLBuilder("/indexes").addSubroute(this.uid).addSubroute("/similar").getURL(),
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 <a href="https://www.meilisearch.com/docs/reference/api/settings#get-embedders">API
* specification</a>
*/
public Map<String, Embedder> 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 <a href="https://www.meilisearch.com/docs/reference/api/settings#update-embedders">API
* specification</a>
*/
public TaskInfo updateEmbeddersSettings(Map<String, Embedder> 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 <a href="https://www.meilisearch.com/docs/reference/api/settings#reset-embedders">API
* specification</a>
*/
public TaskInfo resetEmbeddersSettings() throws MeilisearchException {
return this.settingsHandler.resetEmbedders(this.uid);
}
}
6 changes: 4 additions & 2 deletions src/main/java/com/meilisearch/sdk/IndexSearchRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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();
}
Expand Down
16 changes: 13 additions & 3 deletions src/main/java/com/meilisearch/sdk/SearchRequest.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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();
}
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/com/meilisearch/sdk/SettingsHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, Embedder> 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<String, Embedder> 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);
}
}
30 changes: 12 additions & 18 deletions src/main/java/com/meilisearch/sdk/SimilarDocumentRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,22 @@ public class SimilarDocumentRequest {
private Double rankingScoreThreshold;
private Boolean retrieveVectors;

/**
* Constructor for SimilarDocumentsRequest for building search request for similar documents
* with the default values: id null, embedder "default", attributesToRetrieve ["*"], offset 0,
* limit 20, filter null, showRankingScore false, showRankingScoreDetails false,
* rankingScoreThreshold null, retrieveVectors false
*/
/** Constructor for SimilarDocumentsRequest for building search request for similar documents */
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.put("id", this.id);
jsonObject.put("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();
}
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/com/meilisearch/sdk/model/Embedder.java
Original file line number Diff line number Diff line change
@@ -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<String, Object> request;

/** Response configuration. Mandatory only when using rest embedder, optional otherwise. */
protected Map<String, Object> 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<String, String> 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() {}
}
56 changes: 56 additions & 0 deletions src/main/java/com/meilisearch/sdk/model/EmbedderDistribution.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
24 changes: 0 additions & 24 deletions src/main/java/com/meilisearch/sdk/model/Embedders.java

This file was deleted.

Loading