Initial QSfera import
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package bleve
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/blevesearch/bleve/v2"
|
||||
"github.com/blevesearch/bleve/v2/analysis/analyzer/custom"
|
||||
"github.com/blevesearch/bleve/v2/analysis/analyzer/keyword"
|
||||
"github.com/blevesearch/bleve/v2/analysis/token/lowercase"
|
||||
"github.com/blevesearch/bleve/v2/analysis/token/porter"
|
||||
"github.com/blevesearch/bleve/v2/analysis/tokenizer/single"
|
||||
"github.com/blevesearch/bleve/v2/analysis/tokenizer/unicode"
|
||||
"github.com/blevesearch/bleve/v2/mapping"
|
||||
storageProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
|
||||
"github.com/qsfera/server/services/search/pkg/search"
|
||||
)
|
||||
|
||||
func NewIndex(root string) (bleve.Index, error) {
|
||||
destination := filepath.Join(root, "bleve")
|
||||
index, err := bleve.Open(destination)
|
||||
if errors.Is(bleve.ErrorIndexPathDoesNotExist, err) {
|
||||
indexMapping, err := NewMapping()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index, err = bleve.New(destination, indexMapping)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return index, nil
|
||||
}
|
||||
|
||||
return index, err
|
||||
}
|
||||
|
||||
func NewMapping() (mapping.IndexMapping, error) {
|
||||
nameMapping := bleve.NewTextFieldMapping()
|
||||
nameMapping.Analyzer = "lowercaseKeyword"
|
||||
|
||||
lowercaseMapping := bleve.NewTextFieldMapping()
|
||||
lowercaseMapping.IncludeInAll = false
|
||||
lowercaseMapping.Analyzer = "lowercaseKeyword"
|
||||
|
||||
fulltextFieldMapping := bleve.NewTextFieldMapping()
|
||||
fulltextFieldMapping.Analyzer = "fulltext"
|
||||
fulltextFieldMapping.IncludeInAll = false
|
||||
|
||||
docMapping := bleve.NewDocumentMapping()
|
||||
docMapping.AddFieldMappingsAt("Name", nameMapping)
|
||||
docMapping.AddFieldMappingsAt("Tags", lowercaseMapping)
|
||||
docMapping.AddFieldMappingsAt("Favorites", lowercaseMapping)
|
||||
docMapping.AddFieldMappingsAt("Content", fulltextFieldMapping)
|
||||
|
||||
indexMapping := bleve.NewIndexMapping()
|
||||
indexMapping.DefaultAnalyzer = keyword.Name
|
||||
indexMapping.DefaultMapping = docMapping
|
||||
err := indexMapping.AddCustomAnalyzer("lowercaseKeyword",
|
||||
map[string]any{
|
||||
"type": custom.Name,
|
||||
"tokenizer": single.Name,
|
||||
"token_filters": []string{
|
||||
lowercase.Name,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = indexMapping.AddCustomAnalyzer("fulltext",
|
||||
map[string]any{
|
||||
"type": custom.Name,
|
||||
"tokenizer": unicode.Name,
|
||||
"token_filters": []string{
|
||||
lowercase.Name,
|
||||
porter.Name,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return indexMapping, nil
|
||||
}
|
||||
|
||||
func searchResourceByID(id string, index bleve.Index) (*search.Resource, error) {
|
||||
req := bleve.NewSearchRequest(bleve.NewDocIDQuery([]string{id}))
|
||||
req.Fields = []string{"*"}
|
||||
res, err := index.Search(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.Hits.Len() == 0 {
|
||||
return nil, errors.New("entity not found")
|
||||
}
|
||||
|
||||
return matchToResource(res.Hits[0]), nil
|
||||
}
|
||||
|
||||
func searchResourcesByPath(rootId, lookupPath string, index bleve.Index) ([]*search.Resource, error) {
|
||||
q := bleve.NewConjunctionQuery(
|
||||
bleve.NewQueryStringQuery("RootID:"+rootId),
|
||||
bleve.NewQueryStringQuery("Path:"+escapeQuery(lookupPath+"/*")),
|
||||
)
|
||||
bleveReq := bleve.NewSearchRequest(q)
|
||||
bleveReq.Size = math.MaxInt
|
||||
bleveReq.Fields = []string{"*"}
|
||||
res, err := index.Search(bleveReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources := make([]*search.Resource, 0, res.Hits.Len())
|
||||
for _, match := range res.Hits {
|
||||
resources = append(resources, matchToResource(match))
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func searchAndUpdateResourcesDeletionState(id string, state bool, index bleve.Index) ([]*search.Resource, error) {
|
||||
rootResource, err := searchResourceByID(id, index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rootResource.Deleted = state
|
||||
|
||||
resources := []*search.Resource{rootResource}
|
||||
|
||||
if rootResource.Type == uint64(storageProvider.ResourceType_RESOURCE_TYPE_CONTAINER) {
|
||||
descendantResources, err := searchResourcesByPath(rootResource.RootID, rootResource.Path, index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, descendantResource := range descendantResources {
|
||||
descendantResource.Deleted = state
|
||||
resources = append(resources, descendantResource)
|
||||
}
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
}
|
||||
Reference in New Issue
Block a user