diff --git a/search/searcher.go b/search/searcher.go index b60877a..4590363 100644 --- a/search/searcher.go +++ b/search/searcher.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "sync" "time" @@ -20,7 +21,6 @@ const ( dbFileName = "cache.db" userBucketName = "user" starredBucketSuffix = "starred" - maxQuerySize = 10000 ) var ( @@ -33,6 +33,7 @@ var ( type Searcher interface { CreateIndex() error + Search(text string, size int) ([]*Result, error) } type searcher struct { @@ -43,6 +44,11 @@ type searcher struct { index bleve.Index } +type Result struct { + *git.Starred + Score float64 +} + func ConfigPath() (string, error) { configOnce.Do(func() { // getting home directory. @@ -98,6 +104,42 @@ func NewSearcher(token string) (Searcher, error) { return &searcher{git: git, db: db, index: index, gitToken: token, dbPath: dbPath}, nil } +// Search executes full text search. +func (s *searcher) Search(text string, size int) ([]*Result, error) { + text = strings.TrimSpace(text) + if text == "" { + return []*Result{}, nil + } + + // search text from index. + query := bleve.NewMatchQuery(text) + search := bleve.NewSearchRequestOptions(query, size, 0, false) + search.SortBy([]string{"-_score", "_id"}) + searchResult, err := s.index.Search(search) + if err != nil { + return nil, fmt.Errorf("[err] Search %w", err) + } + + // get a detailed starred information + var list []*Result + s.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket([]byte(starredBucketName(s.gitToken))) + if bucket == nil { + return nil + } + for _, r := range searchResult.Hits { + data := bucket.Get([]byte(r.ID)) + var starred *git.Starred + if err := json.Unmarshal(data, &starred); err == nil { + list = append(list, &Result{Starred: starred, Score: r.Score}) + } + } + return nil + }) + + return list, nil +} + // CreateIndex makes bleve.Index func (s *searcher) CreateIndex() error { // get user diff --git a/search/searcher_test.go b/search/searcher_test.go index 0dd7d29..73c8a5a 100644 --- a/search/searcher_test.go +++ b/search/searcher_test.go @@ -33,7 +33,37 @@ func TestNewSearcher(t *testing.T) { } } -func TestCreateIndex(t *testing.T) { +func TestSearcher_Search(t *testing.T) { + assert := assert.New(t) + + token := os.Getenv("GITHUB_TOKEN") + s, err := NewSearcher(token) + assert.NoError(err) + defer s.(*searcher).db.Close() + err = s.CreateIndex() + assert.NoError(err) + + tests := map[string]struct { + input string + isErr bool + }{ + "all": {input: "ssh certify"}, + } + + for _, t := range tests { + result, err := s.Search(t.input, 100) + assert.Equal(t.isErr, err != nil) + if err == nil { + log.Printf("==============%s=============\n", t.input) + for _, r := range result { + log.Println(r.FullName, r.Score) + } + } + } + +} + +func TestSearcher_CreateIndex(t *testing.T) { assert := assert.New(t) token := os.Getenv("GITHUB_TOKEN") @@ -50,7 +80,7 @@ func TestCreateIndex(t *testing.T) { for _, t := range tests { err := s.CreateIndex() assert.Equal(t.isErr, err != nil) - query := bleve.NewMatchQuery("docker") + query := bleve.NewMatchQuery("docker hello kubernetes") search := bleve.NewSearchRequestOptions(query, 10000, 0, true) search.SortBy([]string{"-_score", "_id"}) searchResult, err := s.(*searcher).index.Search(search)