diff --git a/index/bitmap.go b/index/bitmap.go index c3395bb3d..881c50a6e 100644 --- a/index/bitmap.go +++ b/index/bitmap.go @@ -260,7 +260,7 @@ func Union(a_bm IBitmap, b_bm IBitmap) IBitmap { return output } -func AND_NOT(a_bm IBitmap, b_bm IBitmap) IBitmap { +func Difference(a_bm IBitmap, b_bm IBitmap) IBitmap { var a = a_bm.Min() var b = b_bm.Min() defer a.Close() diff --git a/index/bitmap_test.go b/index/bitmap_test.go index 24f966beb..2915ea21d 100644 --- a/index/bitmap_test.go +++ b/index/bitmap_test.go @@ -3,6 +3,7 @@ package index import ( "testing" "time" + . "github.com/smartystreets/goconvey/convey" ) @@ -17,17 +18,32 @@ func TestBitmaps(t *testing.T) { So(bc1, ShouldEqual, bc2) So(bc1, ShouldEqual, 4096) }) - Convey("function AND_NOT 1 and not 0 => true ", t, func() { + Convey("function Difference 1 and not 0 => true ", t, func() { bm1 := CreateRBBitmap() bm2 := CreateRBBitmap() SetBit(bm1, 1) //SetBit(bm2,2) - all := AND_NOT(bm1, bm2) + all := Difference(bm1, bm2) res := BitCount(all) So(1, ShouldEqual, res) }) + Convey("function Difference 1 and not 0 => true ", t, func() { + bm1 := CreateRBBitmap() + bm2 := CreateRBBitmap() + SetBit(bm1, 1) + SetBit(bm1, 2) + SetBit(bm1, 3) + SetBit(bm1, 4) + SetBit(bm2, 3) + //SetBit(bm2,2) + all := Difference(bm1, bm2) + res := BitCount(all) + + So(3, ShouldEqual, res) + }) + Convey("UNION even + odd equal 4096 ", t, func() { even := CreateRBBitmap() for i := uint64(0); i < uint64(4096); i += 2 { diff --git a/index/commands.go b/index/commands.go index 0ddcb0d2b..4f27c7483 100644 --- a/index/commands.go +++ b/index/commands.go @@ -79,6 +79,19 @@ func (self *CmdUnion) Execute(f *Fragment) Calculation { return f.union(self.bitmap_ids) } +type CmdDifference struct { + *Responder + bitmap_ids []BitmapHandle +} + +func NewDifference(bitmaps []BitmapHandle) *CmdDifference { + result := &CmdDifference{NewResponder("Difference"), bitmaps} + return result +} +func (self *CmdDifference) Execute(f *Fragment) Calculation { + return f.difference(self.bitmap_ids) +} + type CmdIntersect struct { *Responder bitmaps []BitmapHandle diff --git a/index/fragment_container.go b/index/fragment_container.go index 771ef0546..1abd38724 100644 --- a/index/fragment_container.go +++ b/index/fragment_container.go @@ -115,6 +115,17 @@ func (self *FragmentContainer) Union(frag_id util.SUUID, bh []BitmapHandle) (Bit return 0, errors.New("Invalid Bitmap Handle") } +func (self *FragmentContainer) Difference(frag_id util.SUUID, bh []BitmapHandle) (BitmapHandle, error) { + if fragment, found := self.GetFragment(frag_id); found { + request := NewDifference(bh) + fragment.requestChan <- request + result := request.Response() + util.SendTimer("fragmant_container_Difference", result.exec_time.Nanoseconds()) + return result.answer.(BitmapHandle), nil + } + return 0, errors.New("Invalid Bitmap Handle") +} + func (self *FragmentContainer) Get(frag_id util.SUUID, bitmap_id uint64) (BitmapHandle, error) { if fragment, found := self.GetFragment(frag_id); found { request := NewGet(bitmap_id) @@ -316,6 +327,7 @@ func (self *Fragment) union(bitmaps []BitmapHandle) BitmapHandle { } return self.AllocHandle(result) } + func (self *Fragment) intersect(bitmaps []BitmapHandle) BitmapHandle { var result IBitmap for i, id := range bitmaps { @@ -328,6 +340,20 @@ func (self *Fragment) intersect(bitmaps []BitmapHandle) BitmapHandle { } return self.AllocHandle(result) } + +func (self *Fragment) difference(bitmaps []BitmapHandle) BitmapHandle { + result := NewBitmap() + for i, id := range bitmaps { + bm, _ := self.getBitmap(id) + if i == 0 { + result = bm + } else { + result = Difference(result, bm) + } + } + return self.AllocHandle(result) +} + func (self *Fragment) Persist() { err := self.impl.Persist() if err != nil { diff --git a/index/fragment_container_test.go b/index/fragment_container_test.go index 9f9a167c6..585f79adf 100644 --- a/index/fragment_container_test.go +++ b/index/fragment_container_test.go @@ -6,6 +6,7 @@ import ( // "io/ioutil" // "time" "pilosa/util" + . "github.com/smartystreets/goconvey/convey" ) @@ -35,7 +36,7 @@ func TestFragment(t *testing.T) { So(num, ShouldEqual, 1) }) - Convey("Union/Intersect", t, func() { + Convey("Union/Intersect/Difference", t, func() { bi1 := uint64(1234) bi2 := uint64(4321) @@ -53,6 +54,11 @@ func TestFragment(t *testing.T) { num, _ = dummy.Count(general, result) So(num, ShouldEqual, 0) + + result, _ = dummy.Difference(general, handles) + num, _ = dummy.Count(general, result) + So(num, ShouldEqual, 1) + }) Convey("Union Empty", t, func() {