Skip to content

Commit

Permalink
the normalizer added
Browse files Browse the repository at this point in the history
  • Loading branch information
2403905 committed Aug 23, 2023
1 parent 52ef5f1 commit f22565b
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 1 deletion.
7 changes: 7 additions & 0 deletions services/search/pkg/query/kql/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kql

const (
BoolAND = "AND"
BoolOR = "OR"
BoolNOT = "NOT"
)
43 changes: 43 additions & 0 deletions services/search/pkg/query/kql/dictionary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,49 @@ func TestParse(t *testing.T) {
Key: "author",
Nodes: []ast.Node{
&ast.StringNode{Value: "John Smith"},
&ast.OperatorNode{Value: "AND"},
&ast.StringNode{Value: "Jane"},
},
},
},
},
err: false,
},
{
name: "KeyGroup or key",
got: []string{
`author:("John Smith" Jane) author:"Jack" AND author:"Oggy"`,
},
want: &ast.Ast{
Nodes: []ast.Node{
&ast.GroupNode{
Key: "author",
Nodes: []ast.Node{
&ast.StringNode{Value: "John Smith"},
&ast.OperatorNode{Value: "AND"},
&ast.StringNode{Value: "Jane"},
},
},
&ast.OperatorNode{Value: "OR"},
&ast.StringNode{Key: "author", Value: "Jack"},
&ast.OperatorNode{Value: "AND"},
&ast.StringNode{Key: "author", Value: "Oggy"},
},
},
err: false,
},
{
name: "KeyGroup",
got: []string{
`author:("John Smith" OR Jane)"`,
},
want: &ast.Ast{
Nodes: []ast.Node{
&ast.GroupNode{
Key: "author",
Nodes: []ast.Node{
&ast.StringNode{Value: "John Smith"},
&ast.OperatorNode{Value: "OR"},
&ast.StringNode{Value: "Jane"},
},
},
Expand Down
71 changes: 70 additions & 1 deletion services/search/pkg/query/kql/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func root(n interface{}, text []byte, pos position) (*ast.Ast, error) {

return &ast.Ast{
Base: b,
Nodes: nodes,
Nodes: normalize(nodes),
}, nil
}

Expand Down Expand Up @@ -140,3 +140,72 @@ func groupNode(k, n interface{}, text []byte, pos position) (*ast.GroupNode, err
Nodes: nodes,
}, nil
}

var source = "implicitly operator"
var operatorNodeAnd = ast.OperatorNode{Base: &ast.Base{Loc: &ast.Location{Source: &source}}, Value: BoolAND}
var operatorNodeOr = ast.OperatorNode{Base: &ast.Base{Loc: &ast.Location{Source: &source}}, Value: BoolOR}

// normalize Populate the implicit logical operators in the ast
//
// https://learn.microsoft.com/en-us/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference#constructing-free-text-queries-using-kql
// If there are multiple free-text expressions without any operators in between them, the query behavior is the same as using the AND operator.
// "John Smith" "Jane Smith"
// This functionally is the same as using the OR Boolean operator, as follows:
// "John Smith" AND "Jane Smith"
//
// https://learn.microsoft.com/en-us/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference#using-multiple-property-restrictions-within-a-kql-query
// When you use multiple instances of the same property restriction, matches are based on the union of the property restrictions in the KQL query.
// author:"John Smith" author:"Jane Smith"
// This functionally is the same as using the OR Boolean operator, as follows:
// author:"John Smith" OR author:"Jane Smith"
//
// When you use different property restrictions, matches are based on an intersection of the property restrictions in the KQL query, as follows:
// author:"John Smith" filetype:docx
// This is the same as using the AND Boolean operator, as follows:
// author:"John Smith" AND filetype:docx
//
// https://learn.microsoft.com/en-us/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference#grouping-property-restrictions-within-a-kql-query
// author:("John Smith" "Jane Smith")
// This is the same as using the AND Boolean operator, as follows:
// author:"John Smith" AND author:"Jane Smith"
func normalize(nodes []ast.Node) []ast.Node {
res := make([]ast.Node, 0, len(nodes))
var currentNode ast.Node
var prevKey, currentKey *string
for _, node := range nodes {
switch n := node.(type) {
case *ast.StringNode:
if prevKey == nil {
prevKey = &n.Key
res = append(res, node)
continue
}
currentNode = n
currentKey = &n.Key
case *ast.GroupNode:
n.Nodes = normalize(n.Nodes)
if prevKey == nil {
prevKey = &n.Key
res = append(res, n)
continue
}
currentNode = n
currentKey = &n.Key
default:
prevKey = nil
res = append(res, node)
}
if prevKey != nil && currentKey != nil {
if *prevKey == *currentKey && *prevKey != "" {
res = append(res, &operatorNodeOr, currentNode)
} else {
res = append(res, &operatorNodeAnd, currentNode)
}
currentNode = nil
currentKey = nil
prevKey = nil
continue
}
}
return res
}

0 comments on commit f22565b

Please sign in to comment.