docstore/pkg/index/index.go

144 lines
2.9 KiB
Go

// Copyright (C) 2019 Marius Schellenberger
package index
import (
"errors"
"git.giftfish.de/ston1th/docstore/pkg/core"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/document"
"github.com/blevesearch/bleve/mapping"
"html/template"
"os"
"strings"
"time"
)
const (
maxSearchResult = 101
docType = "document"
textField = "text"
tagsField = "tags"
createdField = "created"
)
type Document struct {
Text string `json:"text"`
Tags []string `json:"tags"`
Created time.Time `json:"created"`
}
func (d *Document) Type() string {
return docType
}
type Index struct {
i bleve.Index
}
func NewIndex(path string) (i *Index, err error) {
var bi bleve.Index
if _, err = os.Stat(path); os.IsNotExist(err) {
var m *mapping.IndexMappingImpl
m, err = createMapping()
if err != nil {
err = errors.New("index: " + err.Error())
return
}
bi, err = bleve.New(path, m)
if err != nil {
err = errors.New("index: " + err.Error())
return
}
} else {
bi, err = bleve.Open(path)
if err != nil {
err = errors.New("index: " + err.Error())
return
}
}
i = &Index{i: bi}
return
}
func (i *Index) Close() error {
return i.i.Close()
}
func (i *Index) Add(text string, tags []string) (id string, err error) {
id = newID()
for {
doc, _ := i.i.Document(id)
if doc == nil {
break
}
id = newID()
}
err = i.i.Index(id, &Document{text, tags, time.Now()})
return
}
func (i *Index) Reindex(id string, doc *Document) error {
return i.i.Index(id, doc)
}
func (i *Index) Get(id string) (doc *Document, err error) {
d, err := i.i.Document(id)
if d == nil || err != nil {
return
}
doc = new(Document)
for _, f := range d.Fields {
n := f.Name()
switch n {
case textField:
text := document.NewTextField(n, f.ArrayPositions(), f.Value())
doc.Text = string(text.Value())
case createdField:
created := document.NewDateTimeFieldFromBytes(n, f.ArrayPositions(), f.Value())
doc.Created, _ = created.DateTime()
}
}
return
}
func (i *Index) Delete(id string) error {
return i.i.Delete(id)
}
func (i *Index) Search(search string) (results core.Results, err error) {
req := bleve.NewSearchRequest(bleve.NewQueryStringQuery(search))
req.Highlight = bleve.NewHighlightWithStyle("html")
req.Size = maxSearchResult
res, err := i.i.Search(req)
if err != nil {
return
}
for _, hit := range res.Hits {
if hit == nil {
continue
}
r := core.Result{ID: hit.ID}
d, err := i.i.Document(hit.ID)
if d == nil || err != nil {
continue
}
for fragField, frags := range hit.Fragments {
if fragField == tagsField {
var t string
for _, f := range frags {
t += f
}
r.Tags = strings.ReplaceAll(strings.ReplaceAll(t, "<mark>", ""), "</mark>", "")
}
if fragField == textField || fragField == createdField {
for _, f := range frags {
r.HTML += template.HTML(f)
}
break
}
}
results = append(results, r)
}
return
}