diff --git a/search/search.go b/search/search.go index db4d8aecedb4f7f45564a14980e48b5946a69ca8..9d59e42817d273b13cf22459a562008b6414e8ae 100644 --- a/search/search.go +++ b/search/search.go @@ -52,3 +52,53 @@ func ItemTextSearch(query string, item *items.Item) (*items.Item, []string, erro return item, fields, nil } + +func ItemsTextSearch(query string, itms []*items.Item) ([]*items.Item, error) { + + index, err := bleve.NewMemOnly(bleve.NewIndexMapping()) + if err != nil { + return nil, err + } + + im := make(map[string]*items.Item, len(itms)) + for _, i := range itms { + im[i.ID] = i + if err = index.Index(i.ID, i); err != nil { + return nil, err + } + } + + searchRequest := bleve.NewSearchRequest(bleve.NewQueryStringQuery(query)) + searchRequest.Highlight = bleve.NewHighlight() + searchResult, err := index.Search(searchRequest) + if err != nil { + return nil, err + } + + if searchResult.Total == 0 { + return nil, errors.New("no results found") + } + + result := make([]*items.Item, 0, len(searchResult.Hits)) + for _, hint := range searchResult.Hits { + item, ok := im[hint.ID] + if !ok { + return nil, errors.New("search result not match item") + } + + for key, value := range hint.Fragments { + key = strings.TrimPrefix(key, "data.") + + if key == "id" { + item.Data[key] = value + } + + if err = item.Set(key, value); err != nil { + return nil, err + } + } + result = append(result, item) + } + + return result, nil +} diff --git a/search/search_test.go b/search/search_test.go index 025269383ed08115dbeb9eea46c54a40a98548fa..260a6a16592b66fe81566b52b2b010dc72abcb2b 100644 --- a/search/search_test.go +++ b/search/search_test.go @@ -2,13 +2,14 @@ package search import ( "encoding/json" + "strconv" "testing" "git.perx.ru/perxis/perxis-go/pkg/items" + "github.com/stretchr/testify/require" ) -func BenchmarkItemTextSearch(b *testing.B) { - +func BenchmarkTextSearch(b *testing.B) { jsonStr := `{ "common": { "environment_id": "cjfmbiaeibkll33i38g0", @@ -35,14 +36,30 @@ func BenchmarkItemTextSearch(b *testing.B) { } }` - item := &items.Item{ID: "1"} query := "cjfmbiaeibkll33i38fg" d := map[string]interface{}{} _ = json.Unmarshal([]byte(jsonStr), &d) - item.Data = d - for i := 0; i < b.N; i++ { - v, f, err := ItemTextSearch(query, item) - _, _, _ = v, f, err + b.Run("Item", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _, err := ItemTextSearch(query, &items.Item{ID: "1", Data: d}) + require.NoError(b, err) + } + }) + + var itms []*items.Item + for i := 0; i < 100; i++ { + itms = append(itms, &items.Item{ID: strconv.Itoa(i), Data: d}) } + + b.Run("Items", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := ItemsTextSearch(query, itms) + require.NoError(b, err) + } + }) }