
Alexey
20.01.2017
18:00:28


Artem
20.01.2017
18:04:14
О мы как раз хотим его использовать тоже в блокчейне

Google

Artem
20.01.2017
18:04:18
Спасибо, посмотрю

Alexey
20.01.2017
18:06:56
https://twitter.com/blockchair
https://vk.com/blockchair

Artem
20.01.2017
18:10:34
Спасибо

prll
20.01.2017
18:23:19

Nikita
20.01.2017
18:23:20
До меня тут донесли, что мой поисковик пиарят, я тут :) Буду немного рассказывать про это на ближайшей конференции http://www.osp.ru/iz/blockchain
Всем доброго вечера!
Блокчейн — сам по себе — децентрализованная БД + механизм прихождения к консенсусу по вопросу “какие записи внесены в каком порядке”, поэтому Кликхаус тут не очень подходит. Но для аналитики Кликхаус — просто бомба.

Igor
20.01.2017
19:19:19
Добрый вечер, хочу презентовать пользователям CHGui - построение графиков и узнать что вы думаете о таком подходе к настройке графики - настройки прямо в запросе пишутся , и может кто то сталкивался с похожим решением в открытых/коммерческих продуктах -> чтобы можно было не изобретать, а просто откопировать документацию/решения ))
Для простых графиков все просто, а вот для Sankey/Treemap/Heatmap/punchCard - “велосипедостроение какоето” ))
Скринкаст dev версии: https://monosnap.com/file/O0tlFI6MJj5opkaOXjtJ5bYgjUjCyT

Alexey
20.01.2017
19:20:51
пытается ли scheduler вычислить сколько потребуется памяти для запроса?
По-умолчанию не пытается. Есть отдельные настройки - max_memory_usage_for_user и max_memory_usage_for_all_queries. Они работают весьма просто. Так, если max_memory_usage_for_user = 10 GB, и уже есть запросы, которые заняли 9.9GB, то следующий запрос будет почти сразу кидать исключение о том, что max_memory_usage_for_all_queries превышено.

Nikita
20.01.2017
19:23:36
Алексей, пользуясь случаем, всё хотел спросить — не появился пока changelog?

Alexey
20.01.2017
19:23:50

Google

Alexey
20.01.2017
19:23:59
Наверное, я просто плохо знаю Docker.


Nikita
20.01.2017
19:32:02
Без changelog страшновато обновляться, потому что часть логики иногда висит на немного костылях :)
rows_before_limit_at_least вроде бы точно работает с FINAL

Shine
20.01.2017
19:33:39

Alexey
20.01.2017
19:36:51
То, что на видео - уже хочу использовать. Это готово?


Igor
20.01.2017
19:50:13
> @milovidov_an
>Вроде бы в EventQL.
Как раз с него и взял идею писать прямо в запросе
>То, что на видео - уже хочу использовать. Это готово?
Пока нет, думаю/планирую собрать за 2-3 недели до стабильного состояния и выкатить одним большим обновлением - постарвюсь успеть к след. митапу )) Сейчас просто оочень не стабильно - только сегодня прикрутил Sankeys

Nikita
20.01.2017
19:54:10
@garikanet мм. а я правильно понимаю, что я могу взять nginx, поднять https, поднять basic авторизацию, засервить clickhouse-frontend, в nginx прпоисать location который будет проксировать в http api clickhouse, прописать этот путь в clickhouse-frontend и оно как-то заработает и можно давать ребятам уже играться с запросами? правда немного пугает, что нужен не RO пользователь.

Igor
20.01.2017
20:04:32
Да, если перед CH поставить nginx -> в GUI указать http://ip то будет работать ... мы у себя прямо со сборки guiclickhouse.smi2.ru подключаемся к CH, но у нас iptables+vpn
фичу RO юзера - поправлю в следующем релизе , проблема в том что gui послывает всегда параметр max_rows - который под ro вызывает ошибку переопределения в ch
Да и мне как то писать drop / create table в gui приятнее )


Kirill
21.01.2017
11:03:46
Привет, может кто-нибудь подсказать по структуре массивов в нативном протоколе, например у меня есть таблица
CREATE TABLE example
(
IntArray Array(Int8),
StrArray Array(String)
) ENGINE = Memory
мне приходит пакет вида:
column name - string (uvariant (strlen) + []byte (str))
column type - string (uvariant (strlen) + []byte (str))
{ // data
{
array len (uvariant)
}
values
}
мне интересны первые 8 байт, сначала в них идет длина, но она переменной длины,
после 8 байт идут данные массива которыя я вычитываю в зависимости от типа
интересует как получить данный офсет и зачем он нужен?

f1yegor
21.01.2017
12:15:18

Darafei
21.01.2017
15:33:14
эээм, комментарии через решётку?

f1yegor
21.01.2017
18:10:51

Roman
21.01.2017
18:32:06
на это похоже http://airbnb.io/superset/
Нее, суперсет это классический BI, а у Igor Str ноутбук вроде цепеллина получается. Еще не получился, конечно. Но в эту степь копает. Ноутбук с основным языком Clickhouse SQL и расширениями для визуализации.

Igor
21.01.2017
19:00:38
Да мне ноутбук ближе по стилю оказался. Но идеи из суперсета я тоже планирую реализовать, пользовался им год назад на протяжении полугода - крутой тулл но сыроват был )
Я решил делать типа : eventql + periscopedata для CH и для mySQL/pgSQL с упором на написание запросов руками без возможности drag&drop (bi). Уже в dev ветки такие вещи, как схлопывать запросы, автоформат, подсказки по каждой ф-ции ch, автодополнения словорей / ф-ции + хоткеи для удобной навигации ну и графики.

Google

f1yegor
21.01.2017
19:01:44
это еще на опубликовано?

Igor
21.01.2017
19:05:04
можно собрать ветку devigor1701 - но она очень не стабильна ...

f1yegor
21.01.2017
19:05:33
github?

Igor
21.01.2017
19:06:06
да
changelog https://github.com/smi2/clickhouse-frontend/blob/devigor1701/README.md#changelog

f1yegor
21.01.2017
19:07:21
а, понял. это я уже задеплоил и немного посмотрел


Alexey
21.01.2017
20:25:48
Привет, может кто-нибудь подсказать по структуре массивов в нативном протоколе, например у меня есть таблица
CREATE TABLE example
(
IntArray Array(Int8),
StrArray Array(String)
) ENGINE = Memory
мне приходит пакет вида:
column name - string (uvariant (strlen) + []byte (str))
column type - string (uvariant (strlen) + []byte (str))
{ // data
{
array len (uvariant)
}
values
}
мне интересны первые 8 байт, сначала в них идет длина, но она переменной длины,
после 8 байт идут данные массива которыя я вычитываю в зависимости от типа
интересует как получить данный офсет и зачем он нужен?
Для массива будут идти подряд два куска с данными.
Сначала - смещения массивов - это числа UInt64 и их столько, сколько строк в блоке.
Смещение в позиции i - это суммарное количество элементов во всех массивах до i-го, включительно. Другими словами, это - смещение (в количестве элементов) до начала i+1-го массива.
Последнее смещение - это суммарное количество элементов всех массивов.
Следующий кусок данных - это все элементы массивов, уложенные подряд.
Пример: массивы [1], [10, 11]
смещения будут записаны так:
1, 3
элементы будут записаны так:
1, 10, 11
И ещё:
> uvariant (strlen)
Правильно было бы написать - uvarint. Это очень частая ошибка. Почти всегда varint при взгляде читьается как variant.


f1yegor
21.01.2017
21:12:03
а отличие не в том, что в 'subselect on left' у меня выбираются данные из таблицы 3 в память, далее стрим join c таблицей 2, и результат стрим join с таблицей один. а во втором случае идет выборка всего в память из таблицы 3, потом выборка в память из т2, потом стриминг join т1 с т2, а потом ???
пытаюсь осознать "At the beginning of query execution, the subquery specified after JOIN is run, and its result is saved in memory. Then it is read from the "left" table specified in the FROM clause, and while it is being read, for each of the read rows from the "left" table, rows are selected from the subquery results table (the "right" table) that meet the condition for matching the values of the columns specified in USING."


Alexey
21.01.2017
21:36:18
1.
- из table3 составляется хэш-таблица в оперативке;
- читаем из table2 и делаем JOIN с table3;
- из результата составляется хэш-таблица в оперативке;
- читаем из table1 и делаем JOIN с этим.
2.
- из table3 составляется хэш-таблица в оперативке;
- из table2 составляется хэш-таблица в оперативке;
- читаем из table1 и делаем JOIN с table2 и в том же проходе делаем JOIN с table3.

f1yegor
21.01.2017
21:39:42
т.е. потенциально вариант 1 есть меньше оперативы, но вариант 2 может получаться быстрее

Alexey
21.01.2017
21:41:02
Зависит от соотношения размеров таблиц и то, насколько меньше результат после JOIN.
PS. Если у тебя в запросах есть ещё всякие WHERE, то лучше засовывать их в подзапрос (так как сейчас WHERE при выполнении делается после JOIN).

f1yegor
21.01.2017
21:42:46
да, у меня все WHERE внутри.
спасибо за объяснения

Kirill
22.01.2017
09:53:14

Боб
22.01.2017
18:59:10
А для CollapsingMergeTree у вас данные где-то во внешнем хранилище копятся? (Чтобы вставлять строку со знаком минус и предыдущими значениями)
И можно ли CollapsingMergeTree или SummingMergeTree научить схлопывать строки применением своей функции между двумя строками?

Google

Боб
22.01.2017
20:12:11
Или еще лучше: агрегировать в два уровня и при этом не требовать много памяти. Например нужно построить отчет: сколько пользователей сделали больше 2 кликов и обобщить данные по странам.
Хотелось бы чтобы кликхаус агрегировал данные по пользователю или нескольким пользователям, затем применял бы изменения к конечной агрегации по странам и обработанных пользователей забывал переходя к новым.
Если сделать что то вроде:
select country, sumIf(click >2) from (select any(country) as country, count() as click from log group by userId)
То сервер сначала целиком посчитает весь внутренний запрос и только потом внешний.
Ручная оптимизация выглядит как запрашивание агрегаций по пользователям небольшими кусками: по интервалам userid и потом конечные расчеты во внешней системе. Это позволяет экономить много оперативки.
Можно ли подобную оптимизацию сделать внутри запросов?


f1yegor
22.01.2017
20:19:23
а почему не сделать просто select country, count(*) from log where click >2 group by country

papa
22.01.2017
20:21:38
потому что нужны не клики,а уники.

f1yegor
22.01.2017
20:26:40
select country, uniqIf(userId, click > 2) from log group by country


papa
22.01.2017
22:31:49
если я правильно понимаю задачу, то схема данных имеет вид
table log(
userid,
country
...
)по которой надо посчитать кол-во людей, у которых было больше двух кликов, что и делает запрос
select country, sumIf(click > 2) from (
select any(country) as country, count() as click from log
group by userId)который в общем случае не работает, т.к. userid имеет большую кардинальность.
из того как объявлен click можно предположить, что каждая строка лога - это отдельный клик.
также, видимо, предполагается что страна пользователя меняется редко.
запрос
select country, uniqIf(userId, click > 2) from log group by countryсработал бы в случае, если строка лога была бы пользователем, и в ней была колонка с количеством кликов.
для этого, возможно, подойдет AggregatingMergeTree, countState(), вот это все.
еще наверное в ключ надо добавить дату, т.к. без окна по времени любой запрос к log со временем работать перестанет.

f1yegor
22.01.2017
22:34:30
А, понятно

Боб
23.01.2017
07:49:06
Про даты это понятно, тут я их специально опустил для упрощения восприятия.
Log это таблица, в которую вставлен лог апача, пока что без предварительной обработки. А статистика в основном нужна по уникам. При этом в разных разрезах: страны, устройства (телефон, десктоп), источники трафика и т.п. за произвольные интервалы времени.
А есть ли какой-то способ чтобы кликхаус сам агрегировал информацию из таблицы логов в таблицу пользователей. Чтобы выборку потом уже из пользователей делать?
В идеале что-то вроде SummingMergeTree, только чтобы суммирование происходило собственной функцией.
Т.е. например есть две записи о пользователе - я хочу оставить одну, но не просто сложить числа, а например запомнить время последних 10 кликов и соответственно при каждом слиянии эти "последние 10" должны сливаться и укорачиваться по длине до 10 элементов. А не просто складываться или работать как map.


Alexey
23.01.2017
07:51:51
Я бы писал просто:
SELECT Country, uniq(UserID) FROM log GROUP BY Country ORDER BY uniq(UserID) DESC
Пямяти такой запрос потребляет мало.
Разница с предложенным вами запросом лишь в случае, когда пользователь был в нескольких странах, и нужно учесть его только в одной.

Боб
23.01.2017
07:53:51
Разница еще в том, что в вашем запросе считается количество уников, а в моём количество уников, которые кликнули минимум два раза.

Alexey
23.01.2017
07:54:17
А. Совсем другое дело. Не обратил внимания.
Функциональности сброса временных данных агрегации в случае, когда данные одного ключа идут при обработке подряд - нет.

Боб
23.01.2017
07:55:48
на самом деле нужно считать и другие агрегации в разрезе пользователя, например уходил ли пользователь с сайта (т.е. тут нужно как-то времена кликов соотносить. Сейчас пробую добавить колонку "время предыдущего клика" и потом придумать как её при записи в лог добавлять), паузы между кликами - т.е. количество кликов когда время между кликами больше n секунд (пользователь ушел, потом на след. день вернулся) и т.п.

Alexey
23.01.2017
07:56:55


Боб
23.01.2017
09:34:17
А есть способ "Сдвинуть" элементы массива на 1 вперед и потом в конец добавить еще один элемент (пустой).
Задача: собираю таблицу по пользователям. Для каждого пользователя получаю массив времён, когда он заходил - groupArray(Timestamp) as Times.
Дальше мне нужно будет сравнить разницу между соседними Timestamp чтобы понять например - были ли у пользователя возвраты.
Я себе это вижу примерно так
SELECT arrayExists( (Time1,Time2) -> Time2 != 0 AND Time1 - Time2 > 86400, Times, append(shift(Times, 1), 0) ) as isReturned
Интересует как сделать часть:
append(shift(Times, 1), 0) )
т.е. откусить от массива первый элемент и добавить в конец пустой элемент.
Или так:
SELECT arrayExists( (Time1,Time2) -> Time1 - Time2 > 86400, Times[:length(Times)-1], Times[1:] ) as isReturned
т.е. передать в arrayExists два массива, у одного откушен первый элемент. У другого - последний.


Vladislav
23.01.2017
10:29:57
странное поведение, если указать в условии несуществующие даты:
SELECT DISTINCT download_date
FROM analytics.apps_store_downloads
WHERE (download_date >= '2016-11-28') AND (download_date <= '2016-11-31')
ORDER BY download_date ASC
┌─download_date─┐
│ 2016-11-28 │
│ 2016-11-29 │
│ 2016-11-30 │
│ 2016-12-01 │
└───────────────┘
SELECT DISTINCT download_date
FROM analytics.apps_store_downloads
WHERE (download_date >= '2016-11-28') AND (download_date <= '2016-11-32')
ORDER BY download_date ASC
Ok.
почему в первом случае что-то возвращается, а во втором – нет?

Igor
23.01.2017
10:32:14
:) select toDate('2016-11-30'), toDate('2016-11-31'), toDate('2016-11-32') FORMAT Vertical;
Row 1:
──────
toDate(\'2016-11-30\'): 2016-11-30
toDate(\'2016-11-31\'): 2016-12-01
toDate(\'2016-11-32\'): 0000-00-00
видимо, поэтому

Google

Igor
23.01.2017
10:32:43
насчет 2016-11-31 - поржал :))
о, с февралем так же прокатывает, 31 февраля == 2 марта

Eduard
23.01.2017
10:47:28
?

Shine
23.01.2017
11:01:26
Ребят, подскажите, у меня есть поля с массивы строк, хочется, что бы мы фильтровали по этим полям с логикой И (как в постгресе есть @> - contains), т е чтобы мы условие возвращало истину ,только если все искомые элементы есть в массиве
Когда делаем так
select query_id, tags, arrayAll(x -> has(['3rd generation', '5th generation'], x), tags) as has_tags from queries_1 limit 10;
мы ограничены количеством элементов массива tags. Если количество элементов массива tags меньше, чем количество запрашиваемых элементов, то мы получим те строки массива tags, которые содержат хотя бы один элемент. А нам нужно обязательно, чтобы в результате выдавались только те строки, которые имееют все запрашиваемые теги (тут мы не фильтруем, а для теста выводим булеву колонку, но не суть)

Nikita
23.01.2017
11:02:25
а в jdbc и readonly пользователь не дружат? ругается на "Cannot override setting (extremes) in readonly mode"
дурья моя башка, readonly же может быть 2


Боб
23.01.2017
11:20:35
Ребят, подскажите, у меня есть поля с массивы строк, хочется, что бы мы фильтровали по этим полям с логикой И (как в постгресе есть @> - contains), т е чтобы мы условие возвращало истину ,только если все искомые элементы есть в массиве
Когда делаем так
select query_id, tags, arrayAll(x -> has(['3rd generation', '5th generation'], x), tags) as has_tags from queries_1 limit 10;
мы ограничены количеством элементов массива tags. Если количество элементов массива tags меньше, чем количество запрашиваемых элементов, то мы получим те строки массива tags, которые содержат хотя бы один элемент. А нам нужно обязательно, чтобы в результате выдавались только те строки, которые имееют все запрашиваемые теги (тут мы не фильтруем, а для теста выводим булеву колонку, но не суть)
я бы сделал что-то вроде
arrayCount >= 3 AND
arrayAll(x-> has(['a', 'b', 'c']),
arrayFilter( x-> has(['a', 'b', 'c']) )
)
а еще лучше:
arrayCount(
arrayFilter( x-> has(['a', 'b', 'c']) )
) == 3
arrayCount(
arrayFilter( x-> has(['a', 'b', 'c']),tags )
) == 3


Shine
23.01.2017
11:25:40

Боб
23.01.2017
11:28:37
Интересно а как в метрике считают данные по пользователям - у вас же тоже на входе просто логи, а на выходе есть какая-то статистика по посетителям?
Если я правильно понял предыдущие диалоги, то посетители у вас лежат в таблице CollapsingMergeTree. Где-то снаружи вы отдельно определяете что клик принадлежит такому-то посетителю, снаружи обновляете его счетчики (время последнего клика, количество кликов и т.п.), и скидываете лог изменений в CollapsingMergeTree.
Затем, когда надо выдать статистику по пользователям делаете уже запрос к таблице посетителей и её доагрегируете с учетом строк или FINAL?
И сколько памяти кушает FINAL - так же как загрузить всю таблицу в память и посчитать по GROUP BY или меньше?