137 lines
2.7 KiB
Go
137 lines
2.7 KiB
Go
package backend
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/blevesearch/bleve"
|
|
)
|
|
|
|
type (
|
|
Index struct {
|
|
index bleve.Index
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
Result struct{ *bleve.SearchResult }
|
|
)
|
|
|
|
func (i *Index) isIndexed(filename string, errChan chan<- error) bool {
|
|
i.mu.RLock()
|
|
defer i.mu.RUnlock()
|
|
|
|
query := bleve.NewDocIDQuery([]string{filename})
|
|
request := bleve.NewSearchRequest(query)
|
|
result, err := i.index.Search(request)
|
|
if err != nil {
|
|
errChan <- fmt.Errorf("error searching for file %v in index: %v", filename, err)
|
|
return false
|
|
}
|
|
|
|
return len(result.Hits) > 0
|
|
}
|
|
|
|
func (i *Index) indexAllArticles(c *Config, db *DB) error {
|
|
articles, err := db.GetAllArticles()
|
|
if err != nil {
|
|
return fmt.Errorf("error getting all articles from DB: %v", err)
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
errChan := make(chan error, len(articles))
|
|
|
|
go func() {
|
|
wg.Wait()
|
|
close(errChan)
|
|
}()
|
|
|
|
for _, article := range articles {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
filename := article.UUID.String()
|
|
content, err := article.ReadContent(c)
|
|
if err != nil {
|
|
errChan <- fmt.Errorf("error reading content of article %v: %v", filename, err)
|
|
return
|
|
}
|
|
|
|
if !i.isIndexed(filename, errChan) {
|
|
if err := i.Add(filename, content); err != nil {
|
|
errChan <- fmt.Errorf("error adding file %v to index: %v", filename, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
errChan <- nil
|
|
}()
|
|
}
|
|
if err = <-errChan; err != nil {
|
|
return fmt.Errorf("error(s) indexing all articles: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func InitIndex(c *Config) (*Index, error) {
|
|
var err error
|
|
index := new(Index)
|
|
|
|
index.index, err = bleve.Open(c.IndexDir)
|
|
if err != nil {
|
|
mapping := bleve.NewIndexMapping()
|
|
index.index, err = bleve.New(c.IndexDir, mapping)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error creating new index file: %v", err)
|
|
}
|
|
}
|
|
|
|
return index, err
|
|
}
|
|
|
|
func (i *Index) Add(filename, content string) error {
|
|
i.mu.Lock()
|
|
defer i.mu.Unlock()
|
|
|
|
doc := map[string]string{
|
|
"name": filename,
|
|
"body": content,
|
|
}
|
|
|
|
if err := i.index.Index(filename, doc); err != nil {
|
|
return fmt.Errorf("error indexing file %v: %v", filename, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (i *Index) Query(q string) (*Result, error) {
|
|
i.mu.RLock()
|
|
defer i.mu.RUnlock()
|
|
|
|
query := bleve.NewQueryStringQuery(q)
|
|
request := bleve.NewSearchRequest(query)
|
|
result, err := i.index.Search(request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error querying index for \"%v\": %v", q, err)
|
|
}
|
|
|
|
if len(result.Hits) < 1 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &Result{result}, err
|
|
}
|
|
|
|
func (i *Index) Delete(filename string) error {
|
|
i.mu.Lock()
|
|
defer i.mu.Unlock()
|
|
|
|
if err := i.index.Delete(filename); err != nil {
|
|
return fmt.Errorf("error deleting file %v from index: %v", filename, err)
|
|
}
|
|
|
|
return nil
|
|
}
|