Clean up search code, limit bookmarks list by query and/or tags

This commit is contained in:
Justin Hawkins 2022-06-07 11:07:38 +09:30
parent 1563c7b21d
commit 42fd1973b8
4 changed files with 34 additions and 42 deletions

View File

@ -18,6 +18,11 @@ type BookmarkManager struct {
scrapeQueue chan *entity.Bookmark scrapeQueue chan *entity.Bookmark
} }
type SearchOptions struct {
Query string
Tags []string
}
func NewBookmarkManager(db *DB) *BookmarkManager { func NewBookmarkManager(db *DB) *BookmarkManager {
return &BookmarkManager{db: db, scrapeQueue: make(chan *entity.Bookmark)} return &BookmarkManager{db: db, scrapeQueue: make(chan *entity.Bookmark)}
} }
@ -94,28 +99,12 @@ func (m *BookmarkManager) LoadBookmarkByID(id uint64) entity.Bookmark {
return ret return ret
} }
func (m *BookmarkManager) LoadBookmarksByIDs(ids []uint64) []entity.Bookmark { func (m *BookmarkManager) Search(opts SearchOptions) ([]entity.Bookmark, error) {
// log.Printf("loading %v", ids)
ret := make([]entity.Bookmark, 0, 0)
s := make([]interface{}, len(ids))
for i, v := range ids {
s[i] = v
}
err := m.db.store.Find(&ret, bolthold.Where("ID").In(s...))
if err != nil {
panic(err)
}
return ret
}
func (m *BookmarkManager) Search(query string, tags []string) ([]entity.Bookmark, error) {
rets := make([]uint64, 0, 0)
// first get a list of all the ids that match our query
idsMatchingQuery := make([]uint64, 0, 0)
counts := make(map[uint64]uint8) counts := make(map[uint64]uint8)
words := content.StringToSearchWords(opts.Query)
words := content.StringToSearchWords(query)
for _, word := range words { for _, word := range words {
var wi *entity.WordIndex var wi *entity.WordIndex
@ -133,30 +122,33 @@ func (m *BookmarkManager) Search(query string, tags []string) ([]entity.Bookmark
for k, v := range counts { for k, v := range counts {
if v == uint8(len(words)) { if v == uint8(len(words)) {
rets = append(rets, k) idsMatchingQuery = append(idsMatchingQuery, k)
if len(rets) > 10 { if len(idsMatchingQuery) > 10 {
break break
} }
} }
} }
if tags != nil && len(tags) > 0 { // now we can do our search
rets = m.LimitToIdsWithTags(rets, tags) bhQuery := bolthold.Query{}
if opts.Query != "" {
bhQuery = bolthold.Query(*bhQuery.And("ID").In(bolthold.Slice(idsMatchingQuery)...))
} }
return m.LoadBookmarksByIDs(rets), nil if opts.Tags != nil && len(opts.Tags) > 0 {
bhQuery = bolthold.Query(*bhQuery.And("Tags").ContainsAll(bolthold.Slice(opts.Tags)...))
} }
func (m *BookmarkManager) LimitToIdsWithTags(ids []uint64, tags []string) []uint64 { out := []entity.Bookmark{}
outIds := []uint64{} err := m.db.store.ForEach(&bhQuery,
err := m.db.store.ForEach(bolthold.Where("ID").ContainsAny(bolthold.Slice(ids)...).And("Tags").ContainsAll(bolthold.Slice(tags)...),
func(bm *entity.Bookmark) error { func(bm *entity.Bookmark) error {
outIds = append(outIds, bm.ID) out = append(out, *bm)
return nil return nil
}) })
if err != nil { if err != nil {
panic(err) panic(err)
} }
return outIds
return out, nil
} }
func (m *BookmarkManager) ScrapeAndIndex(bm *entity.Bookmark) error { func (m *BookmarkManager) ScrapeAndIndex(bm *entity.Bookmark) error {

View File

@ -73,7 +73,7 @@ func BenchmarkOneWordSearch(b *testing.B) {
bmm := NewBookmarkManager(&dbh) bmm := NewBookmarkManager(&dbh)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bmm.Search("hello", nil) bmm.Search(SearchOptions{Query: "hello"})
} }
} }
@ -84,7 +84,7 @@ func BenchmarkTwoWordSearch(b *testing.B) {
bmm := NewBookmarkManager(&dbh) bmm := NewBookmarkManager(&dbh)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bmm.Search("human relate", nil) bmm.Search(SearchOptions{Query: "human relate"})
} }
} }
@ -95,6 +95,6 @@ func BenchmarkThreeWordSearch(b *testing.B) {
bmm := NewBookmarkManager(&dbh) bmm := NewBookmarkManager(&dbh)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bmm.Search("human wiki editor", nil) bmm.Search(SearchOptions{Query: "human wiki editor"})
} }
} }

View File

@ -47,7 +47,7 @@ func TestAddRemove(t *testing.T) {
t.Errorf("scrape index returned %s", err) t.Errorf("scrape index returned %s", err)
} }
searchRes, err := bmm.Search("fox", nil) searchRes, err := bmm.Search(SearchOptions{Query: "fox"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }
@ -62,7 +62,7 @@ func TestAddRemove(t *testing.T) {
t.Errorf("scrape index returned %s", err) t.Errorf("scrape index returned %s", err)
} }
searchRes, err = bmm.Search("fox", nil) searchRes, err = bmm.Search(SearchOptions{Query: "fox"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }
@ -70,7 +70,7 @@ func TestAddRemove(t *testing.T) {
t.Error("got result when should not") t.Error("got result when should not")
} }
searchRes, err = bmm.Search("rabbit", nil) searchRes, err = bmm.Search(SearchOptions{Query: "rabbit"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }
@ -83,7 +83,7 @@ func TestAddRemove(t *testing.T) {
t.Errorf("got error when deleting: %s", err) t.Errorf("got error when deleting: %s", err)
} }
searchRes, err = bmm.Search("rabbit", nil) searchRes, err = bmm.Search(SearchOptions{Query: "rabbit"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }
@ -119,7 +119,7 @@ func TestTagIndexing(t *testing.T) {
t.Errorf("scrape index returned %s", err) t.Errorf("scrape index returned %s", err)
} }
searchRes, err := bmm.Search("fox", nil) searchRes, err := bmm.Search(SearchOptions{Query: "fox"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }
@ -133,7 +133,7 @@ func TestTagIndexing(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("scrape index returned %s", err) t.Errorf("scrape index returned %s", err)
} }
searchRes, err = bmm.Search("sloth", nil) searchRes, err = bmm.Search(SearchOptions{Query: "sloth"})
if err != nil { if err != nil {
t.Errorf("search returned %s", err) t.Errorf("search returned %s", err)
} }

View File

@ -95,7 +95,7 @@ func Create(bmm *db.BookmarkManager, cmm *db.ConfigManager) *Server {
if c.PostForm("tags_hidden") != "" { if c.PostForm("tags_hidden") != "" {
tags = strings.Split(c.PostForm("tags_hidden"), "|") tags = strings.Split(c.PostForm("tags_hidden"), "|")
} }
allBookmarks, _ := bmm.Search(query, tags) allBookmarks, _ := bmm.Search(db.SearchOptions{Query: query, Tags: tags})
meta := gin.H{"config": config, "bookmarks": allBookmarks} meta := gin.H{"config": config, "bookmarks": allBookmarks}
log.Printf("query is %s, tags %v", query, tags) log.Printf("query is %s, tags %v", query, tags)
@ -125,7 +125,7 @@ func Create(bmm *db.BookmarkManager, cmm *db.ConfigManager) *Server {
r.POST("/search", func(c *gin.Context) { r.POST("/search", func(c *gin.Context) {
query := c.PostForm("query") query := c.PostForm("query")
sr, err := bmm.Search(query, nil) sr, err := bmm.Search(db.SearchOptions{Query: query})
data := gin.H{ data := gin.H{
"results": sr, "results": sr,
"error": err, "error": err,