Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
62fabfd
Update contrib/datasketches-cpp to 5.2.0 and backport the HLL union fix
UnamedRus Sep 17, 2026
8cd0586
Add uniqApacheHLL: Apache DataSketches HLL as a native aggregate func…
UnamedRus Sep 17, 2026
c1d107c
Merge branch 'antalya-26.6' into feature/antalya-26.6/uniq-apache-hll
zvonand Sep 28, 2026
9c9c7fb
Simplify `uniqApacheHLL` implementation and tests
zvonand Sep 29, 2026
562352f
Fix `uniqApacheHLL` merge resolution below 7 and empty state serializ…
zvonand Sep 30, 2026
a6477a1
Merge branch 'antalya-26.6' into feature/antalya-26.6/uniq-apache-hll
zvonand Sep 30, 2026
81fb83c
Fix `uniqApacheHLL` on an all-NULL argument and merge its tests
zvonand Oct 1, 2026
00dbe28
ci: run aggregate functions regression
DimensionWieldr Oct 2, 2026
a626ce8
Defer folding in `uniqApacheHLL` and add missing includes
claude Oct 3, 2026
516fd39
Make `uniqApacheHLL` reject non-integer `lg_k` and skip merging empty…
claude Oct 3, 2026
5cc6aaa
Remove stray blank line in `AggregateFunctionUniqApacheHLL`
claude Oct 3, 2026
2440dbe
Use `FieldVisitorConvertToNumber` for the `uniqApacheHLL` parameter `…
UnamedRus Oct 5, 2026
12c65dd
Include `config.h` explicitly where `USE_DATASKETCHES` is used for re…
UnamedRus Oct 5, 2026
b403cd0
Update `contrib/datasketches-cpp` to include the compact theta preamb…
UnamedRus Oct 5, 2026
629b427
Merge branch 'antalya-26.6' into feature/antalya-26.6/uniq-apache-hll
UnamedRus Oct 5, 2026
254c630
Merge `rhs` sketches before folding the pending one in `uniqApacheHLL`
UnamedRus Oct 5, 2026
31e9e7a
Add a test pinning how `uniqApacheHLL` hashes every argument type on …
UnamedRus Oct 5, 2026
8d49460
Ignore empty strings in `uniqApacheHLL` and pin its `NULL` handling
UnamedRus Oct 5, 2026
30ad260
Keep the `uniqApacheHLL` state of a `Nullable` argument a bare DataSk…
UnamedRus Oct 5, 2026
a30cd57
Give the `uniqApacheHLL` state of a `Nullable` argument the type of t…
UnamedRus Oct 5, 2026
2033e7b
Let a function opt out of the flag and type of the `Null` and `If` wr…
UnamedRus Oct 5, 2026
e99077e
Merge branch 'feature/antalya-26.6/uniq-apache-hll' of github.com:Alt…
UnamedRus Oct 5, 2026
71ed5a7
Fix the expected output of two new `uniqApacheHLL` tests after the fi…
UnamedRus Oct 5, 2026
1bfd0e1
DCO remediation commit for UnamedRus <dtitmoav@gmail.com>
UnamedRus Oct 5, 2026
970be31
Stop converting `uniqApacheHLL` unions to the declared type to read o…
UnamedRus Oct 6, 2026
5f06020
Drop the speculative ordering comment in `uniqApacheHLL` merge
UnamedRus Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
url = https://github.com/ClickHouse/NuRaft
[submodule "contrib/datasketches-cpp"]
path = contrib/datasketches-cpp
url = https://github.com/apache/datasketches-cpp
url = https://github.com/ClickHouse/datasketches-cpp
[submodule "contrib/yaml-cpp"]
path = contrib/yaml-cpp
url = https://github.com/ClickHouse/yaml-cpp
Expand Down
2 changes: 1 addition & 1 deletion contrib/datasketches-cpp
Submodule datasketches-cpp updated 40 files
+1 −1 .github/workflows/build_cmake.yml
+1 −1 .github/workflows/code_coverage.yml
+1 −1 .github/workflows/doxygen.yml
+1 −1 .github/workflows/sanitize.yml
+7 −2 .github/workflows/serde_compat.yml
+1 −0 CMakeLists.txt
+35 −7 LICENSE
+2 −2 NOTICE
+2 −3 README.md
+2 −1 common/CMakeLists.txt
+1 −0 common/include/common_defs.hpp
+5 −7 common/include/quantiles_sorted_view_impl.hpp
+202 −0 common/include/xxhash64.h
+43 −0 filters/CMakeLists.txt
+180 −0 filters/include/bit_array_ops.hpp
+753 −0 filters/include/bloom_filter.hpp
+132 −0 filters/include/bloom_filter_builder_impl.hpp
+908 −0 filters/include/bloom_filter_impl.hpp
+60 −0 filters/test/CMakeLists.txt
+107 −0 filters/test/bit_array_ops_test.cpp
+75 −0 filters/test/bloom_filter_allocation_test.cpp
+51 −0 filters/test/bloom_filter_deserialize_from_java_test.cpp
+45 −0 filters/test/bloom_filter_serialize_for_java.cpp
+406 −0 filters/test/bloom_filter_test.cpp
+3 −0 hll/include/Hll8Array-internal.hpp
+4 −0 hll/include/HllArray-internal.hpp
+3 −0 hll/include/HllUnion-internal.hpp
+70 −0 hll/test/HllUnionTest.cpp
+6 −5 kll/test/kll_sketch_custom_type_test.cpp
+51 −1 tdigest/include/tdigest.hpp
+38 −1 tdigest/include/tdigest_impl.hpp
+12 −3 tdigest/test/tdigest_test.cpp
+5 −5 theta/include/bit_packing.hpp
+5 −1 theta/include/compact_theta_sketch_parser_impl.hpp
+1 −0 theta/include/theta_sketch_impl.hpp
+41 −38 theta/test/bit_packing_test.cpp
+17 −0 theta/test/theta_sketch_deserialize_from_java_test.cpp
+1 −1 theta/test/theta_sketch_serialize_for_java.cpp
+85 −0 theta/test/theta_sketch_test.cpp
+1 −1 version.cfg.in
1 change: 1 addition & 0 deletions contrib/datasketches-cpp-cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_library(_datasketches INTERFACE)
target_include_directories(_datasketches SYSTEM BEFORE INTERFACE
"${ClickHouse_SOURCE_DIR}/contrib/datasketches-cpp/common/include"
"${ClickHouse_SOURCE_DIR}/contrib/datasketches-cpp/count/include"
"${ClickHouse_SOURCE_DIR}/contrib/datasketches-cpp/hll/include"
"${ClickHouse_SOURCE_DIR}/contrib/datasketches-cpp/theta/include")

add_library(ch_contrib::datasketches ALIAS _datasketches)
140 changes: 140 additions & 0 deletions src/AggregateFunctions/AggregateFunctionUniqApacheHLL.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <AggregateFunctions/AggregateFunctionUniqApacheHLL.h>
#include <AggregateFunctions/AggregateFunctionFactory.h>
#include <AggregateFunctions/FactoryHelpers.h>
#include <Common/FieldVisitorConvertToNumber.h>

#if USE_DATASKETCHES

namespace DB
{

namespace ErrorCodes
{
extern const int ARGUMENT_OUT_OF_BOUND;
extern const int BAD_ARGUMENTS;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
}

static AggregateFunctionPtr createAggregateFunctionUniqApacheHLL(
const std::string & name, const DataTypes & argument_types, const Array & params, const Settings *)
{
uint8_t lg_config_k = 12;
datasketches::target_hll_type target_type = datasketches::HLL_4;

if (params.size() > 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
"Aggregate function {} accepts at most two parameters (lg_k, type).", name);

if (!params.empty())
{
const UInt64 lg_k_param = applyVisitor(FieldVisitorConvertToNumber<UInt64>(), params[0]);
if (lg_k_param < 4 || lg_k_param > 21)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND,
"Parameter lg_k for aggregate function {} is out of range: [4, 21].", name);
lg_config_k = static_cast<uint8_t>(lg_k_param);
}

if (params.size() == 2)
{
if (params[1].getType() != Field::Types::String)
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Parameter type for aggregate function {} must be a string.", name);

const String type_param = params[1].safeGet<String>();
if (type_param == "HLL_4")
target_type = datasketches::HLL_4;
else if (type_param == "HLL_6")
target_type = datasketches::HLL_6;
else if (type_param == "HLL_8")
target_type = datasketches::HLL_8;
else
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Parameter type for aggregate function {} must be one of 'HLL_4', 'HLL_6', 'HLL_8'.", name);
}

assertUnary(name, argument_types);

const IDataType & argument_type = *argument_types[0];
WhichDataType which(argument_type);

/// Unlike other decimals, `DateTime64` has an interoperable representation as epoch ticks.
if (which.isDateTime64())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeDateTime64::FieldType>>(lg_config_k, target_type, argument_types, params);

/// Exclude wide integers: DataSketches has no portable representation for them.
if (!which.isInt128() && !which.isInt256() && !which.isUInt128() && !which.isUInt256())
{
AggregateFunctionPtr res(createWithNumericType<AggregateFunctionUniqApacheHLL>(
argument_type, lg_config_k, target_type, argument_types, params));
if (res)
return res;
}

if (which.isDate())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeDate::FieldType>>(lg_config_k, target_type, argument_types, params);
if (which.isDate32())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeDate32::FieldType>>(lg_config_k, target_type, argument_types, params);
if (which.isDateTime())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeDateTime::FieldType>>(lg_config_k, target_type, argument_types, params);
if (which.isStringOrFixedString())
return std::make_shared<AggregateFunctionUniqApacheHLL<String>>(lg_config_k, target_type, argument_types, params);
if (which.isUUID())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeUUID::FieldType>>(lg_config_k, target_type, argument_types, params);
if (which.isIPv4())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeIPv4::FieldType>>(lg_config_k, target_type, argument_types, params);
if (which.isIPv6())
return std::make_shared<AggregateFunctionUniqApacheHLL<DataTypeIPv6::FieldType>>(lg_config_k, target_type, argument_types, params);

/// For `Nullable(Nothing)` the `Null` combinator replaces this function with `nothing`, but it must be created first.
if (argument_type.onlyNull())
return std::make_shared<AggregateFunctionUniqApacheHLL<UInt8>>(lg_config_k, target_type, argument_types, params);

throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Illegal type {} of argument for aggregate function {}. Use uniq, uniqCombined or uniqHLL12 for unsupported types.",
argument_type.getName(), name);
}

void registerAggregateFunctionUniqApacheHLL(AggregateFunctionFactory & factory);
void registerAggregateFunctionUniqApacheHLL(AggregateFunctionFactory & factory)
{
FunctionDocumentation::Description description = R"(
Calculates the approximate number of different argument values using an [Apache DataSketches](https://datasketches.apache.org/docs/HLL/HllSketches.html) HyperLogLog sketch.

The `-State` and `-Merge` combinators exchange Apache DataSketches HLL sketches with a varint length prefix.

For interoperability, integers of at most 64 bits are hashed as 8-byte integers, floating-point values as IEEE-754 doubles, strings as raw bytes, `UUID` values as canonical 16 bytes, and `IPv6` addresses in network order.
`Date`, `Date32`, `DateTime` and `DateTime64` use their underlying integer values. External producers must use the same unit; for example, `DateTime64(3)` uses epoch milliseconds.
Unsupported types and multiple arguments are rejected. Use `uniq`, `uniqCombined` or `uniqHLL12` for those inputs.

`NULL` values and empty strings are ignored, as in the Java, Python and C++ implementations and in Spark; unlike `uniq`, an empty string is not counted as a value.
A `Nullable` argument gives the same state as a non-`Nullable` one, a bare DataSketches sketch, and the same state type, `AggregateFunction(uniqApacheHLL, T)`.

Merging can switch from the HIP estimator to the less accurate composite estimator, so results can depend on partitioning across threads, parts and shards.
Merging a lower-resolution sketch permanently lowers the result's resolution, regardless of the declared `lg_k`.
)";
FunctionDocumentation::Syntax syntax = "uniqApacheHLL([lg_k, [type]])(x)";
FunctionDocumentation::Arguments arguments = {
{"x", "Column to compute the number of distinct values of.", {"(U)Int8/16/32/64", "Enum", "BFloat16", "Float32", "Float64", "String", "FixedString", "UUID", "IPv4", "IPv6", "Date", "Date32", "DateTime", "DateTime64"}},
};
FunctionDocumentation::Parameters parameters = {
{"lg_k", "Optional. Log-base-2 of the number of buckets, in range [4, 21]. Higher means better accuracy and more memory. Default: 12.", {"UInt8"}},
{"type", "Optional. Storage format of the sketch: 'HLL_4', 'HLL_6', or 'HLL_8'. Default: 'HLL_4'.", {"String"}},
};
FunctionDocumentation::ReturnedValue returned_value = {"Returns the approximate number of distinct values.", {"UInt64"}};
FunctionDocumentation::Examples examples = {
{"Basic usage", "SELECT uniqApacheHLL(number) FROM numbers(1000)", "1000"},
{"With parameters", "SELECT uniqApacheHLL(14, 'HLL_8')(number) FROM numbers(1000)", "1000"},
};
FunctionDocumentation::IntroducedIn introduced_in = {26, 6};
FunctionDocumentation::Category category = FunctionDocumentation::Category::AggregateFunction;
FunctionDocumentation documentation = {description, syntax, arguments, parameters, returned_value, examples, introduced_in, category};

AggregateFunctionProperties properties = { .returns_default_when_only_null = true, .is_order_dependent = false };

factory.registerFunction("uniqApacheHLL", {createAggregateFunctionUniqApacheHLL, documentation, properties});
}

}

#endif
Loading
Loading