TestMergeSfmSketchAggregation.java

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.operator.aggregation.noisyaggregation;

import com.facebook.presto.common.Page;
import com.facebook.presto.common.block.Block;
import com.facebook.presto.common.block.BlockBuilder;
import com.facebook.presto.operator.aggregation.noisyaggregation.sketch.SfmSketch;
import org.testng.annotations.Test;

import static com.facebook.presto.operator.aggregation.AggregationTestUtils.assertAggregation;
import static com.facebook.presto.type.SfmSketchType.SFM_SKETCH;

public class TestMergeSfmSketchAggregation
        extends AbstractTestNoisySfmAggregation
{
    protected String getFunctionName()
    {
        return "merge";
    }

    protected long getCardinalityFromResult(Object result)
    {
        return getSketchFromResult(result).cardinality();
    }

    private Block[] buildBlocks(SfmSketch... sketches)
    {
        BlockBuilder builder = SFM_SKETCH.createBlockBuilder(null, 3);
        for (SfmSketch sketch : sketches) {
            SFM_SKETCH.writeSlice(builder, sketch.serialize());
        }
        return new Block[] {builder.build()};
    }

    private void assertMergedCardinality(SfmSketch[] indivdualSketches, SfmSketch mergedSketch, double delta)
    {
        assertAggregation(
                getAggregator(getFunctionName(), SFM_SKETCH),
                (actualValue, expectedValue) -> equalCardinalityWithAbsoluteError(actualValue, expectedValue, delta),
                null,
                new Page(buildBlocks(indivdualSketches)),
                toSqlVarbinary(mergedSketch));
    }

    @Test
    public void testMergeOneNonPrivate()
    {
        SfmSketch sketch = createLongSketch(4096, 24, 1, 100_000);

        // deterministic test/no noise (no delta needed)
        assertMergedCardinality(new SfmSketch[] {sketch}, sketch, 0);
    }

    @Test
    public void testMergeOnePrivate()
    {
        SfmSketch sketch = createLongSketch(4096, 24, 1, 100_000);
        sketch.enablePrivacy(4);

        // although there is random noise in the sketch, the merge is a no-op, so no delta is needed
        assertMergedCardinality(new SfmSketch[] {sketch}, sketch, 0);
    }

    @Test
    public void testMergeManyNonPrivate()
    {
        SfmSketch sketch1 = createLongSketch(4096, 24, 1, 100_000);
        SfmSketch sketch2 = createLongSketch(4096, 24, 50_000, 200_000);
        SfmSketch sketch3 = createLongSketch(4096, 24, 190_000, 210_000);
        SfmSketch mergedSketch = createLongSketch(4096, 24, 1, 210_000);

        // deterministic test/no noise (no delta needed)
        assertMergedCardinality(new SfmSketch[] {sketch1, sketch2, sketch3}, mergedSketch, 0);
    }

    @Test
    public void testMergeManyPrivate()
    {
        SfmSketch sketch1 = createLongSketch(4096, 24, 1, 100_000);
        SfmSketch sketch2 = createLongSketch(4096, 24, 50_000, 200_000);
        SfmSketch sketch3 = createLongSketch(4096, 24, 190_000, 210_000);
        SfmSketch mergedSketch = createLongSketch(4096, 24, 1, 210_000);
        sketch1.enablePrivacy(10);
        sketch2.enablePrivacy(11);
        sketch3.enablePrivacy(12);

        // there is randomness in this merge, so the cardinality should only match approximately
        assertMergedCardinality(new SfmSketch[] {sketch1, sketch2, sketch3}, mergedSketch, 50_000);
    }
}