0
0
Fork 0

query: add DumpQuery to expand string query and format them as JSON

This is convenient to see either complicated queries build
programmatically, or to make sure the query parser does what it is
expected to do.

Note only queries made of bleve basic queries are supported. If we
wanted to support external queries, for instance string queries with an
alternative parser, I suggest to introduce some kind of:

type ExpandableQuery interface {
    Query
    Expand(*IndexMapping) (Query, error)
}

and type assert to that instead of *queryStringQuery.
This commit is contained in:
Patrick Mezard 2015-10-23 14:24:22 +02:00
parent 89bc8c3a93
commit c9619f0359
2 changed files with 140 additions and 0 deletions

View File

@ -11,6 +11,7 @@ package bleve
import (
"encoding/json"
"fmt"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/search"
@ -209,3 +210,90 @@ func ParseQuery(input []byte) (Query, error) {
}
return nil, ErrorUnknownQueryType
}
// expandQuery traverses the input query tree and returns a new tree where
// query string queries have been expanded into base queries. Returned tree may
// reference queries from the input tree or new queries.
func expandQuery(m *IndexMapping, query Query) (Query, error) {
var expand func(query Query) (Query, error)
var expandSlice func(queries []Query) ([]Query, error)
expandSlice = func(queries []Query) ([]Query, error) {
expanded := []Query{}
for _, q := range queries {
exp, err := expand(q)
if err != nil {
return nil, err
}
expanded = append(expanded, exp)
}
return expanded, nil
}
expand = func(query Query) (Query, error) {
switch query.(type) {
case *queryStringQuery:
q := query.(*queryStringQuery)
parsed, err := parseQuerySyntax(q.Query, m)
if err != nil {
return nil, fmt.Errorf("could not parse '%s': %s", q.Query, err)
}
return expand(parsed)
case *conjunctionQuery:
q := *query.(*conjunctionQuery)
children, err := expandSlice(q.Conjuncts)
if err != nil {
return nil, err
}
q.Conjuncts = children
return &q, nil
case *disjunctionQuery:
q := *query.(*disjunctionQuery)
children, err := expandSlice(q.Disjuncts)
if err != nil {
return nil, err
}
q.Disjuncts = children
return &q, nil
case *booleanQuery:
q := *query.(*booleanQuery)
var err error
q.Must, err = expand(q.Must)
if err != nil {
return nil, err
}
q.Should, err = expand(q.Should)
if err != nil {
return nil, err
}
q.MustNot, err = expand(q.MustNot)
if err != nil {
return nil, err
}
return &q, nil
case *phraseQuery:
q := *query.(*phraseQuery)
children, err := expandSlice(q.TermQueries)
if err != nil {
return nil, err
}
q.TermQueries = children
return &q, nil
default:
return query, nil
}
}
return expand(query)
}
// DumpQuery returns a string representation of the query tree, where query
// string queries have been expanded into base queries. The output format is
// meant for debugging purpose and may change in the future.
func DumpQuery(m *IndexMapping, query Query) (string, error) {
q, err := expandQuery(m, query)
if err != nil {
return "", err
}
data, err := json.MarshalIndent(q, "", " ")
return string(data), err
}

View File

@ -11,6 +11,7 @@ package bleve
import (
"reflect"
"strings"
"testing"
)
@ -232,3 +233,54 @@ func TestQueryValidate(t *testing.T) {
}
}
}
func TestDumpQuery(t *testing.T) {
mapping := &IndexMapping{}
q := NewQueryStringQuery("+water -light beer")
s, err := DumpQuery(mapping, q)
if err != nil {
t.Fatal(err)
}
s = strings.TrimSpace(s)
wanted := strings.TrimSpace(`{
"must": {
"conjuncts": [
{
"match": "water",
"boost": 1,
"prefix_length": 0,
"fuzziness": 0
}
],
"boost": 1
},
"should": {
"disjuncts": [
{
"match": "beer",
"boost": 1,
"prefix_length": 0,
"fuzziness": 0
}
],
"boost": 1,
"min": 1
},
"must_not": {
"disjuncts": [
{
"match": "light",
"boost": 1,
"prefix_length": 0,
"fuzziness": 0
}
],
"boost": 1,
"min": 0
},
"boost": 1
}`)
if wanted != s {
t.Fatalf("query:\n%s\ndiffers from expected:\n%s", s, wanted)
}
}