// 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, "", ""), "", "") } if fragField == textField || fragField == createdField { for _, f := range frags { r.HTML += template.HTML(f) } break } } results = append(results, r) } return }