Skip to content

Commit 3be2aaf

Browse files
committed
Use the multiSearch api instead of multiple individual searches for Meilisearch v1.1.0 (#1038)
1 parent cb4b051 commit 3be2aaf

File tree

19 files changed

+372
-204
lines changed

19 files changed

+372
-204
lines changed

.changeset/fresh-countries-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@meilisearch/instant-meilisearch": minor
3+
---
4+
5+
Replaces search with multiSearch API.

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,6 @@ const search = instantsearch({
350350

351351
`Index` is the component that lets you apply widgets to a dedicated index. It’s useful if you want to build an interface that targets multiple indices.
352352

353-
Using this component, instant-meilisearch does an http-request for each different `Index` widget added. More http requests are made when using the [`RefinementList`](#✅-refinementlist) widget.
354-
355353
### ✅ SearchBox
356354

357355
[SearchBox references](https://www.algolia.com/doc/api-reference/widgets/search-box/js/)
@@ -675,9 +673,6 @@ The `refinementList` widget is one of the most common widgets you can find in a
675673
- ✅ templates: The templates to use for the widget.
676674
- ✅ cssClasses: The CSS classes to override.
677675

678-
The `RefinementList` widget uses the `disjunctive facet search` principle when using the `or` operator. For each different facet category used, an additional http call is made.
679-
For example, if I ask for `color=green` and `size=2`, three http requests are made. One for the hits, one for the `color` facet distribution, and one for the `size` facet distribution. To provide feedback on the subject, refer to [this discussion](https://github.com/meilisearch/product/issues/54).
680-
681676
The following example will create a UI component with the a list of genres on which you will be able to facet.
682677

683678
```js

packages/instant-meilisearch/__tests__/search-resolver.test.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { instantMeiliSearch } from '../src'
33
import { MeiliSearch } from 'meilisearch'
44
import { mocked } from 'ts-jest/utils'
55
import { PACKAGE_VERSION } from '../src/package-version'
6+
import { MeiliSearchMultiSearchParams } from '../src/types'
67

78
jest.mock('meilisearch')
89

@@ -18,19 +19,22 @@ export const searchResponse = {
1819

1920
// Mocking of Meilisearch package
2021
const mockedMeilisearch = mocked(MeiliSearch, true)
21-
const mockedSearch = jest.fn(() => searchResponse)
22-
const mockedIndex = jest.fn(() => {
22+
const mockedMultiSearch = jest.fn((request) => {
23+
const response = request.queries.map((req: MeiliSearchMultiSearchParams) => ({
24+
...searchResponse,
25+
indexUid: req.indexUid,
26+
}))
2327
return {
24-
search: mockedSearch,
28+
results: response,
2529
}
2630
})
2731

2832
mockedMeilisearch.mockReturnValue({
2933
// @ts-ignore
30-
index: mockedIndex,
34+
multiSearch: mockedMultiSearch,
3135
})
3236

33-
describe('Pagination browser test', () => {
37+
describe('Cached search tests', () => {
3438
afterEach(() => {
3539
jest.clearAllMocks()
3640
})
@@ -51,7 +55,7 @@ describe('Pagination browser test', () => {
5155
apiKey: '',
5256
clientAgents: [`Meilisearch instant-meilisearch (v${PACKAGE_VERSION})`],
5357
})
54-
expect(mockedSearch).toHaveBeenCalledTimes(2)
58+
expect(mockedMultiSearch).toHaveBeenCalledTimes(2)
5559
})
5660

5761
test('two different search parameters', async () => {
@@ -77,7 +81,7 @@ describe('Pagination browser test', () => {
7781
apiKey: '',
7882
clientAgents: [`Meilisearch instant-meilisearch (v${PACKAGE_VERSION})`],
7983
})
80-
expect(mockedSearch).toHaveBeenCalledTimes(3)
84+
expect(mockedMultiSearch).toHaveBeenCalledTimes(3)
8185
})
8286

8387
test('two identical and one different search parameters', async () => {
@@ -104,7 +108,7 @@ describe('Pagination browser test', () => {
104108
apiKey: '',
105109
clientAgents: [`Meilisearch instant-meilisearch (v${PACKAGE_VERSION})`],
106110
})
107-
expect(mockedSearch).toHaveBeenCalledTimes(3)
111+
expect(mockedMultiSearch).toHaveBeenCalledTimes(3)
108112
})
109113

110114
test('two same and two different search parameter', async () => {
@@ -132,6 +136,43 @@ describe('Pagination browser test', () => {
132136
apiKey: '',
133137
clientAgents: [`Meilisearch instant-meilisearch (v${PACKAGE_VERSION})`],
134138
})
135-
expect(mockedSearch).toHaveBeenCalledTimes(3)
139+
expect(mockedMultiSearch).toHaveBeenCalledTimes(3)
140+
})
141+
142+
test('Multiple search parameters on different index uids', async () => {
143+
const searchParameters1 = [
144+
{
145+
indexName: 'movies',
146+
params: {
147+
query: '',
148+
},
149+
},
150+
{
151+
indexName: 'game',
152+
params: {
153+
query: '',
154+
},
155+
},
156+
]
157+
158+
const searchParameters2 = {
159+
indexName: 'movies',
160+
params: {
161+
query: 'other query',
162+
},
163+
}
164+
const searchClient = instantMeiliSearch('http://localhost:7700')
165+
await searchClient.search<Movies>(searchParameters1)
166+
await searchClient.search<Movies>([searchParameters2])
167+
await searchClient.search<Movies>(searchParameters1)
168+
await searchClient.search<Movies>([searchParameters2])
169+
170+
expect(mockedMeilisearch).toHaveBeenCalledWith({
171+
host: 'http://localhost:7700',
172+
apiKey: '',
173+
clientAgents: [`Meilisearch instant-meilisearch (v${PACKAGE_VERSION})`],
174+
})
175+
176+
expect(mockedMultiSearch).toHaveBeenCalledTimes(3)
136177
})
137178
})

packages/instant-meilisearch/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"templates"
4848
],
4949
"dependencies": {
50-
"meilisearch": "^0.31.1"
50+
"meilisearch": "0.32.0-v1.1.0-pre-release.0"
5151
},
5252
"devDependencies": {
5353
"@babel/cli": "^7.21.0",

packages/instant-meilisearch/src/adapter/search-request-adapter/search-params-adapter.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type {
2-
MeiliSearchParams,
32
SearchContext,
43
Filter,
54
PaginationState,
5+
MeiliSearchMultiSearchParams,
66
} from '../../types'
77

88
import {
@@ -72,7 +72,7 @@ function setFinitePagination(
7272
* @returns {MeiliSearchParams}
7373
*/
7474
export function MeiliParamsCreator(searchContext: SearchContext) {
75-
const meiliSearchParams: Record<string, any> = {}
75+
const meiliSearchParams: any = {}
7676
const {
7777
facets,
7878
attributesToSnippet,
@@ -89,14 +89,21 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
8989
filters,
9090
numericFilters,
9191
facetFilters,
92+
indexUid,
9293
} = searchContext
9394

9495
const meilisearchFilters = adaptFilters(filters, numericFilters, facetFilters)
9596

9697
return {
97-
getParams() {
98+
getParams(): MeiliSearchMultiSearchParams {
9899
return meiliSearchParams
99100
},
101+
addQuery() {
102+
meiliSearchParams.q = query
103+
},
104+
addIndexUid() {
105+
meiliSearchParams.indexUid = indexUid
106+
},
100107
addFacets() {
101108
if (Array.isArray(facets)) {
102109
meiliSearchParams.facets = facets
@@ -194,12 +201,14 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
194201
* to search request compliant with Meilisearch
195202
*
196203
* @param {SearchContext} searchContext
197-
* @returns {MeiliSearchParams}
204+
* @returns {MeiliSearchMultiSearchParams}
198205
*/
199206
export function adaptSearchParams(
200207
searchContext: SearchContext
201-
): MeiliSearchParams {
208+
): MeiliSearchMultiSearchParams {
202209
const meilisearchParams = MeiliParamsCreator(searchContext)
210+
meilisearchParams.addQuery()
211+
meilisearchParams.addIndexUid()
203212
meilisearchParams.addFacets()
204213
meilisearchParams.addAttributesToHighlight()
205214
meilisearchParams.addPreTag()
Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
2-
SearchContext,
32
MeiliSearch,
4-
MeiliSearchResponse,
53
SearchCacheInterface,
6-
MeiliSearchParams,
4+
MeiliSearchMultiSearchParams,
5+
MeilisearchMultiSearchResult,
6+
PaginationState,
77
} from '../../types'
88

99
/**
@@ -14,37 +14,35 @@ export function SearchResolver(
1414
cache: SearchCacheInterface
1515
) {
1616
return {
17-
/**
18-
* @param {SearchContext} searchContext
19-
* @param {MeiliSearchParams} searchParams
20-
* @param {MeiliSearch} client
21-
* @returns {Promise}
22-
*/
23-
searchResponse: async function (
24-
searchContext: SearchContext,
25-
searchParams: MeiliSearchParams
26-
): Promise<MeiliSearchResponse<Record<string, any>>> {
27-
// Create cache key containing a unique set of search parameters
28-
const key = cache.formatKey([
29-
searchParams,
30-
searchContext.indexUid,
31-
searchContext.query,
32-
searchContext.pagination,
33-
])
34-
const cachedResponse = cache.getEntry(key)
17+
multiSearch: async function (
18+
searchQueries: MeiliSearchMultiSearchParams[],
19+
instantSearchPagination: PaginationState[]
20+
): Promise<MeilisearchMultiSearchResult[]> {
21+
const key = cache.formatKey([searchQueries])
22+
23+
const cachedResponse = cache.getEntry<MeilisearchMultiSearchResult[]>(key)
3524

3625
// Check if specific request is already cached with its associated search response.
3726
if (cachedResponse) return cachedResponse
3827

39-
// Make search request
40-
const searchResponse = await client
41-
.index(searchContext.indexUid)
42-
.search(searchContext.query, searchParams)
28+
const searchResponses = await client.multiSearch({
29+
queries: searchQueries,
30+
})
4331

32+
const responseWithPagination = searchResponses.results.map(
33+
(response, index) => ({
34+
...response,
35+
// TODO: should be removed at one point
36+
pagination: instantSearchPagination[index] || {},
37+
})
38+
)
4439
// Cache response
45-
cache.setEntry<MeiliSearchResponse>(key, searchResponse)
40+
cache.setEntry<MeilisearchMultiSearchResult[]>(
41+
key,
42+
responseWithPagination
43+
)
4644

47-
return searchResponse
45+
return responseWithPagination
4846
},
4947
}
5048
}

packages/instant-meilisearch/src/adapter/search-response-adapter/hits-adapter.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1-
import type { SearchContext, MeiliSearchResponse } from '../../types'
1+
import type {
2+
PaginationState,
3+
MeilisearchMultiSearchResult,
4+
InstantMeiliSearchConfig,
5+
} from '../../types'
26
import { adaptFormattedFields } from './format-adapter'
37
import { adaptGeoResponse } from './geo-reponse-adapter'
48

59
/**
6-
* @param {MeiliSearchResponse<Record<string, any>>} searchResponse
10+
* @param {MeilisearchMultiSearchResult} searchResult
711
* @param {SearchContext} searchContext
812
* @returns {Array<Record<string, any>>}
913
*/
1014
export function adaptHits(
11-
searchResponse: MeiliSearchResponse<Record<string, any>>,
12-
searchContext: SearchContext
15+
searchResponse: MeilisearchMultiSearchResult & {
16+
pagination: PaginationState
17+
},
18+
config: InstantMeiliSearchConfig
1319
): any {
14-
const { primaryKey } = searchContext
1520
const { hits } = searchResponse
16-
const {
17-
pagination: { finite, hitsPerPage },
18-
} = searchContext
21+
const { hitsPerPage } = searchResponse.pagination
22+
const { finitePagination, primaryKey } = config // Needs: finite, hitsPerPage
1923

2024
// if the length of the hits is bigger than the hitsPerPage
2125
// It means that there is still pages to come as we append limit by hitsPerPage + 1
2226
// In which case we still need to remove the additional hit returned by Meilisearch
23-
if (!finite && hits.length > hitsPerPage) {
27+
if (!finitePagination && hits.length > hitsPerPage) {
2428
hits.splice(hits.length - 1, 1)
2529
}
2630

packages/instant-meilisearch/src/adapter/search-response-adapter/pagination-adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {
22
MeiliSearchResponse,
3-
PaginationState,
43
InstantSearchPagination,
4+
PaginationState,
55
} from '../../types'
66

77
function adaptNbPages(

0 commit comments

Comments
 (0)