Skip to content

Commit 4c5c107

Browse files
authored
Merge pull request #1912 from meilisearch/feat/add-v1.14-features
Add v1.14.0 features
2 parents e6fd019 + aef4986 commit 4c5c107

12 files changed

Lines changed: 225 additions & 13 deletions

.code-samples.meilisearch.yaml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,14 @@ get_filterable_attributes_1: |-
528528
update_filterable_attributes_1: |-
529529
client.index('movies')
530530
.updateFilterableAttributes([
531-
'genres',
532-
'director'
531+
"genres",
532+
{
533+
attributePatterns: ["genre"],
534+
features: {
535+
facetSearch: true,
536+
filter: { equality: true, comparison: false },
537+
},
538+
}
533539
])
534540
reset_filterable_attributes_1: |-
535541
client.index('movies').resetFilterableAttributes()

src/indexes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,8 @@ export class Index<T extends RecordAny = RecordAny> {
782782
*
783783
* @returns Promise containing an array of filterable-attributes
784784
*/
785-
async getFilterableAttributes(): Promise<string[]> {
786-
return await this.httpRequest.get<string[]>({
785+
async getFilterableAttributes(): Promise<FilterableAttributes> {
786+
return await this.httpRequest.get<FilterableAttributes>({
787787
path: `indexes/${this.uid}/settings/filterable-attributes`,
788788
});
789789
}

src/types/task_and_batch.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ type BatchStats = {
168168
status: Record<TaskStatus, number>;
169169
types: Record<TaskType, number>;
170170
indexUids: Record<string, number>;
171+
progressTrace: Record<string, number>;
172+
// Do not type this field because the keys can change in a breaking way
173+
internalDatabaseSizes?: Record<string, number>;
171174
};
172175

173176
/**

src/types/types.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ export type Crop = {
183183
// `facetName` becomes mandatory when using `searchForFacetValues`
184184
export type SearchForFacetValuesParams = Omit<SearchParams, "facetName"> & {
185185
facetName: string;
186+
/**
187+
* If true, the facet search will return the exhaustive count of the facet
188+
* values.
189+
*/
190+
exhaustiveFacetCount?: boolean;
186191
};
187192

188193
export type FacetHit = {
@@ -469,6 +474,7 @@ export type RawDocumentAdditionOptions = DocumentOptions & {
469474
};
470475

471476
export type DocumentsQuery<T = RecordAny> = ResourceQuery & {
477+
ids?: string[] | number[];
472478
fields?: Fields<T>;
473479
filter?: Filter;
474480
limit?: number;
@@ -496,7 +502,17 @@ export type UpdateDocumentsByFunctionOptions = {
496502
** Settings
497503
*/
498504

499-
export type FilterableAttributes = string[] | null;
505+
type GranularFilterableAttribute = {
506+
attributePatterns: string[];
507+
features: {
508+
facetSearch: boolean;
509+
filter: { equality: boolean; comparison: boolean };
510+
};
511+
};
512+
513+
export type FilterableAttributes =
514+
| (string | GranularFilterableAttribute)[]
515+
| null;
500516
export type DistinctAttribute = string | null;
501517
export type SearchableAttributes = string[] | null;
502518
export type SortableAttributes = string[] | null;
@@ -541,6 +557,7 @@ export type HuggingFaceEmbedder = {
541557
revision?: string;
542558
documentTemplate?: string;
543559
distribution?: Distribution;
560+
pooling?: "useModel" | "forceMean" | "forceCls";
544561
documentTemplateMaxBytes?: number;
545562
binaryQuantized?: boolean;
546563
};
@@ -578,12 +595,19 @@ export type OllamaEmbedder = {
578595
binaryQuantized?: boolean;
579596
};
580597

598+
export type CompositeEmbedder = {
599+
source: "composite";
600+
searchEmbedder: Embedder;
601+
indexingEmbedder: Embedder;
602+
};
603+
581604
export type Embedder =
582605
| OpenAiEmbedder
583606
| HuggingFaceEmbedder
584607
| UserProvidedEmbedder
585608
| RestEmbedder
586609
| OllamaEmbedder
610+
| CompositeEmbedder
587611
| null;
588612

589613
export type Embedders = Record<string, Embedder> | null;

tests/__snapshots__/facet_search.test.ts.snap

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ exports[`Test on POST search > Admin key: basic facet value search 1`] = `
1717
}
1818
`;
1919

20+
exports[`Test on POST search > Admin key: facet value search with exhaustive facet count 1`] = `
21+
{
22+
"facetHits": [
23+
{
24+
"count": 1,
25+
"value": "adventure",
26+
},
27+
],
28+
"facetQuery": "a",
29+
"processingTimeMs": 0,
30+
}
31+
`;
32+
2033
exports[`Test on POST search > Admin key: facet value search with filter 1`] = `
2134
{
2235
"facetHits": [
@@ -85,6 +98,19 @@ exports[`Test on POST search > Master key: basic facet value search 1`] = `
8598
}
8699
`;
87100

101+
exports[`Test on POST search > Master key: facet value search with exhaustive facet count 1`] = `
102+
{
103+
"facetHits": [
104+
{
105+
"count": 1,
106+
"value": "adventure",
107+
},
108+
],
109+
"facetQuery": "a",
110+
"processingTimeMs": 0,
111+
}
112+
`;
113+
88114
exports[`Test on POST search > Master key: facet value search with filter 1`] = `
89115
{
90116
"facetHits": [
@@ -153,6 +179,19 @@ exports[`Test on POST search > Search key: basic facet value search 1`] = `
153179
}
154180
`;
155181

182+
exports[`Test on POST search > Search key: facet value search with exhaustive facet count 1`] = `
183+
{
184+
"facetHits": [
185+
{
186+
"count": 1,
187+
"value": "adventure",
188+
},
189+
],
190+
"facetQuery": "a",
191+
"processingTimeMs": 0,
192+
}
193+
`;
194+
156195
exports[`Test on POST search > Search key: facet value search with filter 1`] = `
157196
{
158197
"facetHits": [

tests/__snapshots__/settings.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ exports[`Test on settings > Admin key: Update embedders settings 1`] = `
268268
{% endif %}{% endfor %}",
269269
"documentTemplateMaxBytes": 400,
270270
"model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
271+
"pooling": "useModel",
271272
"source": "huggingFace",
272273
},
273274
},
@@ -958,6 +959,7 @@ exports[`Test on settings > Master key: Update embedders settings 1`] = `
958959
{% endif %}{% endfor %}",
959960
"documentTemplateMaxBytes": 400,
960961
"model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
962+
"pooling": "useModel",
961963
"source": "huggingFace",
962964
},
963965
},

tests/batch.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
3333
const batches = await client.batches.getBatches();
3434
const batch = await client.batches.getBatch(batches.results[0].uid);
3535
expect(batch.uid).toEqual(batches.results[0].uid);
36+
37+
// Can't use toMatchSnapshot because the output changes every time
3638
expect(batch.details).toBeDefined();
3739
expect(batch.stats).toHaveProperty("totalNbTasks");
3840
expect(batch.stats).toHaveProperty("status");
3941
expect(batch.stats).toHaveProperty("types");
4042
expect(batch.stats).toHaveProperty("indexUids");
43+
expect(batch.stats).toHaveProperty("progressTrace");
4144
expect(batch.duration).toBeDefined();
4245
expect(batch.startedAt).toBeDefined();
4346
expect(batch.finishedAt).toBeDefined();

tests/documents.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ describe("Documents tests", () => {
7979
expect(document.id).toBeUndefined();
8080
});
8181

82+
test(`${permission} key: Get multiple documents by IDs`, async () => {
83+
const client = await getClient(permission);
84+
await client.index(indexPk.uid).addDocuments(dataset).waitTask();
85+
86+
const documents = await client
87+
.index(indexPk.uid)
88+
.getDocuments<Book>({ ids: [1, 2] });
89+
90+
expect(documents.results.length).toEqual(2);
91+
expect(documents.results.map(({ id }) => id).sort()).toEqual([1, 2]);
92+
});
93+
8294
test(`${permission} key: Get documents with string fields`, async () => {
8395
const client = await getClient(permission);
8496

tests/embedders.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
BAD_HOST,
77
MeiliSearch,
88
getClient,
9+
getKey,
10+
HOST,
911
} from "./utils/meilisearch-test-utils.js";
1012

1113
const index = {
@@ -130,6 +132,7 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
130132
mean: 0.7,
131133
sigma: 0.3,
132134
},
135+
pooling: "useModel",
133136
documentTemplateMaxBytes: 500,
134137
binaryQuantized: false,
135138
},
@@ -235,6 +238,51 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
235238
expect(response).toEqual(newEmbedder);
236239
});
237240

241+
test(`${permission} key: Update embedders with composite embedder`, async () => {
242+
const adminKey = await getKey("Admin");
243+
244+
// first enable the network endpoint.
245+
await fetch(`${HOST}/experimental-features`, {
246+
body: JSON.stringify({ compositeEmbedders: true }),
247+
headers: {
248+
Authorization: `Bearer ${adminKey}`,
249+
"Content-Type": "application/json",
250+
},
251+
method: "PATCH",
252+
});
253+
254+
const client = await getClient(permission);
255+
const embedders = {
256+
default: {
257+
source: "composite",
258+
searchEmbedder: {
259+
source: "huggingFace",
260+
model:
261+
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
262+
pooling: "useModel",
263+
},
264+
indexingEmbedder: {
265+
source: "huggingFace",
266+
model:
267+
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
268+
documentTemplate: "{{doc.title}}",
269+
pooling: "useModel",
270+
documentTemplateMaxBytes: 500,
271+
},
272+
},
273+
} satisfies Embedders;
274+
275+
const task = await client
276+
.index(index.uid)
277+
.updateEmbedders(embedders)
278+
.waitTask();
279+
const response: Embedders = await client.index(index.uid).getEmbedders();
280+
281+
const processedTask = await client.tasks.getTask(task.uid);
282+
expect(processedTask.status).toEqual("succeeded");
283+
expect(response).toEqual(embedders);
284+
});
285+
238286
test(`${permission} key: Reset embedders`, async () => {
239287
const client = await getClient(permission);
240288
await client.index(index.uid).resetEmbedders().waitTask();

tests/facet_search.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,21 @@ describe.each([
9898
// @TODO: This is flaky, processingTimeMs is not guaranteed
9999
expect(response).toMatchSnapshot();
100100
});
101+
102+
test(`${permission} key: facet value search with exhaustive facet count`, async () => {
103+
const client = await getClient(permission);
104+
105+
const params = {
106+
facetName: "genres",
107+
facetQuery: "a",
108+
q: "Alice",
109+
exhaustiveFacetCount: true,
110+
};
111+
const response = await client.index(index.uid).searchForFacetValues(params);
112+
113+
// @TODO: This is flaky, processingTimeMs is not guaranteed
114+
expect(response).toMatchSnapshot();
115+
});
101116
});
102117

103118
afterAll(() => {

0 commit comments

Comments
 (0)