Skip to content
Merged
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 @@ -47,5 +47,71 @@ 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>'
)
})

test('sort parameter precedence: per-index overrides global overrides', async () => {
await meilisearchClient
.index('movies')
.updateSettings({
sortableAttributes: ['release_date', 'title'],
})
.waitTask()

const { searchClient, setMeiliSearchParams } = instantMeiliSearch(
'http://localhost:7700',
'masterKey',
{
meiliSearchParams: {
sort: ['title:asc'],
},
}
)

const queryParams = [
{
indexName: 'movies',
params: { query: '', hitsPerPage: 3 },
},
]

// Test global sort override - should sort by title ascending
const globalResponse = await searchClient.search<Movies>(queryParams)
const globalHits = globalResponse.results[0].hits
expect(globalHits.length).toBeGreaterThan(1)
// Verify titles are sorted in ascending order
const globalTitles = globalHits
.map((hit: Movies) => hit.title)
.filter(Boolean)
expect(globalTitles).toEqual([...globalTitles].sort())

// Test per-index sort override takes precedence over global
setMeiliSearchParams({
sort: ['title:asc'],
indexesOverrides: {
movies: { sort: ['title:desc'] },
},
})

const perIndexResponse = await searchClient.search<Movies>(queryParams)
const perIndexHits = perIndexResponse.results[0].hits
expect(perIndexHits.length).toBeGreaterThan(1)
// Verify titles are sorted in descending order
const perIndexTitles = perIndexHits
.map((hit: Movies) => hit.title)
.filter(Boolean)
expect(perIndexTitles).toEqual([...perIndexTitles].sort().reverse())
})
})
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,56 @@ 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)
})

test('filter can be set via global override when IS filters are empty', () => {
const globalFilter = 'category = "books"'

const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
// No facetFilters, filters, or numericFilters - empty IS filters
meiliSearchParams: {
filter: globalFilter,
},
})

expect(searchParams.filter).toBe(globalFilter)
})

test('filter can be set via per-index override when IS filters are empty', () => {
const globalFilter = 'category = "books"'
const indexFilter = 'status = "active"'

const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
// No facetFilters, filters, or numericFilters - empty IS filters
meiliSearchParams: {
filter: globalFilter,
indexesOverrides: {
test: { filter: indexFilter },
},
},
})

// Per-index override should take precedence over global override
expect(searchParams.filter).toBe(indexFilter)
})
})

describe('Geo filter adapter', () => {
Expand Down
Loading