Skip to content
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

feat: added sample script for multisearch #657

Merged
merged 10 commits into from
Dec 7, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added
- Added deprecation warnings for Index Template APIs ([654](https://github.com/opensearch-project/opensearch-js/pull/645))
- Added `http` functions: `connect`, `delete`, `get`, `head`, `options`, `patch`, `post`, `put`, and `trace` ([#649](https://github.com/opensearch-project/opensearch-js/pull/649))
- Added `samples/msearch.js` and `guides/msearch.md` to provide example to multi-search functionality ([#657](https://github.com/opensearch-project/opensearch-js/pull/656))
tejeshreddy marked this conversation as resolved.
Show resolved Hide resolved
- Added `samples/search.js` and updated `guides/search.md` to provide example to search functionality ([#656](https://github.com/opensearch-project/opensearch-js/pull/656))
### Dependencies
- Bumps `@aws-sdk/types` from 3.418.0 to 3.451.0
Expand Down
63 changes: 63 additions & 0 deletions guides/msearch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Multi-Search (msearch)

OpenSearch's Multi-Search (`msearch`) API is a tool that allows you to execute multiple search operations for documents within an index efficiently. This API supports various parameters that provide flexibility in customizing your search operations. It's crucial to understand the key differences between `msearch` and a regular `search` operation in OpenSearch. Unlike a single search operation, `msearch` enables you to perform multiple searches in a single API call, significantly reducing network overhead as it need not initialize a new network connection for each search. This proves particularly advantageous for batch operations or scenarios where searches span multiple indices. By combining searches into one request, `msearch` streamlines the process and enhances overall efficiency. Explore the functionalities of the msearch API with the provided sample code in [../samples/msearch.js](../samples/msearch.js).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"is a tool that allows you to" -> "allows you to", it's an API, not a tool :)

I'd be curious to hear what the downsides of msearch are. For example, does msearch require the caller to examine errors themselves?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be curious to hear what the downsides of msearch are. For example, does msearch require the caller to examine errors themselves?

@dblock did you mean to say this could be one of the disadvantages? I will include a couple of cons related to msearch in comparison to search

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a con I came across when reading about the difference in both.

does msearch require the caller to examine errors themselves?

For the above point, I wasn't able to find anything substantial. It would be great if you could link doc/resources so I can add it to the guide.


# Setup

```javascript
const host = "localhost";
const protocol = "https";
const port = 9200;
const auth = "admin:admin";
const ca_certs_path = "/full/path/to/root-ca.pem";
const { Client } = require("@opensearch-project/opensearch");
const fs = require("fs");
const client = new Client({
node: `${protocol}://${auth}@${host}:${port}`,
ssl: {
ca: fs.readFileSync(ca_certs_path),
},
});

await client.bulk({
body: [
{ index: { _index: 'movies', _id: 1 } },
{ title: 'The Godfather', director: 'Francis Ford Coppola', year: 1972 },
{ index: { _index: 'movies', _id: 2 } },
{ title: 'The Godfather: Part II', director: 'Francis Ford Coppola', year: 1974 },
],
});

await client.index.refresh({ index: 'movies' });
```

# Multi Search API
### Basic Multi Search
tejeshreddy marked this conversation as resolved.
Show resolved Hide resolved

The multi-search allows you to execute multiple search requests within a single API call. The following example shows how each search query provides a list of documents from the movie index.

```javascript
const queries = [
{},
{ query: { match: { title: 'The Godfather' } } },
{},
{ query: { match: { title: 'Part II' } } },
];

const multiSearchResponse = await client.msearch({
index: 'movies',
body: queries,
});

multiSearchResponse.body.responses.map((res) =>
res.hits.hits.map((movie) => {
console.log(movie._source);
})
);
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me what happens in case of errors? Does the user have to handle that, and if so how? I think the sample should explicitly call it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a try-catch block in the code snippet. Please let me know if there is anything else you're referring to here.


# Cleanup

```javascript
await client.indices.delete({index: 'movies'});
```
130 changes: 130 additions & 0 deletions samples/msearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
const { Client } = require('@opensearch-project/opensearch');

const client = new Client({
ssl: {
rejectUnauthorized: false,
},
node: 'https://localhost:9200',
auth: {
username: 'admin',
password: 'admin',
},
});

const printResponse = (title, body) => {
console.log(`\n${title}:`);
console.log(body);
};

const handleErrorResponse = (error) => {
if (error.meta && error.meta.body) {
console.error('Error:', error.meta.body.error);
} else {
console.error('Error:', error.message);
}
};

const refreshIndex = async (indexName) => {
try {
const response = await client.indices.refresh({
index: indexName,
});
printResponse(`Refresh response for index ${indexName}`, response.body);
} catch (error) {
handleErrorResponse(error);
}
};

const deleteIndexIfExists = async (indexName) => {
const indexExistsResponse = await client.indices.exists({ index: indexName });
if (indexExistsResponse.statusCode === 200) {
const response = await client.indices.delete({ index: indexName });
printResponse(`Delete existing \`${indexName}\` Index`, response.body);
}
};

const createMoviesIndex = async () => {
const response = await client.indices.create({
index: 'movies',
body: {
mappings: {
properties: {
title: { type: 'text' },
director: { type: 'text' },
year: { type: 'integer' },
},
},
},
});
printResponse('Create `movies` Index', response.body);
};

const addDocumentsToMoviesIndex = async () => {
const response = await client.bulk({
body: [
{ index: { _index: 'movies', _id: 1 } },
{ title: 'The Godfather', director: 'Francis Ford Coppola', year: 1972 },
{ index: { _index: 'movies', _id: 2 } },
{ title: 'The Godfather: Part II', director: 'Francis Ford Coppola', year: 1974 },
],
});
printResponse('Add documents to the `movies` Index using the Bulk API', response.body);
};

const multiSearchExample = async () => {
const queries = [
{},
{
query: { match: { title: 'The Godfather' } },
},
{},
{
query: { match: { title: 'Part II' } },
},
];

const multiSearchResponse = await client.msearch({
index: 'movies',
body: queries,
});

printResponse(
'MultiSearch Response',
multiSearchResponse.body.responses.map((res) => res.hits.hits.map((movie) => movie._source))
);
};

const deleteMoviesIndex = async () => {
const response = await client.indices.delete({ index: 'movies' });
printResponse('Delete `movies` Index', response.body);
};

const start = async () => {
try {
await deleteIndexIfExists('movies');
await createMoviesIndex();
await addDocumentsToMoviesIndex();

// Refresh the 'movies' index
await refreshIndex('movies');

// Multi-search example
await multiSearchExample();

// Delete the 'movies' index
await deleteMoviesIndex();
} catch (error) {
handleErrorResponse(error);
}
};

start();
Loading