diff --git a/packages/instant-meilisearch/README.md b/packages/instant-meilisearch/README.md index 4a180fb5..1ac90dcd 100644 --- a/packages/instant-meilisearch/README.md +++ b/packages/instant-meilisearch/README.md @@ -296,7 +296,28 @@ instantMeiliSearch( } ) ``` +When using multi search, meilisearchParams can be overriden for specific indexes : +```js +instantMeiliSearch( + // ... + { + meiliSearchParams: { + // All indexes will highlight overview + attributesToHighlight: ['overview'], + highlightPreTag: '', + highlightPostTag: '', + attributesToSearchOn: ['overview'], + indexesOverrides: { + movies: { + // Only title will be highlighted for hits in movies + attributesToHighlight: ['title'] + } + } + }, + } +) +``` ### Modify Meilisearch search parameters `instantMeiliSearch` returns an instance with two properties on it, one of them being `setMeiliSearchParams`. diff --git a/packages/instant-meilisearch/__tests__/overridden-meilisearch-parameters.test.ts b/packages/instant-meilisearch/__tests__/overridden-meilisearch-parameters.test.ts index af9fc73f..6385d434 100644 --- a/packages/instant-meilisearch/__tests__/overridden-meilisearch-parameters.test.ts +++ b/packages/instant-meilisearch/__tests__/overridden-meilisearch-parameters.test.ts @@ -51,5 +51,18 @@ describe('InstantMeiliSearch overridden parameters', () => { expect(secondHits[0]._highlightResult?.overview?.value).toContain( 'While racing to a boxing match' ) + + setMeiliSearchParams({ + indexesOverrides: { + movies: { highlightPreTag: '', highlightPostTag: '' }, + }, + }) + const thirdResponse = await searchClient.search(queryParams) + + const thirdHits = thirdResponse.results[0].hits + expect(thirdHits.length).toEqual(1) + expect(thirdHits[0]._highlightResult?.overview?.value).toContain( + 'While racing to a boxing match' + ) }) }) diff --git a/packages/instant-meilisearch/src/adapter/search-request-adapter/__tests__/search-params.test.ts b/packages/instant-meilisearch/src/adapter/search-request-adapter/__tests__/search-params.test.ts index eaee1fa0..15701de6 100644 --- a/packages/instant-meilisearch/src/adapter/search-request-adapter/__tests__/search-params.test.ts +++ b/packages/instant-meilisearch/src/adapter/search-request-adapter/__tests__/search-params.test.ts @@ -80,6 +80,41 @@ describe('Parameters adapter', () => { ) }) + test('adapting a searchContext with overridden Meilisearch parameters for a specific index', () => { + const meiliSearchParams: OverridableMeiliSearchSearchParameters = { + attributesToHighlight: ['movies', 'genres'], + highlightPreTag: '', + highlightPostTag: '', + matchingStrategy: MatchingStrategies.ALL, + indexesOverrides: { + test: { + attributesToHighlight: ['release_date'], + highlightPreTag: '', + highlightPostTag: '', + matchingStrategy: MatchingStrategies.LAST, + }, + }, + } + + const searchParams = adaptSearchParams({ + ...DEFAULT_CONTEXT, + meiliSearchParams, + }) + + expect(searchParams.attributesToHighlight).toEqual( + meiliSearchParams.indexesOverrides?.test?.attributesToHighlight + ) + expect(searchParams.highlightPreTag).toEqual( + meiliSearchParams.indexesOverrides?.test?.highlightPreTag + ) + expect(searchParams.highlightPostTag).toEqual( + meiliSearchParams.indexesOverrides?.test?.highlightPostTag + ) + expect(searchParams.matchingStrategy).toEqual( + meiliSearchParams.indexesOverrides?.test?.matchingStrategy + ) + }) + test('hybrid search configuration can be set via search parameters', () => { const hybridSearchConfig = { semanticRatio: 0, @@ -96,6 +131,29 @@ describe('Parameters adapter', () => { expect(searchParams.hybrid).toBe(hybridSearchConfig) }) + test('hybrid search configuration can be set via search parameters for a specific index', () => { + const hybridSearchConfig = { + semanticRatio: 0, + embedder: 'default', + } + const specificHybridSearchConfig = { + semanticRatio: 10, + embedder: 'default', + } + + const searchParams = adaptSearchParams({ + ...DEFAULT_CONTEXT, + meiliSearchParams: { + hybrid: hybridSearchConfig, + indexesOverrides: { + test: { hybrid: specificHybridSearchConfig }, + }, + }, + }) + + expect(searchParams.hybrid).toBe(specificHybridSearchConfig) + }) + test('vector can be set via search parameters', () => { const vector = [0, 1, 2] @@ -108,6 +166,20 @@ describe('Parameters adapter', () => { expect(searchParams.vector).toBe(vector) }) + test('vector can be set via search parameters for a specific index', () => { + const vector = [0, 1, 2] + const indexVector = [3, 4, 5] + + const searchParams = adaptSearchParams({ + ...DEFAULT_CONTEXT, + meiliSearchParams: { + vector, + indexesOverrides: { test: { vector: indexVector } }, + }, + }) + + expect(searchParams.vector).toBe(indexVector) + }) test('ranking score threshold can be set via search parameters', () => { const rankingScoreThreshold = 0.974 @@ -122,6 +194,23 @@ describe('Parameters adapter', () => { expect(searchParams.rankingScoreThreshold).toBe(rankingScoreThreshold) }) + test('ranking score threshold can be set via search parameters for a specific index', () => { + const rankingScoreThreshold = 0.974 + const indexRankingScoreThreshold = 0.567 + + const searchParams = adaptSearchParams({ + ...DEFAULT_CONTEXT, + meiliSearchParams: { + rankingScoreThreshold, + indexesOverrides: { + test: { rankingScoreThreshold: indexRankingScoreThreshold }, + }, + }, + }) + + expect(searchParams.rankingScoreThreshold).toBe(indexRankingScoreThreshold) + }) + test('distinct search configuration can be set via search parameters', () => { const distinctSearchConfig = 'title' @@ -134,6 +223,23 @@ describe('Parameters adapter', () => { expect(searchParams.distinct).toBe(distinctSearchConfig) }) + + test('distinct search configuration can be set via search parameters for a specific', () => { + const distinctSearchConfig = 'title' + const indexDistinctSearchConfig = 'name' + + const searchParams = adaptSearchParams({ + ...DEFAULT_CONTEXT, + meiliSearchParams: { + distinct: distinctSearchConfig, + indexesOverrides: { + test: { distinct: indexDistinctSearchConfig }, + }, + }, + }) + + expect(searchParams.distinct).toBe(indexDistinctSearchConfig) + }) }) describe('Geo filter adapter', () => { diff --git a/packages/instant-meilisearch/src/adapter/search-request-adapter/search-params-adapter.ts b/packages/instant-meilisearch/src/adapter/search-request-adapter/search-params-adapter.ts index 3b140b76..1ba67660 100644 --- a/packages/instant-meilisearch/src/adapter/search-request-adapter/search-params-adapter.ts +++ b/packages/instant-meilisearch/src/adapter/search-request-adapter/search-params-adapter.ts @@ -96,7 +96,10 @@ export function MeiliParamsCreator(searchContext: SearchContext) { meiliSearchParams.q = query }, addFacets() { - const value = >facets + const value = + overrideParams?.indexesOverrides?.[indexUid]?.facets ?? + overrideParams?.facets ?? + >facets if (value !== undefined) { // despite Instantsearch.js typing it as `string[]`, // it still can send `string` @@ -105,6 +108,7 @@ export function MeiliParamsCreator(searchContext: SearchContext) { }, addAttributesToCrop() { const value = + overrideParams?.indexesOverrides?.[indexUid]?.attributesToCrop ?? overrideParams?.attributesToCrop ?? >attributesToSnippet if (value !== undefined) { @@ -112,24 +116,33 @@ export function MeiliParamsCreator(searchContext: SearchContext) { } }, addCropLength() { - const value = overrideParams?.cropLength + const value = + overrideParams?.indexesOverrides?.[indexUid]?.cropLength ?? + overrideParams?.cropLength if (value !== undefined) { meiliSearchParams.cropLength = value } }, addCropMarker() { - const value = overrideParams?.cropMarker ?? snippetEllipsisText + const value = + overrideParams?.indexesOverrides?.[indexUid]?.cropMarker ?? + overrideParams?.cropMarker ?? + snippetEllipsisText if (value !== undefined) { meiliSearchParams.cropMarker = value } }, addFilters() { if (meilisearchFilters.length) { - meiliSearchParams.filter = meilisearchFilters + meiliSearchParams.filter = + overrideParams?.indexesOverrides?.[indexUid]?.filter ?? + overrideParams?.filter ?? + meilisearchFilters } }, addAttributesToRetrieve() { const value = + overrideParams?.indexesOverrides?.[indexUid]?.attributesToRetrieve ?? overrideParams?.attributesToRetrieve ?? >attributesToRetrieve if (value !== undefined) { @@ -137,18 +150,21 @@ export function MeiliParamsCreator(searchContext: SearchContext) { } }, addAttributesToHighlight() { - meiliSearchParams.attributesToHighlight = + meiliSearchParams.attributesToHighlight = overrideParams + ?.indexesOverrides?.[indexUid]?.attributesToHighlight ?? overrideParams?.attributesToHighlight ?? - >attributesToHighlight ?? ['*'] + >attributesToHighlight ?? ['*'] }, addPreTag() { meiliSearchParams.highlightPreTag = + overrideParams?.indexesOverrides?.[indexUid]?.highlightPreTag ?? overrideParams?.highlightPreTag ?? highlightPreTag ?? '__ais-highlight__' }, addPostTag() { meiliSearchParams.highlightPostTag = + overrideParams?.indexesOverrides?.[indexUid]?.highlightPostTag ?? overrideParams?.highlightPostTag ?? highlightPostTag ?? '__/ais-highlight__' @@ -204,54 +220,69 @@ export function MeiliParamsCreator(searchContext: SearchContext) { } }, addShowMatchesPosition() { - const value = overrideParams?.showMatchesPosition + const value = + overrideParams?.indexesOverrides?.[indexUid]?.showMatchesPosition ?? + overrideParams?.showMatchesPosition if (value !== undefined) { meiliSearchParams.showMatchesPosition = value } }, addMatchingStrategy() { - const value = overrideParams?.matchingStrategy + const value = + overrideParams?.indexesOverrides?.[indexUid]?.matchingStrategy ?? + overrideParams?.matchingStrategy if (value !== undefined) { meiliSearchParams.matchingStrategy = value } }, addShowRankingScore() { - const value = overrideParams?.showRankingScore + const value = + overrideParams?.indexesOverrides?.[indexUid]?.showRankingScore ?? + overrideParams?.showRankingScore if (value !== undefined) { meiliSearchParams.showRankingScore = value } }, addAttributesToSearchOn() { const value = - overrideParams?.attributesToSearchOn !== undefined - ? overrideParams.attributesToSearchOn - : >( - restrictSearchableAttributes - ) + overrideParams?.indexesOverrides?.[indexUid]?.attributesToSearchOn ?? + overrideParams?.attributesToSearchOn ?? + >( + restrictSearchableAttributes + ) + if (value !== undefined) { meiliSearchParams.attributesToSearchOn = value } }, addHybridSearch() { - const value = overrideParams?.hybrid + const value = + overrideParams?.indexesOverrides?.[indexUid]?.hybrid ?? + overrideParams?.hybrid if (value !== undefined) { meiliSearchParams.hybrid = value } }, addVector() { - const value = overrideParams?.vector + const value = + overrideParams?.indexesOverrides?.[indexUid]?.vector ?? + overrideParams?.vector if (value !== undefined) { meiliSearchParams.vector = value } }, addDistinct() { - const value = overrideParams?.distinct + const value = + overrideParams?.indexesOverrides?.[indexUid]?.distinct ?? + overrideParams?.distinct if (value !== undefined) { meiliSearchParams.distinct = value } }, addRankingScoreThreshold() { - const value = overrideParams?.rankingScoreThreshold + const value = + overrideParams?.indexesOverrides?.[indexUid]?.rankingScoreThreshold ?? + overrideParams?.rankingScoreThreshold if (value !== undefined) { meiliSearchParams.rankingScoreThreshold = value } diff --git a/packages/instant-meilisearch/src/types/types.ts b/packages/instant-meilisearch/src/types/types.ts index 3b0e26de..550ff772 100644 --- a/packages/instant-meilisearch/src/types/types.ts +++ b/packages/instant-meilisearch/src/types/types.ts @@ -41,8 +41,12 @@ export type InstantSearchParams = NonNullable< AlgoliaMultipleQueriesQuery['params'] > -export type OverridableMeiliSearchSearchParameters = Pick< +type BaseOverridableMeiliSearchSearchParameters = Pick< MeiliSearchMultiSearchParams, + | 'sort' + | 'hitsPerPage' + | 'filter' + | 'facets' | 'attributesToCrop' | 'attributesToRetrieve' | 'attributesToSearchOn' @@ -60,6 +64,14 @@ export type OverridableMeiliSearchSearchParameters = Pick< | 'vector' > +export type OverridableMeiliSearchSearchParameters = + BaseOverridableMeiliSearchSearchParameters & { + indexesOverrides?: Record< + string, + BaseOverridableMeiliSearchSearchParameters + > + } + type BaseInstantMeiliSearchOptions = { placeholderSearch?: boolean primaryKey?: string