diff --git a/bench/query.go b/bench/query.go new file mode 100644 index 000000000..69e375c47 --- /dev/null +++ b/bench/query.go @@ -0,0 +1,155 @@ +package bench + +import ( + "github.com/umbel/pilosa/pql" + "math/rand" +) + +func NewQueryMaker(seed int64) *QueryMaker { + return &QueryMaker{ + IDToFrameFn: func(id uint64) string { return "frame.n" }, + R: rand.New(rand.NewSource(seed)), + Frames: []string{"frame.n"}, + } +} + +type QueryMaker struct { + IDToFrameFn func(id uint64) string + R *rand.Rand + Frames []string +} + +func (q *QueryMaker) Random(maxN, depth, maxargs int, idmin, idmax uint64) pql.Call { + val := q.R.Intn(5) + switch val { + case 0: + return q.RandomTopN(maxN, depth, maxargs, idmin, idmax) + default: + return q.RandomBitmapCall(depth, maxargs, idmin, idmax) + } +} + +func (q *QueryMaker) RandomTopN(maxN, depth, maxargs int, idmin, idmax uint64) *pql.TopN { + frameIdx := q.R.Intn(len(q.Frames)) + return &pql.TopN{ + Frame: q.Frames[frameIdx], + N: q.R.Intn(maxN-1) + 1, + Src: q.RandomBitmapCall(depth, maxargs, idmin, idmax), + } +} + +func (q *QueryMaker) RandomBitmapCall(depth, maxargs int, idmin, idmax uint64) pql.BitmapCall { + if depth <= 1 { + bitmapID := q.R.Int63n(int64(idmax)-int64(idmin)) + int64(idmin) + return Bitmap(uint64(bitmapID), q.IDToFrameFn(uint64(bitmapID))) + } + call := q.R.Intn(4) + if call == 0 { + return q.RandomBitmapCall(1, 0, idmin, idmax) + } + + var numargs int + if maxargs <= 2 { + numargs = 2 + } else { + numargs = q.R.Intn(maxargs-2) + 2 + } + calls := make([]pql.BitmapCall, numargs) + for i := 0; i < numargs; i++ { + calls[i] = q.RandomBitmapCall(depth-1, maxargs, idmin, idmax) + } + + switch call { + case 1: + return Difference(calls...) + case 2: + return Intersect(calls...) + case 3: + return Union(calls...) + } + return nil +} + +/////////////////////////////////////////////////// +// Helpers TODO: move elsewhere +/////////////////////////////////////////////////// + +func ClearBit(id uint64, frame string, profileID uint64) *pql.ClearBit { + return &pql.ClearBit{ + ID: id, + Frame: frame, + ProfileID: profileID, + } +} + +func Count(bm pql.BitmapCall) *pql.Count { + return &pql.Count{ + Input: bm, + } +} + +func Profile(id uint64) *pql.Profile { + return &pql.Profile{ + ID: id, + } +} + +func SetBit(id uint64, frame string, profileID uint64) *pql.SetBit { + return &pql.SetBit{ + ID: id, + Frame: frame, + ProfileID: profileID, + } +} + +func SetBitmapAttrs(id uint64, frame string, attrs map[string]interface{}) *pql.SetBitmapAttrs { + return &pql.SetBitmapAttrs{ + ID: id, + Frame: frame, + Attrs: attrs, + } +} + +func SetProfileAttrs(id uint64, attrs map[string]interface{}) *pql.SetProfileAttrs { + return &pql.SetProfileAttrs{ + ID: id, + Attrs: attrs, + } +} + +func TopN(frame string, n int, src pql.BitmapCall, bmids []uint64, field string, filters []interface{}) *pql.TopN { + return &pql.TopN{ + Frame: frame, + N: n, + Src: src, + BitmapIDs: bmids, + Field: field, + Filters: filters, + } +} + +func Difference(bms ...pql.BitmapCall) *pql.Difference { + // TODO does this need to be limited to two inputs? + return &pql.Difference{ + Inputs: bms, + } +} + +func Intersect(bms ...pql.BitmapCall) *pql.Intersect { + return &pql.Intersect{ + Inputs: bms, + } +} + +func Union(bms ...pql.BitmapCall) *pql.Union { + return &pql.Union{ + Inputs: bms, + } +} + +func Bitmap(id uint64, frame string) *pql.Bitmap { + return &pql.Bitmap{ + ID: id, + Frame: frame, + } +} diff --git a/bench/query_test.go b/bench/query_test.go new file mode 100644 index 000000000..67b5c2521 --- /dev/null +++ b/bench/query_test.go @@ -0,0 +1,20 @@ +package bench_test + +import ( + "github.com/umbel/pilosa/bench" + "testing" +) + +func TestRandomBitmapCall(t *testing.T) { + qm := bench.NewQueryMaker(5) + bmc := qm.RandomBitmapCall(4, 3, 0, 1000) + t.Log(bmc.String()) +} + +func TestRandom(t *testing.T) { + for i := 99; i < 120; i++ { + qm := bench.NewQueryMaker(int64(i)) + call := qm.Random(10, 4, 3, 0, 1000) + t.Log(call) + } +}