Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 39 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
+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
+41 −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)
137 changes: 137 additions & 0 deletions src/AggregateFunctions/AggregateFunctionUniqApacheHLL.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#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.

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