Skip to content

Commit cf7732e

Browse files
meili-bors[bot]jdvalenzuelahcurquiza
authored
Merge #761
761: Add similar documents query to index r=curquiza a=jdvalenzuelah # Pull Request ## Related issue Fixes #755 ## What does this PR do? - Add similar documents method to index ## PR checklist Please check if your PR fulfills the following requirements: - [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)? - [x] Have you read the contributing guidelines? - [x] Have you made sure that the title is accurate and descriptive of the changes? Thank you so much for contributing to Meilisearch! Co-authored-by: Josue Valenzuela <[email protected]> Co-authored-by: Clémentine <[email protected]>
2 parents 67e3467 + 1880805 commit cf7732e

File tree

13 files changed

+245
-27
lines changed

13 files changed

+245
-27
lines changed

.code-samples.meilisearch.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,3 +822,8 @@ multi_search_1: |-
822822
multiIndexSearch.addQuery(new IndexSearchRequest("movie_ratings").setQuery("us"));
823823
824824
client.multiSearch(multiSearchRequest);
825+
get_similar_post_1:
826+
SimilarDocumentRequest query = new SimilarDocumentRequest()
827+
.setId("143")
828+
.setEmbedder("manual");
829+
client.index("movies").searchSimilarDocuments(query)

src/main/java/com/meilisearch/sdk/Client.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ public Results<MultiSearchResult> multiSearch(MultiSearchRequest search)
434434
"/multi-search", search, Results.class, MultiSearchResult.class);
435435
}
436436

437+
public void experimentalFeatures(Map<String, Boolean> features) {
438+
this.config.httpClient.patch("/experimental-features", features, Void.class);
439+
}
440+
437441
public String generateTenantToken(String apiKeyUid, Map<String, Object> searchRules)
438442
throws MeilisearchException {
439443
return this.generateTenantToken(apiKeyUid, searchRules, new TenantTokenOptions());

src/main/java/com/meilisearch/sdk/Index.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
11
package com.meilisearch.sdk;
22

33
import com.meilisearch.sdk.exceptions.MeilisearchException;
4-
import com.meilisearch.sdk.model.DocumentQuery;
5-
import com.meilisearch.sdk.model.DocumentsQuery;
6-
import com.meilisearch.sdk.model.FacetSearchable;
7-
import com.meilisearch.sdk.model.Faceting;
8-
import com.meilisearch.sdk.model.IndexStats;
9-
import com.meilisearch.sdk.model.Pagination;
10-
import com.meilisearch.sdk.model.Results;
11-
import com.meilisearch.sdk.model.SearchResult;
12-
import com.meilisearch.sdk.model.Searchable;
13-
import com.meilisearch.sdk.model.Settings;
14-
import com.meilisearch.sdk.model.Task;
15-
import com.meilisearch.sdk.model.TaskInfo;
16-
import com.meilisearch.sdk.model.TasksQuery;
17-
import com.meilisearch.sdk.model.TasksResults;
18-
import com.meilisearch.sdk.model.TypoTolerance;
4+
import com.meilisearch.sdk.http.URLBuilder;
5+
import com.meilisearch.sdk.model.*;
196
import java.io.Serializable;
207
import java.util.ArrayList;
218
import java.util.List;
@@ -1214,4 +1201,12 @@ public TaskInfo updateSearchCutoffMsSettings(Integer milliseconds) throws Meilis
12141201
public TaskInfo resetSearchCutoffMsSettings() throws MeilisearchException {
12151202
return this.settingsHandler.resetSearchCutoffMsSettings(this.uid);
12161203
}
1204+
1205+
public SimilarDocumentsResults searchSimilarDocuments(SimilarDocumentRequest query)
1206+
throws MeilisearchException {
1207+
return this.config.httpClient.post(
1208+
new URLBuilder("/indexes").addSubroute(this.uid).addSubroute("/similar").getURL(),
1209+
query,
1210+
SimilarDocumentsResults.class);
1211+
}
12171212
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.meilisearch.sdk;
2+
3+
import lombok.*;
4+
import lombok.experimental.Accessors;
5+
import org.json.JSONObject;
6+
7+
@Builder
8+
@AllArgsConstructor(access = AccessLevel.PACKAGE)
9+
@Getter
10+
@Setter
11+
@Accessors(chain = true)
12+
public class SimilarDocumentRequest {
13+
private String id;
14+
private String embedder;
15+
private String[] attributesToRetrieve;
16+
private Integer offset;
17+
private Integer limit;
18+
private String filter;
19+
private Boolean showRankingScore;
20+
private Boolean showRankingScoreDetails;
21+
private Double rankingScoreThreshold;
22+
private Boolean retrieveVectors;
23+
24+
/**
25+
* Constructor for SimilarDocumentsRequest for building search request for similar documents
26+
* with the default values: id null, embedder "default", attributesToRetrieve ["*"], offset 0,
27+
* limit 20, filter null, showRankingScore false, showRankingScoreDetails false,
28+
* rankingScoreThreshold null, retrieveVectors false
29+
*/
30+
public SimilarDocumentRequest() {}
31+
32+
@Override
33+
public String toString() {
34+
JSONObject jsonObject =
35+
new JSONObject()
36+
.put("id", this.id)
37+
.put("embedder", this.embedder)
38+
.put("attributesToRetrieve", this.attributesToRetrieve)
39+
.put("offset", this.offset)
40+
.put("limit", this.limit)
41+
.put("filter", this.filter)
42+
.put("showRankingScore", this.showRankingScore)
43+
.put("showRankingScoreDetails", this.showRankingScoreDetails)
44+
.put("rankingScoreThreshold", this.rankingScoreThreshold)
45+
.put("retrieveVectors", this.retrieveVectors);
46+
47+
return jsonObject.toString();
48+
}
49+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.meilisearch.sdk.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
import com.google.gson.annotations.SerializedName;
5+
6+
public enum EmbedderInputType {
7+
@SerializedName("text")
8+
TEXT("text"),
9+
10+
@SerializedName("textArray")
11+
TEXT_ARRAY("textArray");
12+
13+
public final String inputType;
14+
15+
private EmbedderInputType(String inputType) {
16+
this.inputType = inputType;
17+
}
18+
19+
@JsonValue
20+
@Override
21+
public String toString() {
22+
return this.inputType;
23+
}
24+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.meilisearch.sdk.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
import com.google.gson.annotations.SerializedName;
5+
6+
public enum EmbedderSource {
7+
@SerializedName("openAi")
8+
OPEN_AI("openAi"),
9+
10+
@SerializedName("huggingFace")
11+
HUGGING_FACE("huggingFace"),
12+
13+
@SerializedName("ollama")
14+
OLLAMA("ollama"),
15+
16+
@SerializedName("rest")
17+
REST("rest"),
18+
19+
@SerializedName("userProvided")
20+
USER_PROVIDED("userProvided");
21+
22+
public final String source;
23+
24+
private EmbedderSource(String source) {
25+
this.source = source;
26+
}
27+
28+
@JsonValue
29+
@Override
30+
public String toString() {
31+
return this.source;
32+
}
33+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.meilisearch.sdk.model;
2+
3+
import lombok.*;
4+
import lombok.experimental.Accessors;
5+
6+
@Builder
7+
@AllArgsConstructor(access = AccessLevel.PACKAGE)
8+
@Getter
9+
@Setter
10+
@Accessors(chain = true)
11+
public class Embedders {
12+
protected EmbedderSource source;
13+
protected String url;
14+
protected String apiKey;
15+
protected String model;
16+
protected String documentTemplate;
17+
protected Integer dimensions;
18+
protected String revision;
19+
protected String[] inputField;
20+
protected EmbedderInputType inputType;
21+
protected String query;
22+
23+
public Embedders() {}
24+
}

src/main/java/com/meilisearch/sdk/model/Settings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class Settings {
3131
protected Integer searchCutoffMs;
3232
protected String[] separatorTokens;
3333
protected String[] nonSeparatorTokens;
34+
protected HashMap<String, Embedders> embedders;
3435

3536
public Settings() {}
3637
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.meilisearch.sdk.model;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import lombok.Getter;
6+
import lombok.ToString;
7+
8+
/**
9+
* Meilisearch similar documents results data structure
10+
*
11+
* @see <a href="https://www.meilisearch.com/docs/reference/api/similar#response-200-ok">API
12+
* specification</a>
13+
*/
14+
@Getter
15+
@ToString
16+
public class SimilarDocumentsResults {
17+
ArrayList<HashMap<String, Object>> hits;
18+
String id;
19+
int processingTimeMs;
20+
int offset;
21+
int limit;
22+
int estimatedTotalHits;
23+
}

src/test/java/com/meilisearch/integration/SearchTest.java

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,11 @@
1313

1414
import com.meilisearch.integration.classes.AbstractIT;
1515
import com.meilisearch.integration.classes.TestData;
16-
import com.meilisearch.sdk.Index;
17-
import com.meilisearch.sdk.IndexSearchRequest;
18-
import com.meilisearch.sdk.MultiSearchRequest;
19-
import com.meilisearch.sdk.SearchRequest;
16+
import com.meilisearch.sdk.*;
2017
import com.meilisearch.sdk.json.GsonJsonHandler;
21-
import com.meilisearch.sdk.model.FacetRating;
22-
import com.meilisearch.sdk.model.MatchingStrategy;
23-
import com.meilisearch.sdk.model.MultiSearchResult;
24-
import com.meilisearch.sdk.model.SearchResult;
25-
import com.meilisearch.sdk.model.SearchResultPaginated;
26-
import com.meilisearch.sdk.model.Searchable;
27-
import com.meilisearch.sdk.model.Settings;
28-
import com.meilisearch.sdk.model.TaskInfo;
18+
import com.meilisearch.sdk.model.*;
2919
import com.meilisearch.sdk.utils.Movie;
20+
import java.util.ArrayList;
3021
import java.util.HashMap;
3122
import java.util.HashSet;
3223
import org.junit.jupiter.api.AfterAll;
@@ -843,4 +834,38 @@ public void testMultiSearchWithRankingScoreThreshold() throws Exception {
843834
assertThat(rankingScore, is(greaterThanOrEqualTo(0.98)));
844835
}
845836
}
837+
838+
@Test
839+
public void testSimilarDocuments() throws Exception {
840+
HashMap<String, Boolean> features = new HashMap();
841+
features.put("vectorStore", true);
842+
client.experimentalFeatures(features);
843+
844+
String indexUid = "SimilarDocuments";
845+
Index index = client.index(indexUid);
846+
HashMap<String, Embedders> embedders = new HashMap<>();
847+
embedders.put(
848+
"manual", new Embedders().setSource(EmbedderSource.USER_PROVIDED).setDimensions(3));
849+
850+
Settings settings = new Settings();
851+
settings.setEmbedders(embedders);
852+
853+
index.updateSettings(settings);
854+
855+
TestData<Movie> testData = this.getTestData(VECTOR_MOVIES, Movie.class);
856+
TaskInfo task = index.addDocuments(testData.getRaw());
857+
858+
index.waitForTask(task.getTaskUid());
859+
860+
SimilarDocumentsResults results =
861+
index.searchSimilarDocuments(
862+
new SimilarDocumentRequest().setId("143").setEmbedder("manual"));
863+
864+
ArrayList<HashMap<String, Object>> hits = results.getHits();
865+
assertThat(hits.size(), is(4));
866+
assertThat(hits.get(0).get("title"), is("Escape Room"));
867+
assertThat(hits.get(1).get("title"), is("Captain Marvel"));
868+
assertThat(hits.get(2).get("title"), is("How to Train Your Dragon: The Hidden World"));
869+
assertThat(hits.get(3).get("title"), is("Shazam!"));
870+
}
846871
}

0 commit comments

Comments
 (0)