mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Merge pull request #455 from benbjohnson/merge-bitmap-profile-call
Consolidate Bitmap() & Profile() calls.
This commit is contained in:
commit
47a68bc3bd
2 changed files with 111 additions and 42 deletions
77
executor.go
77
executor.go
|
|
@ -100,8 +100,6 @@ func (e *Executor) executeCall(ctx context.Context, db string, c *pql.Call, slic
|
|||
return e.executeClearBit(ctx, db, c, opt)
|
||||
case "Count":
|
||||
return e.executeCount(ctx, db, c, slices, opt)
|
||||
case "Profile":
|
||||
return e.executeProfile(ctx, db, c, opt)
|
||||
case "SetBit":
|
||||
return e.executeSetBit(ctx, db, c, opt)
|
||||
case "SetBitmapAttrs":
|
||||
|
|
@ -156,21 +154,32 @@ func (e *Executor) executeBitmapCall(ctx context.Context, db string, c *pql.Call
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Attach bitmap attributes for Bitmap() calls.
|
||||
// Attach attributes for Bitmap() calls.
|
||||
// If the column label is used then return profile attributes.
|
||||
// If the row label is used then return bitmap attributes.
|
||||
bm, _ := other.(*Bitmap)
|
||||
if c.Name == "Bitmap" {
|
||||
frame, _ := c.Args["frame"].(string)
|
||||
|
||||
fr := e.Index.Frame(db, frame)
|
||||
if fr != nil {
|
||||
rowLabel := fr.RowLabel()
|
||||
rowID, _ := c.Args[rowLabel].(uint64)
|
||||
|
||||
attrs, err := fr.BitmapAttrStore().Attrs(rowID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
d := e.Index.DB(db)
|
||||
if d != nil {
|
||||
columnLabel := d.ColumnLabel()
|
||||
if columnID, ok := c.Args[columnLabel].(uint64); ok {
|
||||
attrs, err := d.ProfileAttrStore().Attrs(columnID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bm.Attrs = attrs
|
||||
} else {
|
||||
frame, _ := c.Args["frame"].(string)
|
||||
if fr := d.Frame(frame); fr != nil {
|
||||
rowLabel := fr.RowLabel()
|
||||
rowID, _ := c.Args[rowLabel].(uint64)
|
||||
attrs, err := fr.BitmapAttrStore().Attrs(rowID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bm.Attrs = attrs
|
||||
}
|
||||
}
|
||||
bm.Attrs = attrs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,27 +339,47 @@ func (e *Executor) executeDifferenceSlice(ctx context.Context, db string, c *pql
|
|||
}
|
||||
|
||||
func (e *Executor) executeBitmapSlice(ctx context.Context, db string, c *pql.Call, slice uint64) (*Bitmap, error) {
|
||||
// Fetch column label from database.
|
||||
d := e.Index.DB(db)
|
||||
if d == nil {
|
||||
return nil, ErrDatabaseNotFound
|
||||
}
|
||||
columnLabel := d.ColumnLabel()
|
||||
|
||||
// Fetch frame & row label based on argument.
|
||||
frame, _ := c.Args["frame"].(string)
|
||||
if frame == "" {
|
||||
frame = DefaultFrame
|
||||
}
|
||||
|
||||
f := e.Index.Frame(db, frame)
|
||||
if f == nil {
|
||||
return nil, ErrFrameNotFound
|
||||
}
|
||||
rowLabel := f.RowLabel()
|
||||
|
||||
rowID, ok := c.Args[rowLabel].(uint64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Bitmap() field required: %s", rowLabel)
|
||||
// Return an error if both the row and column label are specified.
|
||||
rowID, rowOK := c.Args[rowLabel].(uint64)
|
||||
columnID, columnOK := c.Args[columnLabel].(uint64)
|
||||
if rowOK && columnOK {
|
||||
return nil, fmt.Errorf("Bitmap() cannot specify both %s and %s values", rowLabel, columnLabel)
|
||||
} else if !rowOK && !columnOK {
|
||||
return nil, fmt.Errorf("Bitmap() must specify either %s or %s values", rowLabel, columnLabel)
|
||||
}
|
||||
|
||||
frag := e.Index.Fragment(db, frame, ViewStandard, slice)
|
||||
// Determine row or column orientation.
|
||||
view, id := ViewStandard, rowID
|
||||
if columnOK {
|
||||
view, id = ViewInverse, columnID
|
||||
if !f.InverseEnabled() {
|
||||
return nil, fmt.Errorf("Bitmap() cannot retrieve columns unless inverse storage enabled")
|
||||
}
|
||||
}
|
||||
|
||||
frag := e.Index.Fragment(db, frame, view, slice)
|
||||
if frag == nil {
|
||||
return NewBitmap(), nil
|
||||
}
|
||||
return frag.Bitmap(rowID), nil
|
||||
return frag.Bitmap(id), nil
|
||||
}
|
||||
|
||||
// executeIntersectSlice executes a intersect() call for a local slice.
|
||||
|
|
@ -482,12 +511,6 @@ func (e *Executor) executeCount(ctx context.Context, db string, c *pql.Call, sli
|
|||
return n, nil
|
||||
}
|
||||
|
||||
// executeProfile executes a Profile() call.
|
||||
// This call only executes locally since the profile attibutes are stored locally.
|
||||
func (e *Executor) executeProfile(ctx context.Context, db string, c *pql.Call, opt *ExecOptions) (*Profile, error) {
|
||||
panic("FIXME: impl: e.Index.ProfileAttr(c.ID)")
|
||||
}
|
||||
|
||||
// executeClearBit executes a ClearBit() call.
|
||||
func (e *Executor) executeClearBit(ctx context.Context, db string, c *pql.Call, opt *ExecOptions) (bool, error) {
|
||||
view, _ := c.Args["view"].(string)
|
||||
|
|
@ -1165,7 +1188,7 @@ func needsSlices(calls []*pql.Call) bool {
|
|||
}
|
||||
for _, call := range calls {
|
||||
switch call.Name {
|
||||
case "ClearBit", "Profile", "SetBit", "SetBitmapAttrs", "SetProfileAttrs":
|
||||
case "ClearBit", "SetBit", "SetBitmapAttrs", "SetProfileAttrs":
|
||||
continue
|
||||
case "Count", "TopN":
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package pilosa_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -13,23 +14,68 @@ import (
|
|||
|
||||
// Ensure a bitmap query can be executed.
|
||||
func TestExecutor_Execute_Bitmap(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
idx.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).MustSetBits(10, 3)
|
||||
idx.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 1).MustSetBits(10, SliceWidth+1)
|
||||
t.Run("Row", func(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
db := idx.MustCreateDBIfNotExists("d", pilosa.DBOptions{})
|
||||
f, err := db.CreateFrame("f", pilosa.FrameOptions{InverseEnabled: true})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := idx.Frame("d", "f").BitmapAttrStore().SetAttrs(10, map[string]interface{}{"foo": "bar", "baz": uint64(123)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e := NewExecutor(idx.Index, NewCluster(1))
|
||||
|
||||
e := NewExecutor(idx.Index, NewCluster(1))
|
||||
if res, err := e.Execute(context.Background(), "d", MustParse(`Bitmap(id=10, frame=f)`), nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if bits := res[0].(*pilosa.Bitmap).Bits(); !reflect.DeepEqual(bits, []uint64{3, SliceWidth + 1}) {
|
||||
t.Fatalf("unexpected bits: %+v", bits)
|
||||
} else if attrs := res[0].(*pilosa.Bitmap).Attrs; !reflect.DeepEqual(attrs, map[string]interface{}{"foo": "bar", "baz": uint64(123)}) {
|
||||
t.Fatalf("unexpected attrs: %s", spew.Sdump(attrs))
|
||||
}
|
||||
// Set bits.
|
||||
if _, err := e.Execute(context.Background(), "d", MustParse(``+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 10, 3)+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 10, SliceWidth+1)+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 20, SliceWidth+1),
|
||||
), nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f.BitmapAttrStore().SetAttrs(10, map[string]interface{}{"foo": "bar", "baz": uint64(123)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if res, err := e.Execute(context.Background(), "d", MustParse(`Bitmap(id=10, frame=f)`), nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if bits := res[0].(*pilosa.Bitmap).Bits(); !reflect.DeepEqual(bits, []uint64{3, SliceWidth + 1}) {
|
||||
t.Fatalf("unexpected bits: %+v", bits)
|
||||
} else if attrs := res[0].(*pilosa.Bitmap).Attrs; !reflect.DeepEqual(attrs, map[string]interface{}{"foo": "bar", "baz": uint64(123)}) {
|
||||
t.Fatalf("unexpected attrs: %s", spew.Sdump(attrs))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Column", func(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
db := idx.MustCreateDBIfNotExists("d", pilosa.DBOptions{})
|
||||
if _, err := db.CreateFrame("f", pilosa.FrameOptions{InverseEnabled: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e := NewExecutor(idx.Index, NewCluster(1))
|
||||
|
||||
// Set bits.
|
||||
if _, err := e.Execute(context.Background(), "d", MustParse(``+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 10, 3)+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 10, SliceWidth+1)+
|
||||
fmt.Sprintf("SetBit(frame=f, id=%d, profileID=%d)\n", 20, SliceWidth+1),
|
||||
), nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.ProfileAttrStore().SetAttrs(SliceWidth+1, map[string]interface{}{"foo": "bar", "baz": uint64(123)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if res, err := e.Execute(context.Background(), "d", MustParse(fmt.Sprintf(`Bitmap(profileID=%d, frame=f)`, SliceWidth+1)), nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if bits := res[0].(*pilosa.Bitmap).Bits(); !reflect.DeepEqual(bits, []uint64{10, 20}) {
|
||||
t.Fatalf("unexpected bits: %+v", bits)
|
||||
} else if attrs := res[0].(*pilosa.Bitmap).Attrs; !reflect.DeepEqual(attrs, map[string]interface{}{"foo": "bar", "baz": uint64(123)}) {
|
||||
t.Fatalf("unexpected attrs: %s", spew.Sdump(attrs))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a difference query can be executed.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue