From 730f0ce3b2157fd4a756f93ec4a12c3070d884b3 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Tue, 30 Jun 2026 13:42:04 -0700 Subject: [PATCH 1/3] Adds union of unions. --- .../org/apache/datasketches/hll/HllUnion.java | 10 +++- .../datasketches/hll/UnionCaseTest.java | 54 ++++++++++++++----- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/apache/datasketches/hll/HllUnion.java b/src/main/java/org/apache/datasketches/hll/HllUnion.java index dca2cd7da..2738d68d7 100644 --- a/src/main/java/org/apache/datasketches/hll/HllUnion.java +++ b/src/main/java/org/apache/datasketches/hll/HllUnion.java @@ -176,7 +176,7 @@ public double getEstimate() { checkRebuildCurMinNumKxQ(gadget); return gadget.getEstimate(); } - + /** * Gets the effective lgConfigK for the HllUnion operator, which may be less than * lgMaxK. @@ -320,6 +320,14 @@ public void update(final HllSketch sketch) { gadget.hllSketchImpl = unionImpl(sketch, gadget, lgMaxK); } + /** + * Update this HllUnion operator with the given HllUnion. + * @param union the given HllUnion. + */ + public void update(final HllUnion union) { + gadget.hllSketchImpl = unionImpl(union.gadget, gadget, lgMaxK); + } + @Override void couponUpdate(final int coupon) { if (coupon == EMPTY) { return; } diff --git a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java index 84ec7ce9a..17d6cc82c 100644 --- a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java +++ b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java @@ -31,6 +31,8 @@ import static org.testng.Assert.assertTrue; import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import org.apache.datasketches.common.SketchesStateException; import org.testng.annotations.Test; @@ -40,6 +42,7 @@ */ public class UnionCaseTest { private static final String LS = System.getProperty("line.separator"); + private static final VarHandle GADGET_HANDLE; long v = 0; final static int maxLgK = 12; HllSketch source; @@ -48,47 +51,66 @@ public class UnionCaseTest { String hdr = String.format(hfmt, "caseNum","srcLgKStr","gdtLgKStr","srcType","gdtType", "srcSeg","gdtSeg","srcMode","gdtMode","srcOoof","gdtOoof"); + static { + try { + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(HllUnion.class, MethodHandles.lookup()); + GADGET_HANDLE = lookup.findVarHandle(HllUnion.class, "gadget", HllSketch.class); + } catch (Exception e) { throw new RuntimeException(e); } + } + @Test public void checkAllCases() { print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_4, false); + checkCase(i, HLL_4, false, false); } println(""); print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_6, false); + checkCase(i, HLL_6, false, false); } println(""); print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_8, false); + checkCase(i, HLL_8, false, false); } println(""); print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_4, true); + checkCase(i, HLL_8, false, true); + } + println(""); + + print(hdr); + for (int i = 0; i < 24; i++) { + checkCase(i, HLL_4, true, false); } println(""); print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_6, true); + checkCase(i, HLL_6, true, false); } println(""); print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_8, true); + checkCase(i, HLL_8, true, false); + } + println(""); + + print(hdr); + for (int i = 0; i < 24; i++) { + checkCase(i, HLL_8, true, true); } println(""); } - private void checkCase(final int caseNum, final TgtHllType srcType, final boolean srcSeg) { - source = getSource(caseNum, srcType, srcSeg); + private void checkCase(final int caseNum, final TgtHllType srcType, final boolean srcSeg, final boolean srcUnion) { + source = getSource(caseNum, srcType, srcSeg, srcUnion); final boolean gdtSeg = (caseNum & 1) > 0; final HllUnion union = getUnion(caseNum, gdtSeg); union.update(source); @@ -121,11 +143,17 @@ private void output(final int caseNum, final HllSketch source, final HllUnion un assertTrue(err < rse, "Err: " + err + ", RSE: " + rse); } - private HllSketch getSource(final int caseNum, final TgtHllType tgtHllType, final boolean useMemorySegment) { + private HllSketch getSource(final int caseNum, final TgtHllType tgtHllType, final boolean useMemorySegment, + final boolean useHllUnion) { final int srcLgK = getSrcLgK(caseNum, maxLgK); final int srcU = getSrcCount(caseNum, maxLgK); if (useMemorySegment) { return buildMemorySegmentSketch(srcLgK, tgtHllType, srcU); + } else if (useHllUnion) { + final HllSketch sk = buildHeapSketch(srcLgK, tgtHllType, srcU); + final HllUnion u = new HllUnion(maxLgK); + u.update(sk); + return (HllSketch) GADGET_HANDLE.get(u); } else { return buildHeapSketch(srcLgK, tgtHllType, srcU); } @@ -133,7 +161,7 @@ private HllSketch getSource(final int caseNum, final TgtHllType tgtHllType, fina private HllUnion getUnion(final int caseNum, final boolean useMemorySegment) { final int unionU = getUnionCount(caseNum); - return (useMemorySegment) ? buildMemorSegmentUnion(maxLgK, unionU) : buildHeapUnion(maxLgK, unionU); + return (useMemorySegment) ? buildMemorySegmentUnion(maxLgK, unionU) : buildHeapUnion(maxLgK, unionU); } private static int getUnionCount(final int caseNum) { @@ -394,7 +422,7 @@ private HllUnion buildHeapUnion(final int lgMaxK, final int n) { return u; } - private HllUnion buildMemorSegmentUnion(final int lgMaxK, final int n) { + private HllUnion buildMemorySegmentUnion(final int lgMaxK, final int n) { final int bytes = HllSketch.getMaxUpdatableSerializationBytes(lgMaxK, TgtHllType.HLL_8); final MemorySegment wseg = MemorySegment.ofArray(new byte[bytes]); final HllUnion u = new HllUnion(lgMaxK, wseg); @@ -436,7 +464,7 @@ static void println(final Object o) { * @param o value to print */ static void print(final Object o) { - //System.out.print(o.toString()); //disable here + System.out.print(o.toString()); //disable here } /** @@ -444,7 +472,7 @@ static void print(final Object o) { * @param args arguments */ static void printf(final String fmt, final Object...args) { - //System.out.printf(fmt, args); //disable here + System.out.printf(fmt, args); //disable here } } From f98acf0d95b1afec1ec3c1c5c328a11374a13af8 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Tue, 30 Jun 2026 13:42:56 -0700 Subject: [PATCH 2/3] suppress printing --- src/test/java/org/apache/datasketches/hll/UnionCaseTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java index 17d6cc82c..500b63b06 100644 --- a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java +++ b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java @@ -464,7 +464,7 @@ static void println(final Object o) { * @param o value to print */ static void print(final Object o) { - System.out.print(o.toString()); //disable here + //System.out.print(o.toString()); //disable here } /** @@ -472,7 +472,7 @@ static void print(final Object o) { * @param args arguments */ static void printf(final String fmt, final Object...args) { - System.out.printf(fmt, args); //disable here + //System.out.printf(fmt, args); //disable here } } From 16a8a31129cc3b2ad5d85496b91e32fc9293371b Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Tue, 30 Jun 2026 14:46:06 -0700 Subject: [PATCH 3/3] Update PR#737 --- .../datasketches/hll/UnionCaseTest.java | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java index 500b63b06..608585f5e 100644 --- a/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java +++ b/src/test/java/org/apache/datasketches/hll/UnionCaseTest.java @@ -31,8 +31,8 @@ import static org.testng.Assert.assertTrue; import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; +//import java.lang.invoke.MethodHandles; +//import java.lang.invoke.VarHandle; import org.apache.datasketches.common.SketchesStateException; import org.testng.annotations.Test; @@ -42,22 +42,14 @@ */ public class UnionCaseTest { private static final String LS = System.getProperty("line.separator"); - private static final VarHandle GADGET_HANDLE; long v = 0; final static int maxLgK = 12; - HllSketch source; - //HllUnion union; + HllSketch skSource; + HllUnion uSource; String hfmt = "%10s%10s%10s%10s%10s%10s%10s%10s%10s%10s%10s" + LS; String hdr = String.format(hfmt, "caseNum","srcLgKStr","gdtLgKStr","srcType","gdtType", "srcSeg","gdtSeg","srcMode","gdtMode","srcOoof","gdtOoof"); - static { - try { - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(HllUnion.class, MethodHandles.lookup()); - GADGET_HANDLE = lookup.findVarHandle(HllUnion.class, "gadget", HllSketch.class); - } catch (Exception e) { throw new RuntimeException(e); } - } - @Test public void checkAllCases() { print(hdr); @@ -80,7 +72,7 @@ public void checkAllCases() { print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_8, false, true); + checkCase(i, HLL_8, false, true); //srcUnion } println(""); @@ -104,18 +96,26 @@ public void checkAllCases() { print(hdr); for (int i = 0; i < 24; i++) { - checkCase(i, HLL_8, true, true); + checkCase(i, HLL_8, true, true); //srcUnion } println(""); } private void checkCase(final int caseNum, final TgtHllType srcType, final boolean srcSeg, final boolean srcUnion) { - source = getSource(caseNum, srcType, srcSeg, srcUnion); + if (srcUnion) { + uSource = getUnionSrc(caseNum); + } else { + skSource = getSkSource(caseNum, srcType, srcSeg); + } final boolean gdtSeg = (caseNum & 1) > 0; final HllUnion union = getUnion(caseNum, gdtSeg); - union.update(source); + if (srcUnion) { + union.update(uSource); + } else { + union.update(skSource); + } final int totalU = getSrcCount(caseNum, maxLgK) + getUnionCount(caseNum); - output(caseNum, source, union, totalU); + output(caseNum, skSource, union, totalU); } private void output(final int caseNum, final HllSketch source, final HllUnion union, final int totalU) { @@ -143,22 +143,25 @@ private void output(final int caseNum, final HllSketch source, final HllUnion un assertTrue(err < rse, "Err: " + err + ", RSE: " + rse); } - private HllSketch getSource(final int caseNum, final TgtHllType tgtHllType, final boolean useMemorySegment, - final boolean useHllUnion) { + private HllSketch getSkSource(final int caseNum, final TgtHllType tgtHllType, final boolean useMemorySegment) { final int srcLgK = getSrcLgK(caseNum, maxLgK); final int srcU = getSrcCount(caseNum, maxLgK); if (useMemorySegment) { return buildMemorySegmentSketch(srcLgK, tgtHllType, srcU); - } else if (useHllUnion) { - final HllSketch sk = buildHeapSketch(srcLgK, tgtHllType, srcU); - final HllUnion u = new HllUnion(maxLgK); - u.update(sk); - return (HllSketch) GADGET_HANDLE.get(u); } else { return buildHeapSketch(srcLgK, tgtHllType, srcU); } } + private HllUnion getUnionSrc(final int caseNum) { + final int srcLgK = getSrcLgK(caseNum, maxLgK); + final int srcU = getSrcCount(caseNum, maxLgK); + final HllSketch sk = buildHeapSketch(srcLgK, HLL_8, srcU); + final HllUnion u = new HllUnion(maxLgK); + u.update(sk); + return u; + } + private HllUnion getUnion(final int caseNum, final boolean useMemorySegment) { final int unionU = getUnionCount(caseNum); return (useMemorySegment) ? buildMemorySegmentUnion(maxLgK, unionU) : buildHeapUnion(maxLgK, unionU);