ClickHouse: агрегаты¶
В hare.dialects.clickhouse.functions.aggregates — собственные агрегаты ClickHouse. Они работают в
annotate(), aggregate() и Window(...), как агрегаты hare, и принимают _filter= и distinct=True,
как любой агрегат.
from hare.dialects.clickhouse.functions.aggregates import ArgMax, Quantile, TopK, Uniq
await PageView.objects.values("day").annotate(visitors=Uniq("visitor_id"))
await Quote.objects.values("symbol").annotate(last_price=ArgMax("price", "quoted_at"))
await PageView.objects.aggregate(typical=Quantile("load_ms", 0.5), slow=Quantile("load_ms", 0.99, exact=True))
await PageView.objects.aggregate(popular=TopK("path", 5))
Агрегаты¶
| Агрегат | SQL | Результат |
|---|---|---|
Uniq(field) |
uniq |
Примерно сколько различных значений в группе — оценка по выборке хешей, самая быстрая |
UniqExact(field) |
uniqExact |
Сколько различных значений, точно — все хранятся в памяти |
UniqCombined(field) |
uniqCombined |
Оценка в меньшей памяти и точнее Uniq при многих значениях |
Quantile(field, level=0.5, *, exact=False) |
quantile(level), quantileExact(level) |
Значение, ниже которого лежит доля level значений, — интерполированная оценка или, с exact=True, одно из значений |
Quantiles(field, *levels, exact=False) |
quantiles(...), quantilesExact(...) |
Несколько квантилей за один проход — массив в порядке уровней |
Median(field, *, exact=False) |
quantile(0.5) |
Медиана — оценка или, с exact=True, среднее значение |
ArgMin(field, by), ArgMax(field, by) |
argMin, argMax |
Значение field в строке группы, где by наименьшее или наибольшее |
GroupArray(field, *, max_size=None) |
groupArray |
Значения массивом в порядке чтения, без NULL; max_size оставляет столько первых |
GroupUniqArray(field, *, max_size=None) |
groupUniqArray |
Различные значения массивом, без порядка; max_size оставляет не больше стольких |
TopK(field, k=10) |
topK(k) |
Примерно k самых частых значений, самое частое первым, — точно только при немногих различных значениях |
AnyValue(field), AnyLast(field) |
any, anyLast |
Первое или последнее значение группы, какое встретит ClickHouse |
SumMap(field) |
sumMap |
Словари MapField, сложенные по ключам |
Quantiles, GroupArray, GroupUniqArray и TopK дают список, SumMap — словарь. Uniq, Quantile
и TopK — оценки и на многих строках могут отличаться от запуска к запуску; UniqExact и exact=True
детерминированы.
_filter, distinct и пустые группы¶
_filter=Q(...)пишется какFILTER (WHERE ...), аdistinct=True— какDISTINCTвнутри вызова, как в других базах; ClickHouse выполняет их как свои комбинаторы-Ifи-Distinct.- На пустом наборе
Max,Min,Avg,StdDevиVarianceдаютNone, как и агрегаты ниже: каждый пишется в форме-OrNull(maxOrNull(amount)) — список см. вNULLот агрегата по пустому набору.Sumдаёт собственный0ClickHouse (0.00для десятичного;Noneдля поля сnull=True, и на наборе только изNULLтоже). В группирующем запросе, где в группе хотя бы одна строка, агрегат без_filterостаётся в простой и более быстрой форме. Выборочное отклонение или дисперсия по одному значению —None, а не NaN ClickHouse. - На пустом наборе (или только из
NULL)Quantile,Median,ArgMin,ArgMax,AnyValueиAnyLastдаютNone;Uniq/UniqExact—0(UniqCombinedот поля сnull=True—None: так считает самuniqCombinedв ClickHouse),GroupArray,GroupUniqArrayиTopK— пустой список, аQuantiles—NaNдля каждого уровня: внутри массива ClickHouse не хранитNULL; сexact=Trueпо целочисленному полю —0для каждого уровня (так считает самquantilesExactClickHouse). ArgMin/ArgMaxчитают только строки, гдеfieldнеNULL: значение строки с наименьшим или наибольшимbyсреди них, а неNone, когда строка с крайнимbyхранитNULL.ArrayAggиз hare — этоgroupArrayкортежей, каждый из которых держит значение: каждое значение — элементArrayAgghare, в том числеNULL, который простойgroupArrayпропускает; сdistinct=TrueэтоgroupUniqArray, а егоorder_byсортирует массив —NULLв значении сортировки встаёт туда, куда его ставит сортировка hare (последним по возрастанию, первым по убыванию), а все сортировки идут в одну сторону (по возрастанию или по убыванию; обе сразу даютUnSupportedError).