119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
// Copyright (C) 2019 Marius Schellenberger
|
|
|
|
package index
|
|
|
|
import (
|
|
"errors"
|
|
"git.giftfish.de/ston1th/docstore/pkg/core"
|
|
"git.giftfish.de/ston1th/godrop/v2"
|
|
"github.com/blevesearch/bleve"
|
|
"github.com/blevesearch/bleve/mapping"
|
|
"html/template"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const maxSearchResult = 101
|
|
|
|
const docType = "document"
|
|
|
|
type document struct {
|
|
Text string `json:"text"`
|
|
Keyword []string `json:"keyword"`
|
|
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
|
|
err = godrop.Unveil(path, "rwc")
|
|
if err != nil {
|
|
return
|
|
}
|
|
if _, err = os.Stat(path); os.IsNotExist(err) {
|
|
var m *mapping.IndexMappingImpl
|
|
m, err = createMapping()
|
|
//m := bleve.NewIndexMapping()
|
|
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) (id string, err error) {
|
|
id = newID()
|
|
for {
|
|
doc, _ := i.i.Document(id)
|
|
if doc == nil {
|
|
break
|
|
}
|
|
id = newID()
|
|
}
|
|
k := classify(text)
|
|
err = i.i.Index(id, &document{text, k, time.Now()})
|
|
return
|
|
}
|
|
|
|
func (i *Index) Delete(id string) error {
|
|
return i.i.Delete(id)
|
|
}
|
|
|
|
func (i *Index) Search(search string) (results []core.Result, 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 == "text" || fragField == "created" {
|
|
for _, f := range frags {
|
|
r.HTML += template.HTML(f)
|
|
}
|
|
break
|
|
}
|
|
if fragField == "keyword" {
|
|
var k string
|
|
for _, f := range frags {
|
|
k += f
|
|
}
|
|
r.Keyword = strings.ReplaceAll(strings.ReplaceAll(k, "<mark>", ""), "</mark>", "")
|
|
break
|
|
}
|
|
}
|
|
results = append(results, r)
|
|
}
|
|
return
|
|
}
|