Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
0c660e8
feat: add DDSketch quantile
srikanthccv Nov 5, 2023
a92cd40
Fix StyleCheck
srikanthccv Nov 5, 2023
5071d67
Move quantileddsketch.md under right dir
srikanthccv Nov 5, 2023
98c57ee
Update stateless test number and add stateful test
srikanthccv Nov 6, 2023
2fd66f5
Throw exception when relative accuracy is too low
srikanthccv Nov 10, 2023
b9c82c0
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 10, 2023
a9d2bc9
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 10, 2023
42d34df
Update test number
srikanthccv Nov 10, 2023
5dde614
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 10, 2023
5b593fb
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 11, 2023
7944ba5
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 11, 2023
495bfbd
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 12, 2023
ef6dd5d
Resolve merge conflicts
srikanthccv Nov 14, 2023
7c0c750
Fix undefined behaviour for empty store
srikanthccv Nov 14, 2023
d6468fd
Fix quantileGK test
srikanthccv Nov 14, 2023
24b475e
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 14, 2023
c22b63e
Update test numbers
srikanthccv Nov 14, 2023
7a56c38
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 14, 2023
cb42198
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 21, 2023
d173be0
Update src/AggregateFunctions/
srikanthccv Nov 21, 2023
03b8b51
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 24, 2023
81ec89f
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 25, 2023
d88ec46
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 26, 2023
1bd1af8
Throw exception on out of range values
srikanthccv Nov 26, 2023
2f89d71
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 26, 2023
b60e16d
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Nov 27, 2023
8536be3
Update relative accuracy docs and add encoding details
srikanthccv Nov 28, 2023
52d293e
Address review comments and suggestions
srikanthccv Dec 2, 2023
a3ef5f2
Remove unused function
srikanthccv Dec 2, 2023
ce0ff8a
Address alexey review comments
srikanthccv Dec 4, 2023
e527cd6
Remove unused function isFloat64FieldType
srikanthccv Dec 4, 2023
b8f864f
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 4, 2023
aa05007
Throw error on invalid relative accuracy
srikanthccv Dec 4, 2023
5a4c283
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 5, 2023
cfa38b4
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 5, 2023
23cc8fc
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 6, 2023
a777850
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 6, 2023
0c158a3
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 7, 2023
ca29696
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 8, 2023
dfe0385
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 8, 2023
167ded4
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 9, 2023
f0f3f23
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 18, 2023
7c912b3
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 18, 2023
2fc87a7
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 24, 2023
182facf
Simplify mapping
srikanthccv Dec 25, 2023
27a6df8
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 25, 2023
2fb78f8
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 27, 2023
8aa354d
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 28, 2023
a1a7f57
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Dec 31, 2023
3db0b00
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 1, 2024
132d7f5
Address remaining review comments
srikanthccv Jan 9, 2024
42a5f4e
Add effective memory usage suggestions
srikanthccv Jan 9, 2024
cd12a94
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 9, 2024
39adc9e
Fix Stylecheck
srikanthccv Jan 9, 2024
5926fc7
Fix fast test
srikanthccv Jan 9, 2024
229a1e4
Incorporate bins capacity suggestion
srikanthccv Jan 9, 2024
b55529b
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 9, 2024
bb8fff3
Fix fuzzer
srikanthccv Jan 9, 2024
a216d8c
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 9, 2024
7a53b6f
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 11, 2024
6119a2f
Remove inheritance in Mapping, Store and DDSketch
srikanthccv Jan 13, 2024
d831792
Add checks for bin resizing
srikanthccv Jan 14, 2024
ea84d8f
Add note about the binary compatible implementation
srikanthccv Jan 14, 2024
c40318d
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 14, 2024
068f6e2
Merge remote-tracking branch 'upstream/master' into ddsketch-quantile
srikanthccv Jan 17, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ ClickHouse-specific aggregate functions:
- [quantileTDigestWeighted](/docs/en/sql-reference/aggregate-functions/reference/quantiletdigestweighted.md)
- [quantileBFloat16](/docs/en/sql-reference/aggregate-functions/reference/quantilebfloat16.md#quantilebfloat16)
- [quantileBFloat16Weighted](/docs/en/sql-reference/aggregate-functions/reference/quantilebfloat16.md#quantilebfloat16weighted)
- [quantileDDSketch](/docs/en/sql-reference/aggregate-functions/reference/quantileddsketch.md#quantileddsketch)
- [simpleLinearRegression](/docs/en/sql-reference/aggregate-functions/reference/simplelinearregression.md)
- [stochasticLinearRegression](/docs/en/sql-reference/aggregate-functions/reference/stochasticlinearregression.md)
- [stochasticLogisticRegression](/docs/en/sql-reference/aggregate-functions/reference/stochasticlogisticregression.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Functions:
- `medianTDigest` — Alias for [quantileTDigest](../../../sql-reference/aggregate-functions/reference/quantiletdigest.md#quantiletdigest).
- `medianTDigestWeighted` — Alias for [quantileTDigestWeighted](../../../sql-reference/aggregate-functions/reference/quantiletdigestweighted.md#quantiletdigestweighted).
- `medianBFloat16` — Alias for [quantileBFloat16](../../../sql-reference/aggregate-functions/reference/quantilebfloat16.md#quantilebfloat16).
- `medianDDSketch` — Alias for [quantileDDSketch](../../../sql-reference/aggregate-functions/reference/quantileddsketch.md#quantileddsketch).

**Example**

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
slug: /en/sql-reference/aggregate-functions/reference/quantileddsketch
sidebar_position: 211
title: quantileDDSketch
---

Computes an approximate [quantile](https://en.wikipedia.org/wiki/Quantile) of a sample with relative-error guarantees. It works by building a [DDSketch](https://www.vldb.org/pvldb/vol12/p2195-masson.pdf).

**Syntax**

``` sql
quantileDDsketch[relative_accuracy, (level)](expr)
```

**Arguments**

- `expr` — Column with numeric data. [Integer](../../../sql-reference/data-types/int-uint.md), [Float](../../../sql-reference/data-types/float.md).

**Parameters**

- `relative_accuracy` — Relative accuracy of the quantile. Possible values are in the range from 0 to 1. [Float](../../../sql-reference/data-types/float.md). The size of the sketch depends on the range of the data and the relative accuracy. The larger the range and the smaller the relative accuracy, the larger the sketch. The rough memory size of the of the sketch is `log(max_value/min_value)/relative_accuracy`. The recommended value is 0.001 or higher.

- `level` — Level of quantile. Optional. Possible values are in the range from 0 to 1. Default value: 0.5. [Float](../../../sql-reference/data-types/float.md).

**Returned value**

- Approximate quantile of the specified level.

Type: [Float64](../../../sql-reference/data-types/float.md#float32-float64).

**Example**

Input table has an integer and a float columns:

``` text
┌─a─┬─────b─┐
│ 1 │ 1.001 │
│ 2 │ 1.002 │
│ 3 │ 1.003 │
│ 4 │ 1.004 │
└───┴───────┘
```

Query to calculate 0.75-quantile (third quartile):

``` sql
SELECT quantileDDSketch(0.01, 0.75)(a), quantileDDSketch(0.01, 0.75)(b) FROM example_table;
```

Result:

``` text
┌─quantileDDSketch(0.01, 0.75)(a)─┬─quantileDDSketch(0.01, 0.75)(b)─┐
│ 2.974233423476717 │ 1.01 │
└─────────────────────────────────┴─────────────────────────────────┘
```

**See Also**

- [median](../../../sql-reference/aggregate-functions/reference/median.md#median)
- [quantiles](../../../sql-reference/aggregate-functions/reference/quantiles.md#quantiles)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sidebar_position: 201

Syntax: `quantiles(level1, level2, …)(x)`

All the quantile functions also have corresponding quantiles functions: `quantiles`, `quantilesDeterministic`, `quantilesTiming`, `quantilesTimingWeighted`, `quantilesExact`, `quantilesExactWeighted`, `quantileInterpolatedWeighted`, `quantilesTDigest`, `quantilesBFloat16`. These functions calculate all the quantiles of the listed levels in one pass, and return an array of the resulting values.
All the quantile functions also have corresponding quantiles functions: `quantiles`, `quantilesDeterministic`, `quantilesTiming`, `quantilesTimingWeighted`, `quantilesExact`, `quantilesExactWeighted`, `quantileInterpolatedWeighted`, `quantilesTDigest`, `quantilesBFloat16`, `quantilesDDSketch`. These functions calculate all the quantiles of the listed levels in one pass, and return an array of the resulting values.

## quantilesExactExclusive

Expand Down
48 changes: 45 additions & 3 deletions src/AggregateFunctions/AggregateFunctionQuantile.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace ErrorCodes

template <typename> class QuantileTiming;
template <typename> class QuantileGK;

template <typename> class QuantileDDSketch;

/** Generic aggregate function for calculation of quantiles.
* It depends on quantile calculation data structure. Look at Quantile*.h for various implementations.
Expand Down Expand Up @@ -64,6 +64,7 @@ class AggregateFunctionQuantile final
using ColVecType = ColumnVectorOrDecimal<Value>;

static constexpr bool returns_float = !(std::is_same_v<FloatReturnType, void>);
static constexpr bool is_quantile_ddsketch = std::is_same_v<Data, QuantileDDSketch<Value>>;
static_assert(!is_decimal<Value> || !returns_float);

QuantileLevels<Float64> levels;
Expand All @@ -74,6 +75,9 @@ class AggregateFunctionQuantile final
/// Used for the approximate version of the algorithm (Greenwald-Khanna)
ssize_t accuracy = 10000;

/// Used for the quantile sketch
Float64 relative_accuracy = 0.01;

DataTypePtr & argument_type;

public:
Expand All @@ -87,7 +91,36 @@ class AggregateFunctionQuantile final
if (!returns_many && levels.size() > 1)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Aggregate function {} requires one level parameter or less", getName());

if constexpr (has_accuracy_parameter)
if constexpr (is_quantile_ddsketch)
{
if (params.empty())
throw Exception(
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Aggregate function {} requires at least one param", getName());

const auto & relative_accuracy_field = params[0];
if (relative_accuracy_field.getType() != Field::Types::Float64)
throw Exception(
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} requires relative accuracy parameter with Float64 type", getName());

relative_accuracy = relative_accuracy_field.get<Float64>();

if (relative_accuracy <= 0 || relative_accuracy >= 1 || isNaN(relative_accuracy))
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Aggregate function {} requires relative accuracy parameter with value between 0 and 1 but is {}",
getName(),
relative_accuracy);
// Throw exception if the relative accuracy is too small.
// This is to avoid the case where the user specifies a relative accuracy that is too small
// and the sketch is not able to allocate enough memory to satisfy the accuracy requirement.
if (relative_accuracy < 1e-6)
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Aggregate function {} requires relative accuracy parameter with value greater than 1e-6 but is {}",
getName(),
relative_accuracy);
}
else if constexpr (has_accuracy_parameter)
{
if (params.empty())
throw Exception(
Expand Down Expand Up @@ -116,7 +149,9 @@ class AggregateFunctionQuantile final

void create(AggregateDataPtr __restrict place) const override /// NOLINT
{
if constexpr (has_accuracy_parameter)
if constexpr (is_quantile_ddsketch)
new (place) Data(relative_accuracy);
else if constexpr (has_accuracy_parameter)
new (place) Data(accuracy);
else
new (place) Data;
Expand Down Expand Up @@ -147,6 +182,10 @@ class AggregateFunctionQuantile final
{
/// Return normalized state type: quantiles*(1)(...)
Array params{1};
if constexpr (is_quantile_ddsketch)
params = {relative_accuracy, 1};
else if constexpr (has_accuracy_parameter)
params = {accuracy, 1};
AggregateFunctionProperties properties;
return std::make_shared<DataTypeAggregateFunction>(
AggregateFunctionFactory::instance().get(
Expand Down Expand Up @@ -295,4 +334,7 @@ struct NameQuantilesBFloat16Weighted { static constexpr auto name = "quantilesBF
struct NameQuantileGK { static constexpr auto name = "quantileGK"; };
struct NameQuantilesGK { static constexpr auto name = "quantilesGK"; };

struct NameQuantileDDSketch { static constexpr auto name = "quantileDDSketch"; };
struct NameQuantilesDDSketch { static constexpr auto name = "quantilesDDSketch"; };

}
61 changes: 61 additions & 0 deletions src/AggregateFunctions/AggregateFunctionQuantileDDSketch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <AggregateFunctions/AggregateFunctionQuantile.h>
#include <AggregateFunctions/QuantileDDSketch.h>
#include <AggregateFunctions/AggregateFunctionFactory.h>
#include <AggregateFunctions/Helpers.h>
#include <DataTypes/DataTypeDate.h>
#include <DataTypes/DataTypeDateTime.h>
#include <Core/Field.h>


namespace DB
{
struct Settings;

namespace ErrorCodes
{
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
}

namespace
{

template <typename Value, bool float_return> using FuncQuantileDDSketch = AggregateFunctionQuantile<Value, QuantileDDSketch<Value>, NameQuantileDDSketch, false, std::conditional_t<float_return, Float64, void>, false, true>;
template <typename Value, bool float_return> using FuncQuantilesDDSketch = AggregateFunctionQuantile<Value, QuantileDDSketch<Value>, NameQuantilesDDSketch, false, std::conditional_t<float_return, Float64, void>, true, true>;


template <template <typename, bool> class Function>
AggregateFunctionPtr createAggregateFunctionQuantile(
const std::string & name, const DataTypes & argument_types, const Array & params, const Settings *)
{
/// Second argument type check doesn't depend on the type of the first one.
Function<void, true>::assertSecondArg(argument_types);

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

#define DISPATCH(TYPE) \
if (which.idx == TypeIndex::TYPE) return std::make_shared<Function<TYPE, true>>(argument_types, params);
FOR_BASIC_NUMERIC_TYPES(DISPATCH)
#undef DISPATCH
if (which.idx == TypeIndex::Date) return std::make_shared<Function<DataTypeDate::FieldType, false>>(argument_types, params);
if (which.idx == TypeIndex::DateTime) return std::make_shared<Function<DataTypeDateTime::FieldType, false>>(argument_types, params);

throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument for aggregate function {}",
argument_type->getName(), name);
}

}

void registerAggregateFunctionsQuantileDDSketch(AggregateFunctionFactory & factory)
{
/// For aggregate functions returning array we cannot return NULL on empty set.
AggregateFunctionProperties properties = { .returns_default_when_only_null = true };

factory.registerFunction(NameQuantileDDSketch::name, createAggregateFunctionQuantile<FuncQuantileDDSketch>);
factory.registerFunction(NameQuantilesDDSketch::name, { createAggregateFunctionQuantile<FuncQuantilesDDSketch>, properties });

/// 'median' is an alias for 'quantile'
factory.registerAlias("medianDDSketch", NameQuantileDDSketch::name);
}

}
Loading