From 07ae881967dd2aba1b20e90c7db18734dd1ad2a2 Mon Sep 17 00:00:00 2001 From: Travis Date: Thu, 5 Oct 2017 11:52:14 -0500 Subject: [PATCH] Add FieldNotNull for more efficient BETWEEN queries --- executor.go | 10 ++++++++++ executor_test.go | 17 +++++++++++++++++ fragment.go | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/executor.go b/executor.go index ae960a5e1..62ac7e7ff 100644 --- a/executor.go +++ b/executor.go @@ -727,6 +727,10 @@ func (e *Executor) executeFieldRangeSlice(ctx context.Context, index string, c * return nil, errors.New("Range(): BETWEEN condition requires exactly two integer values") } + // The reason we don't just call: + // return f.FieldRangeBetween(fieldName, predicates[0], predicates[1]) + // here is because we need the call to be slice-specific. + // Find field. field := f.Field(fieldName) if field == nil { @@ -744,6 +748,12 @@ func (e *Executor) executeFieldRangeSlice(ctx context.Context, index string, c * return NewBitmap(), nil } + // If the query is asking for the entire valid range, just return + // the not-null bitmap for the field. + if predicates[0] <= field.Min && predicates[1] >= field.Max { + return frag.FieldNotNull(field.BitDepth()) + } + return frag.FieldRangeBetween(field.BitDepth(), baseValueMin, baseValueMax) } else { diff --git a/executor_test.go b/executor_test.go index 482903bc2..2a5b90e4b 100644 --- a/executor_test.go +++ b/executor_test.go @@ -796,6 +796,23 @@ func TestExecutor_Execute_FieldRange(t *testing.T) { } }) + t.Run("BETWEEN", func(t *testing.T) { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, foo >< [1, 1000])`), nil, nil); err != nil { + t.Fatal(err) + } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Bitmap).Bits()) { + t.Fatalf("unexpected result: %s", spew.Sdump(result)) + } + }) + + // Ensure that the FieldNotNull code path gets run. + t.Run("FieldNotNull", func(t *testing.T) { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, foo >< [0, 1000])`), nil, nil); err != nil { + t.Fatal(err) + } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Bitmap).Bits()) { + t.Fatalf("unexpected result: %s", spew.Sdump(result)) + } + }) + t.Run("BelowMin", func(t *testing.T) { if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=f, foo == 0)`), nil, nil); err != nil { t.Fatal(err) diff --git a/fragment.go b/fragment.go index cca8c4ede..896096667 100644 --- a/fragment.go +++ b/fragment.go @@ -730,6 +730,11 @@ func (f *Fragment) fieldRangeGT(bitDepth uint, predicate uint64, allowEquality b return b, nil } +// FieldNotNull returns the not-null row (stored at bitDepth). +func (f *Fragment) FieldNotNull(bitDepth uint) (*Bitmap, error) { + return f.Row(uint64(bitDepth)), nil +} + func (f *Fragment) FieldRangeBetween(bitDepth uint, predicateMin, predicateMax uint64) (*Bitmap, error) { b := f.Row(uint64(bitDepth)) keep1 := NewBitmap() // GTE