Files
ocis/services/search/pkg/query/bleve/legacy.go
Florian Schade ed0dbce978 enhancement: Keyword Query Language (KQL) search syntax support (#7043)
* feat(search): introduce search query package

With the increasing complexity of how we organize our resources, the search must also be able to find them using entity properties.

The query package provides the necessary functionality to do this.

This makes it possible to search for resources via KQL, the microsoft spec is largely covered and can be used for this.

In the current state, the legacy query language is still used, in a future update this will be deprecated and KQL will become the standard
2023-08-28 16:41:36 +02:00

77 lines
2.0 KiB
Go

package bleve
import (
"regexp"
"strings"
bQuery "github.com/blevesearch/bleve/v2/search/query"
"github.com/owncloud/ocis/v2/services/search/pkg/query/ast"
)
// LegacyBuilder implements the legacy Builder interface.
type LegacyBuilder struct{}
// Build translates the ast to a valid bleve query.
func (b LegacyBuilder) Build(qs string) (*ast.Ast, error) {
return &ast.Ast{
Base: &ast.Base{
Loc: &ast.Location{
Start: ast.Position{
Line: 0,
Column: 0,
},
End: ast.Position{
Line: 0,
Column: len(qs),
},
Source: &qs,
},
},
}, nil
}
// LegacyCompiler represents a default bleve query formatter.
type LegacyCompiler struct{}
// Compile implements the default bleve query formatter which converts the bleve likes query search string to the bleve query.
func (c LegacyCompiler) Compile(givenAst *ast.Ast) (bQuery.Query, error) {
return &bQuery.QueryStringQuery{
Query: c.formatQuery(*givenAst.Base.Loc.Source),
}, nil
}
func (c LegacyCompiler) formatQuery(q string) string {
cq := q
fields := []string{"RootID", "Path", "ID", "Name", "Size", "Mtime", "MimeType", "Type"}
for _, field := range fields {
cq = strings.ReplaceAll(cq, strings.ToLower(field)+":", field+":")
}
fieldRe := regexp.MustCompile(`\w+:[^ ]+`)
if fieldRe.MatchString(cq) {
nameTagesRe := regexp.MustCompile(`\+?(Name|Tags)`) // detect "Name", "+Name, "Tags" and "+Tags"
parts := strings.Split(cq, " ")
cq = ""
for _, part := range parts {
fieldParts := strings.SplitN(part, ":", 2)
if len(fieldParts) > 1 {
key := fieldParts[0]
value := fieldParts[1]
if nameTagesRe.MatchString(key) {
value = strings.ToLower(value) // do a lowercase query on the lowercased fields
}
cq += key + ":" + value + " "
} else {
cq += part + " "
}
}
return cq // Sophisticated field based search
}
// this is a basic filename search
cq = strings.ReplaceAll(cq, ":", `\:`)
return "Name:*" + strings.ReplaceAll(strings.ToLower(cq), " ", `\ `) + "*"
}