Skip to content

Commit

Permalink
Optimize the implementation of IntervalSet intersection (apache#2300)
Browse files Browse the repository at this point in the history
Co-authored-by: mwish <[email protected]>
Co-authored-by: Twice <[email protected]>
  • Loading branch information
3 people authored May 11, 2024
1 parent b2347f3 commit 1e23484
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
2 changes: 0 additions & 2 deletions src/cluster/redis_slot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

#include "redis_slot.h"

#include <stdlib.h>

#include <algorithm>
#include <cstdlib>
#include <string>
Expand Down
27 changes: 24 additions & 3 deletions src/search/interval.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,32 @@ struct IntervalSet {
}

friend IntervalSet operator&(const IntervalSet &l, const IntervalSet &r) {
if (l.IsEmpty() || r.IsEmpty()) {
return IntervalSet();
IntervalSet result;

if (l.intervals.empty() || r.intervals.empty()) {
return result;
}

auto it_l = l.intervals.begin();
auto it_r = r.intervals.begin();

while (it_l != l.intervals.end() && it_r != r.intervals.end()) {
// Find overlap between current intervals
double start = std::max(it_l->first, it_r->first);
double end = std::min(it_l->second, it_r->second);

if (start <= end) {
result.intervals.emplace_back(start, end);
}

if (it_l->second < it_r->second) {
++it_l;
} else {
++it_r;
}
}

return ~(~l | ~r);
return result;
}

friend IntervalSet operator|(const IntervalSet &l, const IntervalSet &r) {
Expand Down
26 changes: 23 additions & 3 deletions tests/cppunit/interval_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ TEST(IntervalSet, Simple) {
(IntervalSet::DataType{{IntervalSet::minf, 1}, {4, IntervalSet::inf}}));
ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 4) | IntervalSet(NumericCompareExpr::NE, 1)).intervals,
(IntervalSet::DataType{{IntervalSet::minf, 1}, {IntervalSet::NextNum(1), IntervalSet::inf}}));

ASSERT_TRUE((IntervalSet(Interval(1, 2)) & IntervalSet(Interval(3, 4))).IsEmpty());
ASSERT_EQ((IntervalSet(Interval(1, 2)) & IntervalSet(Interval(2, 4))).intervals, (IntervalSet::DataType{{2, 2}}));
ASSERT_EQ((IntervalSet(Interval(1, 3)) & IntervalSet(Interval(2, 4))).intervals, (IntervalSet::DataType{{2, 3}}));
ASSERT_EQ((IntervalSet(Interval(3, 8)) & (IntervalSet(Interval(1, 4)) | IntervalSet(Interval(5, 7)))).intervals,
(IntervalSet::DataType{{3, 4}, {5, 7}}));
ASSERT_EQ((IntervalSet(Interval(3, 8)) & (IntervalSet(Interval(1, 4)) | IntervalSet(Interval(9, 11)))).intervals,
(IntervalSet::DataType{{3, 4}}));
ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 1) & IntervalSet(NumericCompareExpr::LT, 4)).intervals,
(IntervalSet::DataType{{1, 4}}));
ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 1) & IntervalSet(NumericCompareExpr::NE, 4)).intervals,
Expand All @@ -60,9 +68,21 @@ TEST(IntervalSet, Simple) {
IntervalSet({2, 5}) | IntervalSet({7, 8}));
ASSERT_EQ(~IntervalSet({2, 8}), IntervalSet({IntervalSet::minf, 2}) | IntervalSet({8, IntervalSet::inf}));

for (auto i = 0; i < 1000; ++i) {
auto gen = [] { return static_cast<double>(rand()) / 100; };
auto geni = [&gen] { return IntervalSet({gen(), gen()}); };
for (auto i = 0; i < 2000; ++i) {
auto gen = [] { return static_cast<double>(std::rand()) / 100; };
auto geni = [&gen] {
auto r = std::rand() % 50;
if (r == 0) {
return IntervalSet(NumericCompareExpr::GET, gen());
} else if (r == 1) {
return IntervalSet(NumericCompareExpr::LT, gen());
} else if (r == 2) {
return IntervalSet(NumericCompareExpr::NE, gen());
} else {
return IntervalSet({gen(), gen()});
}
};

auto l = geni(), r = geni();
for (int j = 0; j < i % 10; ++j) {
l = l | geni();
Expand Down

0 comments on commit 1e23484

Please sign in to comment.