Skip to content

Commit f93c639

Browse files
meili-bors[bot]consoleLogItStriftflevi29
authored
Merge #1891
1891: Implement the experimental feature for remote federated search requests. r=Strift a=consoleLogIt # Pull Request ## Related issue Fixes #1872 ## What does this PR do? Implement the experimental feature for [remote federated search requests](https://www.meilisearch.com/docs/learn/multi_search/implement_sharding?utm_campaign=oss&utm_source=github). ## 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: consoleLogIt <[email protected]> Co-authored-by: Laurent Cazanove <[email protected]> Co-authored-by: F. Levi <[email protected]>
2 parents d6446f5 + 9bd16a5 commit f93c639

File tree

4 files changed

+158
-2
lines changed

4 files changed

+158
-2
lines changed

src/meilisearch.ts

+50-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
BatchesResults,
2929
BatchesQuery,
3030
MultiSearchResponseOrSearchResponse,
31+
Network,
3132
} from "./types.js";
3233
import { ErrorStatusCode } from "./types.js";
3334
import { HttpRequests } from "./http-requests.js";
@@ -201,7 +202,8 @@ export class MeiliSearch {
201202
* Perform multiple search queries.
202203
*
203204
* It is possible to make multiple search queries on the same index or on
204-
* different ones
205+
* different ones. With network feature enabled, you can also search across
206+
* remote instances.
205207
*
206208
* @example
207209
*
@@ -212,11 +214,33 @@ export class MeiliSearch {
212214
* { indexUid: "books", q: "flower" },
213215
* ],
214216
* });
217+
*
218+
* // Federated search with remote instance (requires network feature enabled)
219+
* client.multiSearch({
220+
* federation: {},
221+
* queries: [
222+
* {
223+
* indexUid: "movies",
224+
* q: "wonder",
225+
* federationOptions: {
226+
* remote: "meilisearch instance name",
227+
* },
228+
* },
229+
* {
230+
* indexUid: "movies",
231+
* q: "wonder",
232+
* federationOptions: {
233+
* remote: "meilisearch instance name",
234+
* },
235+
* },
236+
* ],
237+
* });
215238
* ```
216239
*
217240
* @param queries - Search queries
218241
* @param extraRequestInit - Additional request configuration options
219242
* @returns Promise containing the search responses
243+
* @see {@link https://www.meilisearch.com/docs/learn/multi_search/implement_sharding#perform-a-search}
220244
*/
221245
async multiSearch<
222246
T1 extends MultiSearchParams | FederatedMultiSearchParams,
@@ -234,6 +258,31 @@ export class MeiliSearch {
234258
});
235259
}
236260

261+
///
262+
/// Network
263+
///
264+
265+
/**
266+
* {@link https://www.meilisearch.com/docs/reference/api/network#get-the-network-object}
267+
*
268+
* @experimental
269+
*/
270+
async getNetwork(): Promise<Network> {
271+
return await this.httpRequest.get({ path: "network" });
272+
}
273+
274+
/**
275+
* {@link https://www.meilisearch.com/docs/reference/api/network#update-the-network-object}
276+
*
277+
* @experimental
278+
*/
279+
async updateNetwork(network: Partial<Network>): Promise<Network> {
280+
return await this.httpRequest.patch({
281+
path: "network",
282+
body: network,
283+
});
284+
}
285+
237286
///
238287
/// TASKS
239288
///

src/types.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export type MergeFacets = {
253253
maxValuesPerFacet?: number | null;
254254
};
255255

256-
export type FederationOptions = { weight: number };
256+
export type FederationOptions = { weight: number; remote?: string };
257257
export type MultiSearchFederation = {
258258
limit?: number;
259259
offset?: number;
@@ -274,6 +274,26 @@ export type FederatedMultiSearchParams = {
274274
queries: MultiSearchQueryWithFederation[];
275275
};
276276

277+
/**
278+
* {@link https://www.meilisearch.com/docs/reference/api/network#the-remote-object}
279+
*
280+
* @see `meilisearch_types::features::Remote` at {@link https://github.com/meilisearch/meilisearch}
281+
*/
282+
export type Remote = {
283+
url: string;
284+
searchApiKey: string | null;
285+
};
286+
287+
/**
288+
* {@link https://www.meilisearch.com/docs/reference/api/network#the-network-object}
289+
*
290+
* @see `meilisearch_types::features::Network` at {@link https://github.com/meilisearch/meilisearch}
291+
*/
292+
export type Network = {
293+
self: string | null;
294+
remotes: Record<string, Remote>;
295+
};
296+
277297
export type CategoriesDistribution = {
278298
[category: string]: number;
279299
};

tests/client.test.ts

+32
Original file line numberDiff line numberDiff line change
@@ -899,3 +899,35 @@ describe.each([
899899
);
900900
});
901901
});
902+
903+
describe.each([{ permission: "Master" }])(
904+
"Test network methods",
905+
({ permission }) => {
906+
const instanceName = "instance_1";
907+
908+
test(`${permission} key: Update and get network settings`, async () => {
909+
const client = await getClient(permission);
910+
911+
const instances = {
912+
[instanceName]: {
913+
url: "http://instance-1:7700",
914+
searchApiKey: "search-key-1",
915+
},
916+
};
917+
918+
await client.updateNetwork({ self: instanceName, remotes: instances });
919+
const response = await client.getNetwork();
920+
expect(response).toHaveProperty("self", instanceName);
921+
expect(response).toHaveProperty("remotes");
922+
expect(response.remotes).toHaveProperty("instance_1");
923+
expect(response.remotes["instance_1"]).toHaveProperty(
924+
"url",
925+
instances[instanceName].url,
926+
);
927+
expect(response.remotes["instance_1"]).toHaveProperty(
928+
"searchApiKey",
929+
instances[instanceName].searchApiKey,
930+
);
931+
});
932+
},
933+
);

tests/search.test.ts

+55
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
getClient,
2323
datasetWithNests,
2424
getKey,
25+
HOST,
2526
} from "./utils/meilisearch-test-utils.js";
2627

2728
const index = {
@@ -235,6 +236,60 @@ describe.each([
235236
expect(response2.hits[0].id).toEqual(1344);
236237
});
237238

239+
test(`${permission} key: Multi index search with federation and remote`, async () => {
240+
const adminKey = await getKey("Admin");
241+
242+
// first enable the network endpoint.
243+
await fetch(`${HOST}/experimental-features`, {
244+
body: JSON.stringify({ network: true }),
245+
headers: {
246+
Authorization: `Bearer ${adminKey}`,
247+
"Content-Type": "application/json",
248+
},
249+
method: "PATCH",
250+
});
251+
252+
const masterClient = await getClient("Master");
253+
254+
const searchKey = await getKey("Search");
255+
256+
// set the remote name and instances
257+
const instanceName = "instance_1";
258+
await masterClient.updateNetwork({
259+
self: instanceName,
260+
remotes: { [instanceName]: { url: HOST, searchApiKey: searchKey } },
261+
});
262+
263+
const searchClient = await getClient(permission);
264+
265+
const response = await searchClient.multiSearch<
266+
FederatedMultiSearchParams,
267+
Books | { id: number; asd: string }
268+
>({
269+
federation: {},
270+
queries: [
271+
{
272+
indexUid: index.uid,
273+
q: "456",
274+
attributesToSearchOn: ["id"],
275+
federationOptions: { weight: 1, remote: instanceName },
276+
},
277+
{
278+
indexUid: index.uid,
279+
q: "1344",
280+
federationOptions: { weight: 0.9, remote: instanceName },
281+
attributesToSearchOn: ["id"],
282+
},
283+
],
284+
});
285+
286+
expect(response).toHaveProperty("hits");
287+
expect(Array.isArray(response.hits)).toBe(true);
288+
expect(response.hits.length).toEqual(2);
289+
expect(response.hits[0].id).toEqual(456);
290+
expect(response.hits[0]._federation).toHaveProperty("remote", instanceName);
291+
});
292+
238293
test(`${permission} key: Multi search with facetsByIndex`, async () => {
239294
const client = await getClient(permission);
240295
const masterClient = await getClient("Master");

0 commit comments

Comments
 (0)