add support for top-n(all())

This commit is contained in:
travisturner 2014-09-23 18:54:19 -05:00
parent 4dd88570e4
commit 181215b493
5 changed files with 85 additions and 29 deletions

View file

@ -166,35 +166,36 @@ func init() {
func (self *Service) TopNQueryStepHandler(msg *db.Message) {
qs := msg.Data.(query.TopNQueryStep)
var categoryleaves []uint64
input := qs.Input
value, _ := self.Hold.Get(input, 10)
var bh index.BitmapHandle
switch val := value.(type) {
case index.BitmapHandle:
bh = val
case []byte:
bh, _ = self.Index.FromBytes(qs.Location.FragmentId, val)
var topnPackage TopNPackage
// if we have an input, hold for it. if we don't, we assume an all() query
if qs.Input == nil {
topn, err := self.Index.TopNAll(qs.Location.FragmentId, qs.N*2, qs.Filters)
if err != nil {
log.Println(spew.Sdump(err))
}
topnPackage = TopNPackage{*qs.Location.ProcessId, qs.Location.FragmentId, topn, bh}
} else {
input := qs.Input
value, _ := self.Hold.Get(input, 10)
//var bh index.BitmapHandle
switch val := value.(type) {
case index.BitmapHandle:
bh = val
case []byte:
bh, _ = self.Index.FromBytes(qs.Location.FragmentId, val)
}
topn, err := self.Index.TopN(qs.Location.FragmentId, bh, qs.N*2, qs.Filters)
if err != nil {
log.Println(spew.Sdump(err))
}
topnPackage = TopNPackage{*qs.Location.ProcessId, qs.Location.FragmentId, topn, bh}
}
categoryleaves = qs.Filters
/*
spew.Dump(bh, qs.N*2, categoryleaves)
result_message := db.Message{Data: "foobar"}
self.Transport.Send(&result_message, qs.Destination.ProcessId)
*/
topn, err := self.Index.TopN(qs.Location.FragmentId, bh, qs.N*2, categoryleaves)
topnPackage := TopNPackage{*qs.Location.ProcessId, qs.Location.FragmentId, topn, bh}
if err != nil {
log.Println(spew.Sdump(err))
}
result_message := db.Message{Data: query.TopNQueryResult{&query.BaseQueryResult{Id: qs.Id, Data: topnPackage}}}
self.Transport.Send(&result_message, qs.Destination.ProcessId)
}
func canCompile() bool {

View file

@ -192,6 +192,8 @@ ArgLoop:
}
query.Args["n"] = i
}
case "all":
// do nothing
case "recall": //need pair based list of frag_id,handle
arg, ok := query.Args["stash"]
if !ok {

View file

@ -90,4 +90,17 @@ func TestQueryParser(t *testing.T) {
spew.Dump(q)
So(err, ShouldBeNil)
})
Convey("all() query parse", t, func() {
tokens, err := Lex("top-n(all(), general, 30)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "top-n")
So(len(query.Subqueries), ShouldEqual, 1)
So(query.Subqueries[0].Operation, ShouldEqual, "all")
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{})
})
}

View file

@ -294,6 +294,19 @@ func (qt *CatQueryTree) getLocation(d *db.Database) (*db.Location, error) {
return qt.location, err
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// ALL
///////////////////////////////////////////////////////////////////////////////////////////////////
// QueryTree for GET queries
type AllQueryTree struct {
}
// Uses consistent hashing function to select node containing data for GET operation
func (qt *AllQueryTree) getLocation(d *db.Database) (*db.Location, error) {
return nil, nil
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// GET
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -493,6 +506,8 @@ func (self *QueryPlanner) buildTree(query *Query, slice int) (QueryTree, error)
return nil, err
}
tree = &CountQueryTree{subquery: subquery}
} else if query.Operation == "all" {
tree = &AllQueryTree{}
} else if query.Operation == "top-n" {
var frame string
var n int
@ -715,12 +730,18 @@ func (self *QueryPlanner) flatten(qt QueryTree, id *util.GUID, location *db.Loca
if err != nil {
return nil, err
}
step := &TopNQueryStep{&BaseQueryStep{id, "top-n", loc, location}, &sub_id, topn.Filters, topn.N, topn.Frame}
subq_steps, err := self.flatten(topn.subquery, &sub_id, loc)
if err != nil {
return nil, err
step := &TopNQueryStep{&BaseQueryStep{id, "top-n", loc, location}, nil, topn.Filters, topn.N, topn.Frame}
switch topn.subquery.(type) {
case *AllQueryTree:
// do nothing
default:
step.Input = &sub_id
subq_steps, err := self.flatten(topn.subquery, &sub_id, loc)
if err != nil {
return nil, err
}
plan = append(plan, *subq_steps...)
}
plan = append(plan, *subq_steps...)
plan = append(plan, step)
}
return &plan, nil

View file

@ -203,6 +203,25 @@ func TestQueryPlanner(t *testing.T) {
So(qp[3].(*TopNQueryStep).Input, ShouldEqual, qp[2].(GetQueryStep).Id)
So(qp[3].(*TopNQueryStep).N, ShouldEqual, 50)
})
Convey("All query plan - including parsing", t, func() {
query, err := QueryForPQL("top-n(all(), default, 50, [1,2,3])")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(err, ShouldEqual, nil)
So(len(qp), ShouldEqual, 3)
So(qp[0].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
So(qp[0].(*TopNQueryStep).Input, ShouldEqual, nil)
So(qp[0].(*TopNQueryStep).N, ShouldEqual, 50)
So(qp[0].(*TopNQueryStep).Filters, ShouldResemble, []uint64{1, 2, 3})
})
Convey("Get query plan - including parsing", t, func() {
_, err := QueryForPQL("count()")