Skip to content

Commit

Permalink
Merge #563
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
meili-bors[bot] and polyfloyd authored Sep 18, 2024
2 parents e09d86e + d132bc1 commit 63161f2
Show file tree
Hide file tree
Showing 3 changed files with 764 additions and 431 deletions.
57 changes: 41 additions & 16 deletions meilisearch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import (
"context"
"crypto/tls"
"errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"math"
"reflect"
"strings"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_Version(t *testing.T) {
Expand Down Expand Up @@ -1985,7 +1985,7 @@ func TestClient_MultiSearch(t *testing.T) {
args: args{
client: sv,
queries: &MultiSearchRequest{
[]*SearchRequest{
Queries: []*SearchRequest{
{
IndexUID: "TestClientMultiSearchOneIndex",
Query: "wonder",
Expand Down Expand Up @@ -2017,7 +2017,7 @@ func TestClient_MultiSearch(t *testing.T) {
args: args{
client: sv,
queries: &MultiSearchRequest{
[]*SearchRequest{
Queries: []*SearchRequest{
{
IndexUID: "TestClientMultiSearchOnTwoIndexes1",
Query: "wonder",
Expand Down Expand Up @@ -2065,12 +2065,44 @@ func TestClient_MultiSearch(t *testing.T) {
},
},
},
{
name: "TestClientMultiSearchWithFederation",
args: args{
client: sv,
queries: &MultiSearchRequest{
Queries: []*SearchRequest{
{
IndexUID: "TestClientMultiSearchOnTwoIndexes1",
Query: "wonder",
},
{
IndexUID: "TestClientMultiSearchOnTwoIndexes2",
Query: "prince",
},
},
Federation: &MultiSearchFederation{},
},
UIDS: []string{"TestClientMultiSearchOnTwoIndexes1", "TestClientMultiSearchOnTwoIndexes2"},
},
want: &MultiSearchResponse{
Results: nil,
Hits: []interface{}{
map[string]interface{}{"_federation": map[string]interface{}{"indexUid": "TestClientMultiSearchOnTwoIndexes2", "queriesPosition": 1.0, "weightedRankingScore": 0.8787878787878788}, "book_id": 456.0, "title": "Le Petit Prince"},
map[string]interface{}{"_federation": map[string]interface{}{"indexUid": "TestClientMultiSearchOnTwoIndexes1", "queriesPosition": 0.0, "weightedRankingScore": 0.8712121212121212}, "book_id": 1.0, "title": "Alice In Wonderland"},
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"}},
ProcessingTimeMs: 0,
Offset: 0,
Limit: 20,
EstimatedTotalHits: 3,
SemanticHitCount: 0,
},
},
{
name: "TestClientMultiSearchNoIndex",
args: args{
client: sv,
queries: &MultiSearchRequest{
[]*SearchRequest{
Queries: []*SearchRequest{
{
Query: "",
},
Expand All @@ -2094,17 +2126,10 @@ func TestClient_MultiSearch(t *testing.T) {
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.NotNil(t, got)
for i := 0; i < len(tt.want.Results); i++ {
if !reflect.DeepEqual(got.Results[i].Hits, tt.want.Results[i].Hits) {
t.Errorf("Client.MultiSearch() = %v, want %v", got.Results[i].Hits, tt.want.Results[i].Hits)
}
require.Equal(t, tt.want.Results[i].EstimatedTotalHits, got.Results[i].EstimatedTotalHits)
require.Equal(t, tt.want.Results[i].Offset, got.Results[i].Offset)
require.Equal(t, tt.want.Results[i].Limit, got.Results[i].Limit)
require.Equal(t, tt.want.Results[i].Query, got.Results[i].Query)
require.Equal(t, tt.want.Results[i].IndexUID, got.Results[i].IndexUID)
}
got.ProcessingTimeMs = 0 // Can vary.
require.Equal(t, got, tt.want)
}
})
}
Expand Down
76 changes: 45 additions & 31 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,32 +379,37 @@ type CreateIndexRequest struct {
//
// Documentation: https://www.meilisearch.com/docs/reference/api/search#search-parameters
type SearchRequest struct {
Offset int64 `json:"offset,omitempty"`
Limit int64 `json:"limit,omitempty"`
AttributesToRetrieve []string `json:"attributesToRetrieve,omitempty"`
AttributesToSearchOn []string `json:"attributesToSearchOn,omitempty"`
AttributesToCrop []string `json:"attributesToCrop,omitempty"`
CropLength int64 `json:"cropLength,omitempty"`
CropMarker string `json:"cropMarker,omitempty"`
AttributesToHighlight []string `json:"attributesToHighlight,omitempty"`
HighlightPreTag string `json:"highlightPreTag,omitempty"`
HighlightPostTag string `json:"highlightPostTag,omitempty"`
MatchingStrategy MatchingStrategy `json:"matchingStrategy,omitempty"`
Filter interface{} `json:"filter,omitempty"`
ShowMatchesPosition bool `json:"showMatchesPosition,omitempty"`
ShowRankingScore bool `json:"showRankingScore,omitempty"`
ShowRankingScoreDetails bool `json:"showRankingScoreDetails,omitempty"`
Facets []string `json:"facets,omitempty"`
Sort []string `json:"sort,omitempty"`
Vector []float32 `json:"vector,omitempty"`
HitsPerPage int64 `json:"hitsPerPage,omitempty"`
Page int64 `json:"page,omitempty"`
IndexUID string `json:"indexUid,omitempty"`
Query string `json:"q"`
Distinct string `json:"distinct,omitempty"`
Hybrid *SearchRequestHybrid `json:"hybrid,omitempty"`
RetrieveVectors bool `json:"retrieveVectors,omitempty"`
RankingScoreThreshold float64 `json:"rankingScoreThreshold,omitempty"`
Offset int64 `json:"offset,omitempty"`
Limit int64 `json:"limit,omitempty"`
AttributesToRetrieve []string `json:"attributesToRetrieve,omitempty"`
AttributesToSearchOn []string `json:"attributesToSearchOn,omitempty"`
AttributesToCrop []string `json:"attributesToCrop,omitempty"`
CropLength int64 `json:"cropLength,omitempty"`
CropMarker string `json:"cropMarker,omitempty"`
AttributesToHighlight []string `json:"attributesToHighlight,omitempty"`
HighlightPreTag string `json:"highlightPreTag,omitempty"`
HighlightPostTag string `json:"highlightPostTag,omitempty"`
MatchingStrategy MatchingStrategy `json:"matchingStrategy,omitempty"`
Filter interface{} `json:"filter,omitempty"`
ShowMatchesPosition bool `json:"showMatchesPosition,omitempty"`
ShowRankingScore bool `json:"showRankingScore,omitempty"`
ShowRankingScoreDetails bool `json:"showRankingScoreDetails,omitempty"`
Facets []string `json:"facets,omitempty"`
Sort []string `json:"sort,omitempty"`
Vector []float32 `json:"vector,omitempty"`
HitsPerPage int64 `json:"hitsPerPage,omitempty"`
Page int64 `json:"page,omitempty"`
IndexUID string `json:"indexUid,omitempty"`
Query string `json:"q"`
Distinct string `json:"distinct,omitempty"`
Hybrid *SearchRequestHybrid `json:"hybrid,omitempty"`
RetrieveVectors bool `json:"retrieveVectors,omitempty"`
RankingScoreThreshold float64 `json:"rankingScoreThreshold,omitempty"`
FederationOptions *SearchFederationOptions `json:"federationOptions,omitempty"`
}

type SearchFederationOptions struct {
Weight float64 `json:"weight"`
}

type SearchRequestHybrid struct {
Expand All @@ -413,7 +418,13 @@ type SearchRequestHybrid struct {
}

type MultiSearchRequest struct {
Queries []*SearchRequest `json:"queries"`
Federation *MultiSearchFederation `json:"federation,omitempty"`
Queries []*SearchRequest `json:"queries"`
}

type MultiSearchFederation struct {
Offset int64 `json:"offset,omitempty"`
Limit int64 `json:"limit,omitempty"`
}

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

type MultiSearchResponse struct {
Results []SearchResponse `json:"results"`
Results []SearchResponse `json:"results,omitempty"`
Hits []interface{} `json:"hits,omitempty"`
ProcessingTimeMs int64 `json:"processingTimeMs,omitempty"`
Offset int64 `json:"offset,omitempty"`
Limit int64 `json:"limit,omitempty"`
EstimatedTotalHits int64 `json:"estimatedTotalHits,omitempty"`
SemanticHitCount int64 `json:"semanticHitCount,omitempty"`
}

type FacetSearchRequest struct {
Expand Down Expand Up @@ -532,9 +549,6 @@ func (b RawType) MarshalJSON() ([]byte, error) {
}

func (s *SearchRequest) validate() {
if s.Limit == 0 {
s.Limit = DefaultLimit
}
if s.Hybrid != nil && s.Hybrid.Embedder == "" {
s.Hybrid.Embedder = "default"
}
Expand Down
Loading

0 comments on commit 63161f2

Please sign in to comment.