Skip to content

feature: handle per index meilisearch params #1364

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/instant-meilisearch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: '<em>',
highlightPostTag: '</em>',
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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,18 @@ describe('InstantMeiliSearch overridden parameters', () => {
expect(secondHits[0]._highlightResult?.overview?.value).toContain(
'<om>While racing to a boxing match</om>'
)

setMeiliSearchParams({
indexesOverrides: {
movies: { highlightPreTag: '<span>', highlightPostTag: '</span>' },
},
})
const thirdResponse = await searchClient.search<Movies>(queryParams)

const thirdHits = thirdResponse.results[0].hits
expect(thirdHits.length).toEqual(1)
expect(thirdHits[0]._highlightResult?.overview?.value).toContain(
'<span>While racing to a boxing match</span>'
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -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: '<em>',
highlightPostTag: '</em>',
matchingStrategy: MatchingStrategies.ALL,
indexesOverrides: {
test: {
attributesToHighlight: ['release_date'],
highlightPreTag: '<span>',
highlightPostTag: '</span>',
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,
Expand All @@ -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]

Expand All @@ -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
Expand All @@ -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'

Expand All @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
meiliSearchParams.q = query
},
addFacets() {
const value = <Mutable<typeof facets>>facets
const value =
overrideParams?.indexesOverrides?.[indexUid]?.facets ??
overrideParams?.facets ??
<Mutable<typeof facets>>facets
if (value !== undefined) {
// despite Instantsearch.js typing it as `string[]`,
// it still can send `string`
Expand All @@ -105,50 +108,63 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
},
addAttributesToCrop() {
const value =
overrideParams?.indexesOverrides?.[indexUid]?.attributesToCrop ??
overrideParams?.attributesToCrop ??
<Mutable<typeof attributesToSnippet>>attributesToSnippet
if (value !== undefined) {
meiliSearchParams.attributesToCrop = value
}
},
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 ??
<Mutable<typeof attributesToRetrieve>>attributesToRetrieve
if (value !== undefined) {
meiliSearchParams.attributesToRetrieve = value
}
},
addAttributesToHighlight() {
meiliSearchParams.attributesToHighlight =
meiliSearchParams.attributesToHighlight = overrideParams
?.indexesOverrides?.[indexUid]?.attributesToHighlight ??
overrideParams?.attributesToHighlight ??
<Mutable<typeof attributesToHighlight>>attributesToHighlight ?? ['*']
<Mutable<typeof 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__'
Expand Down Expand Up @@ -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
: <Mutable<typeof restrictSearchableAttributes>>(
restrictSearchableAttributes
)
overrideParams?.indexesOverrides?.[indexUid]?.attributesToSearchOn ??
overrideParams?.attributesToSearchOn ??
<Mutable<typeof restrictSearchableAttributes>>(
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
}
Expand Down
14 changes: 13 additions & 1 deletion packages/instant-meilisearch/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -60,6 +64,14 @@ export type OverridableMeiliSearchSearchParameters = Pick<
| 'vector'
>

export type OverridableMeiliSearchSearchParameters =
BaseOverridableMeiliSearchSearchParameters & {
indexesOverrides?: Record<
string,
BaseOverridableMeiliSearchSearchParameters
>
}

type BaseInstantMeiliSearchOptions = {
placeholderSearch?: boolean
primaryKey?: string
Expand Down