Skip to content

Commit 63161f2

Browse files
Merge #563
563: Add multi-search federation r=Ja7ad a=polyfloyd # Pull Request Fixes #573 ## What does this PR do? This PR adds support for the new federated search to be introduced in v1.10: https://github.com/meilisearch/meilisearch/releases/tag/v1.10.0-rc.0 ## PR checklist Please check if your PR fulfills the following requirements: - [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)? - [x] Have you read the contributing guidelines? - [x] Have you made sure that the title is accurate and descriptive of the changes? Co-authored-by: polyfloyd <[email protected]>
2 parents e09d86e + d132bc1 commit 63161f2

File tree

3 files changed

+764
-431
lines changed

3 files changed

+764
-431
lines changed

meilisearch_test.go

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import (
44
"context"
55
"crypto/tls"
66
"errors"
7-
"github.com/stretchr/testify/assert"
8-
"github.com/stretchr/testify/require"
97
"math"
10-
"reflect"
118
"strings"
129
"sync"
1310
"testing"
1411
"time"
12+
13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
1515
)
1616

1717
func Test_Version(t *testing.T) {
@@ -1985,7 +1985,7 @@ func TestClient_MultiSearch(t *testing.T) {
19851985
args: args{
19861986
client: sv,
19871987
queries: &MultiSearchRequest{
1988-
[]*SearchRequest{
1988+
Queries: []*SearchRequest{
19891989
{
19901990
IndexUID: "TestClientMultiSearchOneIndex",
19911991
Query: "wonder",
@@ -2017,7 +2017,7 @@ func TestClient_MultiSearch(t *testing.T) {
20172017
args: args{
20182018
client: sv,
20192019
queries: &MultiSearchRequest{
2020-
[]*SearchRequest{
2020+
Queries: []*SearchRequest{
20212021
{
20222022
IndexUID: "TestClientMultiSearchOnTwoIndexes1",
20232023
Query: "wonder",
@@ -2065,12 +2065,44 @@ func TestClient_MultiSearch(t *testing.T) {
20652065
},
20662066
},
20672067
},
2068+
{
2069+
name: "TestClientMultiSearchWithFederation",
2070+
args: args{
2071+
client: sv,
2072+
queries: &MultiSearchRequest{
2073+
Queries: []*SearchRequest{
2074+
{
2075+
IndexUID: "TestClientMultiSearchOnTwoIndexes1",
2076+
Query: "wonder",
2077+
},
2078+
{
2079+
IndexUID: "TestClientMultiSearchOnTwoIndexes2",
2080+
Query: "prince",
2081+
},
2082+
},
2083+
Federation: &MultiSearchFederation{},
2084+
},
2085+
UIDS: []string{"TestClientMultiSearchOnTwoIndexes1", "TestClientMultiSearchOnTwoIndexes2"},
2086+
},
2087+
want: &MultiSearchResponse{
2088+
Results: nil,
2089+
Hits: []interface{}{
2090+
map[string]interface{}{"_federation": map[string]interface{}{"indexUid": "TestClientMultiSearchOnTwoIndexes2", "queriesPosition": 1.0, "weightedRankingScore": 0.8787878787878788}, "book_id": 456.0, "title": "Le Petit Prince"},
2091+
map[string]interface{}{"_federation": map[string]interface{}{"indexUid": "TestClientMultiSearchOnTwoIndexes1", "queriesPosition": 0.0, "weightedRankingScore": 0.8712121212121212}, "book_id": 1.0, "title": "Alice In Wonderland"},
2092+
map[string]interface{}{"_federation": map[string]interface{}{"indexUid": "TestClientMultiSearchOnTwoIndexes2", "queriesPosition": 1.0, "weightedRankingScore": 0.8333333333333334}, "book_id": 4.0, "title": "Harry Potter and the Half-Blood Prince"}},
2093+
ProcessingTimeMs: 0,
2094+
Offset: 0,
2095+
Limit: 20,
2096+
EstimatedTotalHits: 3,
2097+
SemanticHitCount: 0,
2098+
},
2099+
},
20682100
{
20692101
name: "TestClientMultiSearchNoIndex",
20702102
args: args{
20712103
client: sv,
20722104
queries: &MultiSearchRequest{
2073-
[]*SearchRequest{
2105+
Queries: []*SearchRequest{
20742106
{
20752107
Query: "",
20762108
},
@@ -2094,17 +2126,10 @@ func TestClient_MultiSearch(t *testing.T) {
20942126
if tt.wantErr {
20952127
require.Error(t, err)
20962128
} else {
2129+
require.NoError(t, err)
20972130
require.NotNil(t, got)
2098-
for i := 0; i < len(tt.want.Results); i++ {
2099-
if !reflect.DeepEqual(got.Results[i].Hits, tt.want.Results[i].Hits) {
2100-
t.Errorf("Client.MultiSearch() = %v, want %v", got.Results[i].Hits, tt.want.Results[i].Hits)
2101-
}
2102-
require.Equal(t, tt.want.Results[i].EstimatedTotalHits, got.Results[i].EstimatedTotalHits)
2103-
require.Equal(t, tt.want.Results[i].Offset, got.Results[i].Offset)
2104-
require.Equal(t, tt.want.Results[i].Limit, got.Results[i].Limit)
2105-
require.Equal(t, tt.want.Results[i].Query, got.Results[i].Query)
2106-
require.Equal(t, tt.want.Results[i].IndexUID, got.Results[i].IndexUID)
2107-
}
2131+
got.ProcessingTimeMs = 0 // Can vary.
2132+
require.Equal(t, got, tt.want)
21082133
}
21092134
})
21102135
}

types.go

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -379,32 +379,37 @@ type CreateIndexRequest struct {
379379
//
380380
// Documentation: https://www.meilisearch.com/docs/reference/api/search#search-parameters
381381
type SearchRequest struct {
382-
Offset int64 `json:"offset,omitempty"`
383-
Limit int64 `json:"limit,omitempty"`
384-
AttributesToRetrieve []string `json:"attributesToRetrieve,omitempty"`
385-
AttributesToSearchOn []string `json:"attributesToSearchOn,omitempty"`
386-
AttributesToCrop []string `json:"attributesToCrop,omitempty"`
387-
CropLength int64 `json:"cropLength,omitempty"`
388-
CropMarker string `json:"cropMarker,omitempty"`
389-
AttributesToHighlight []string `json:"attributesToHighlight,omitempty"`
390-
HighlightPreTag string `json:"highlightPreTag,omitempty"`
391-
HighlightPostTag string `json:"highlightPostTag,omitempty"`
392-
MatchingStrategy MatchingStrategy `json:"matchingStrategy,omitempty"`
393-
Filter interface{} `json:"filter,omitempty"`
394-
ShowMatchesPosition bool `json:"showMatchesPosition,omitempty"`
395-
ShowRankingScore bool `json:"showRankingScore,omitempty"`
396-
ShowRankingScoreDetails bool `json:"showRankingScoreDetails,omitempty"`
397-
Facets []string `json:"facets,omitempty"`
398-
Sort []string `json:"sort,omitempty"`
399-
Vector []float32 `json:"vector,omitempty"`
400-
HitsPerPage int64 `json:"hitsPerPage,omitempty"`
401-
Page int64 `json:"page,omitempty"`
402-
IndexUID string `json:"indexUid,omitempty"`
403-
Query string `json:"q"`
404-
Distinct string `json:"distinct,omitempty"`
405-
Hybrid *SearchRequestHybrid `json:"hybrid,omitempty"`
406-
RetrieveVectors bool `json:"retrieveVectors,omitempty"`
407-
RankingScoreThreshold float64 `json:"rankingScoreThreshold,omitempty"`
382+
Offset int64 `json:"offset,omitempty"`
383+
Limit int64 `json:"limit,omitempty"`
384+
AttributesToRetrieve []string `json:"attributesToRetrieve,omitempty"`
385+
AttributesToSearchOn []string `json:"attributesToSearchOn,omitempty"`
386+
AttributesToCrop []string `json:"attributesToCrop,omitempty"`
387+
CropLength int64 `json:"cropLength,omitempty"`
388+
CropMarker string `json:"cropMarker,omitempty"`
389+
AttributesToHighlight []string `json:"attributesToHighlight,omitempty"`
390+
HighlightPreTag string `json:"highlightPreTag,omitempty"`
391+
HighlightPostTag string `json:"highlightPostTag,omitempty"`
392+
MatchingStrategy MatchingStrategy `json:"matchingStrategy,omitempty"`
393+
Filter interface{} `json:"filter,omitempty"`
394+
ShowMatchesPosition bool `json:"showMatchesPosition,omitempty"`
395+
ShowRankingScore bool `json:"showRankingScore,omitempty"`
396+
ShowRankingScoreDetails bool `json:"showRankingScoreDetails,omitempty"`
397+
Facets []string `json:"facets,omitempty"`
398+
Sort []string `json:"sort,omitempty"`
399+
Vector []float32 `json:"vector,omitempty"`
400+
HitsPerPage int64 `json:"hitsPerPage,omitempty"`
401+
Page int64 `json:"page,omitempty"`
402+
IndexUID string `json:"indexUid,omitempty"`
403+
Query string `json:"q"`
404+
Distinct string `json:"distinct,omitempty"`
405+
Hybrid *SearchRequestHybrid `json:"hybrid,omitempty"`
406+
RetrieveVectors bool `json:"retrieveVectors,omitempty"`
407+
RankingScoreThreshold float64 `json:"rankingScoreThreshold,omitempty"`
408+
FederationOptions *SearchFederationOptions `json:"federationOptions,omitempty"`
409+
}
410+
411+
type SearchFederationOptions struct {
412+
Weight float64 `json:"weight"`
408413
}
409414

410415
type SearchRequestHybrid struct {
@@ -413,7 +418,13 @@ type SearchRequestHybrid struct {
413418
}
414419

415420
type MultiSearchRequest struct {
416-
Queries []*SearchRequest `json:"queries"`
421+
Federation *MultiSearchFederation `json:"federation,omitempty"`
422+
Queries []*SearchRequest `json:"queries"`
423+
}
424+
425+
type MultiSearchFederation struct {
426+
Offset int64 `json:"offset,omitempty"`
427+
Limit int64 `json:"limit,omitempty"`
417428
}
418429

419430
// SearchResponse is the response body for search method
@@ -434,7 +445,13 @@ type SearchResponse struct {
434445
}
435446

436447
type MultiSearchResponse struct {
437-
Results []SearchResponse `json:"results"`
448+
Results []SearchResponse `json:"results,omitempty"`
449+
Hits []interface{} `json:"hits,omitempty"`
450+
ProcessingTimeMs int64 `json:"processingTimeMs,omitempty"`
451+
Offset int64 `json:"offset,omitempty"`
452+
Limit int64 `json:"limit,omitempty"`
453+
EstimatedTotalHits int64 `json:"estimatedTotalHits,omitempty"`
454+
SemanticHitCount int64 `json:"semanticHitCount,omitempty"`
438455
}
439456

440457
type FacetSearchRequest struct {
@@ -532,9 +549,6 @@ func (b RawType) MarshalJSON() ([]byte, error) {
532549
}
533550

534551
func (s *SearchRequest) validate() {
535-
if s.Limit == 0 {
536-
s.Limit = DefaultLimit
537-
}
538552
if s.Hybrid != nil && s.Hybrid.Embedder == "" {
539553
s.Hybrid.Embedder = "default"
540554
}

0 commit comments

Comments
 (0)