Skip to content
This repository was archived by the owner on Jul 7, 2020. It is now read-only.

Commit 8db047c

Browse files
committed
Merge pull request #5 from jmeagher/small-merge-fix
Fix handling of small cardinality cases in CountThenEstimate merges
2 parents fc18269 + d7b1b4c commit 8db047c

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/main/java/com/clearspring/analytics/stream/cardinality/CountThenEstimate.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,13 @@ public static CountThenEstimate mergeEstimators(CountThenEstimate... estimators)
333333

334334
if(untipped.size() > 0)
335335
{
336-
merged = new CountThenEstimate(0, untipped.get(0).builder);
337-
merged.tip();
336+
merged = new CountThenEstimate(untipped.get(0).tippingPoint, untipped.get(0).builder);
338337

339338
for(CountThenEstimate cte : untipped)
340339
{
341340
for(Object o : cte.counter)
342341
{
343-
merged.estimator.offer(o);
342+
merged.offer(o);
344343
}
345344
}
346345
}
@@ -351,8 +350,15 @@ public static CountThenEstimate mergeEstimators(CountThenEstimate... estimators)
351350
merged.estimator = tipped.remove(0);
352351
}
353352

354-
merged.estimator = merged.estimator.merge(tipped.toArray(new ICardinality[tipped.size()]));
355-
353+
if (!tipped.isEmpty())
354+
{
355+
if (!merged.tipped)
356+
{
357+
merged.tip();
358+
}
359+
merged.estimator = merged.estimator.merge(tipped.toArray(new ICardinality[tipped.size()]));
360+
}
361+
356362
}
357363
return merged;
358364
}

src/test/java/com/clearspring/analytics/stream/cardinality/TestCountThenEstimate.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,55 @@ public void testMerge() throws CardinalityMergeException
7878
assertEquals(0.01, error, 0.01);
7979

8080

81+
}
82+
83+
@Test
84+
public void testSmallMerge() throws CardinalityMergeException
85+
{
86+
87+
// Untipped test case
88+
int numToMerge = 1000;
89+
int cardinalityPer = 5;
90+
91+
CountThenEstimate[] ctes = new CountThenEstimate[numToMerge];
92+
93+
for (int i = 0; i < numToMerge; i++)
94+
{
95+
ctes[i] = new CountThenEstimate(10000, AdaptiveCounting.Builder.obyCount(100000));
96+
for (int j = 0; j < cardinalityPer; j++)
97+
{
98+
ctes[i].offer(Math.random());
99+
}
100+
}
101+
102+
int expectedCardinality = numToMerge * cardinalityPer;
103+
CountThenEstimate merged = CountThenEstimate.mergeEstimators(ctes);
104+
long mergedEstimate = merged.cardinality();
105+
assertEquals(expectedCardinality, mergedEstimate);
106+
assertFalse(merged.tipped);
107+
108+
// Tipped test case
109+
numToMerge = 10;
110+
cardinalityPer = 100;
111+
112+
ctes = new CountThenEstimate[numToMerge];
113+
114+
for (int i = 0; i < numToMerge; i++)
115+
{
116+
ctes[i] = new CountThenEstimate(cardinalityPer + 1, AdaptiveCounting.Builder.obyCount(100000));
117+
for (int j = 0; j < cardinalityPer; j++)
118+
{
119+
ctes[i].offer(Math.random());
120+
}
121+
}
122+
123+
expectedCardinality = numToMerge * cardinalityPer;
124+
merged = CountThenEstimate.mergeEstimators(ctes);
125+
mergedEstimate = merged.cardinality();
126+
double error = Math.abs(mergedEstimate - expectedCardinality) / (double) expectedCardinality;
127+
assertEquals(0.01, error, 0.01);
128+
assertTrue(merged.tipped);
129+
81130
}
82131

83132
@Test

0 commit comments

Comments
 (0)