mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-06 16:45:55 +00:00
add support for top-n(all())
This commit is contained in:
parent
4dd88570e4
commit
181215b493
5 changed files with 85 additions and 29 deletions
49
core/topn.go
49
core/topn.go
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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{}{})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue