Задачки с собесов - Python
.
В работе дата инженера нередко приходится тянуть данные из API, в работе с ним помогает Python, поэтому есть и задачки по нему. Встречаем первую:
.
При решении внимательно приглядитесь к функции
.
Пока решаете, вспомните с какими "чудесными" API вам приходилось работать, пишите их в комментах.
#вопросы #собес #python
.
В работе дата инженера нередко приходится тянуть данные из API, в работе с ним помогает Python, поэтому есть и задачки по нему. Встречаем первую:
Ответ от API:
response = '''
{
"trace_id": "d6518bbb-b47b-4d1b-931e-74013148872d",
"type": "ADD",
"data": [
{
"id": 464612,
"timestamp": "2023-05-04T09:24:57Z",
"is_rejected": false,
"reason": null,
"values": [13.4, 64.7, 12]
},
{
"id": 464612,
"timestamp": "2023-05-04T10:32:15Z",
"is_rejected": false,
"reason": null,
"values": [77.3, 7.6, 10]
},
{
"id": 74641123,
"timestamp": "2023-05-04T05:23:13Z",
"is_rejected": true,
"reason": "Code 53",
"values": [45.2, 0.5, 0]
}
]
}
'''
В ответе от API не хватает поля name, его можно получить вызвав функцию get_name_by_id:
def get_name_by_id(id: int) -> str:
from random import randrange
from time import sleep
sleep(1)
box_number = randrange(0, 1000) // len(str(id))
return f"Box {box_number}"
.
При решении внимательно приглядитесь к функции
get_name_by_id, неспроста там есть некоторые моменты☝️.
Пока решаете, вспомните с какими "чудесными" API вам приходилось работать, пишите их в комментах.
#вопросы #собес #python
❤2👍1🔥1
А такое даже не грешно запостить: смотрите как изменилась картина тулзов для дата инженеров🙈
Forwarded from 🔋 Труба данных (Simon Osipov)
How it started (~2012) VS How it is going (2023)
Кстати, текущую карту можно интерактивно покликать вот тут https://mad.firstmark.com/
@ohmydataengineer
Кстати, текущую карту можно интерактивно покликать вот тут https://mad.firstmark.com/
@ohmydataengineer
🔥1
https://bar-or-pie.dianov.org/result-1300.html
Бар о пай
📈Это однозначно лучшее про датавиз-гигиену
.
Пройдите тест и узнайте:
- в каких случаях стоит использовать цветовую кодировку, а когда нет
- когда обводка это зло
- когда следует повернуть ваш барплот
- или когда не следует подписывать все числа на графике
.
И наконец ответьте себе на главный вопрос: Bar or Pie😉
ps: а еще там есть ссылки, в которых более подробно изложена та или иная идея
.
#plot #data #bar #pie
Бар о пай
📈Это однозначно лучшее про датавиз-гигиену
.
Пройдите тест и узнайте:
- в каких случаях стоит использовать цветовую кодировку, а когда нет
- когда обводка это зло
- когда следует повернуть ваш барплот
- или когда не следует подписывать все числа на графике
.
И наконец ответьте себе на главный вопрос: Bar or Pie😉
ps: а еще там есть ссылки, в которых более подробно изложена та или иная идея
.
#plot #data #bar #pie
bar-or-pie.dianov.org
1300 очков набрал в датавиз-игре
Короткий тест с основными принципами визуализации данных.
❤3👍1
😎А вы уже еBASH.....
.
Не перестаю удивляться магии линукса и простых (но это не точно) консольных команд.
.
Разбираясь с уткойпо-пекински 🦆 (про неё тоже будет пост, довольно интересная альтернатива sqlite3, особенно если хочется практиковать SQL) в доке обнаружил утилиту для построения графиков в терминале youplot 😈. В кратком tutorial можно найти довольно приличный набор графиков:
- столбчатые
- линейные
- гистограммы или графики плотности
- scatterplot
- boxplot
Кажется, для базового анализа выше крыши, так что теперь разведывательный анализ можно выполнять без Python😁
.
Конечно, чтобы построить график нужно не бояться терминала (вообще кажется, в нем можно сделать всё и немножечко больше).
.
Вот некоторые сниппеты:
Данные из файла на github:
В общем изучаем магию🧙♀️
А вы знаете что-то хитрое в linux-терминале?
#bash #duckdb #youplot
.
Не перестаю удивляться магии линукса и простых (но это не точно) консольных команд.
.
Разбираясь с уткой
- столбчатые
- линейные
- гистограммы или графики плотности
- scatterplot
- boxplot
Кажется, для базового анализа выше крыши, так что теперь разведывательный анализ можно выполнять без Python😁
.
Конечно, чтобы построить график нужно не бояться терминала (вообще кажется, в нем можно сделать всё и немножечко больше).
.
Вот некоторые сниппеты:
<code class="language-bash"># данные из Python
echo -e "from numpy import random;"
"n = random.randn(25000);"
"print('\\n'.join(str(i) for i in n))"
| python3
| uplot hist --nbins 51
Данные из файла на github:
<code class="language-bash">curl -s https://raw.githubusercontent.com/urevoleg/example-direct-access/main/kinopoisk/kinopoisk_parsing.csv | awk -F';' '{print $20}' | uplot hist --nbins 20В общем изучаем магию🧙♀️
А вы знаете что-то хитрое в linux-терминале?
#bash #duckdb #youplot
🔥1
🔥По горячим следам
.
Случился стандартный рабочий кейс: надо затащить несколько внешних таблиц в клик.
Источник: Postgres
Сущность: N вьюх (у одной из под капотом было около десятка JOIN 🥶, дадим ей имя вьюха
История умалчивает подробности и даже почему выбран такой способ загрузки: целевая таблица полностью перегружается каждый день.
.
Работа шла стандартным флоу (практикую частичное решение задач):
- написал даг с коннектом к источнику
- таски для создания инфры
- несколько таск групп с небольшим селектом из источника (проверить, что всё ок и источник отдает данные)
- заварил 🫖 и стал налюдать за даграном
.
Всё шло хорошо до момента тестирования вьюхи G. В логах вижу инфра создается, как только дело доходит до забора данных, то таска ждет и падает по
.
В процессе обсуждения с разработчиком со стороны источника выяснилось:
- про десятки JOIN
- там в таблице 10+млн строк
- .....
.
Но тут я подумал: ведь я же батчами забираю, причем здесь млн строк🤔.
.
Код для загрузки батчами тривиален:
.
Крутил, вертел никак, надо идти курить доку (тимлид подкинул про именованные курсоры). И от тут истина и открылась, если делать так как выше, то:
-
- полные данные передаются на клиент
- и батчи получаются на стороне клиента - то есть у нас клиентский курсор
И естественно дождаться не получается пока собирутся 10+млн строк.
.
Из доки psycopg2 узнал про реализацию серверного курсора (тот который будет формировать батчи на стороне сервера и отдавать их). Для организиации серверного курсора меняем код, использовать красивую pandas-обертку уже не получится:
.
Бинго, теперь батчи отдаются по мере готовности и не нужно ждать сбора всех данных - пошло чтение данных. Далее я дописал загрузку в Clickhouse.
.
ps: на источнике окаалось 36+млн строк 🤨
#case #work #psycopg2 #def
.
Случился стандартный рабочий кейс: надо затащить несколько внешних таблиц в клик.
Источник: Postgres
Сущность: N вьюх (у одной из под капотом было около десятка JOIN 🥶, дадим ей имя вьюха
G)История умалчивает подробности и даже почему выбран такой способ загрузки: целевая таблица полностью перегружается каждый день.
.
Работа шла стандартным флоу (практикую частичное решение задач):
- написал даг с коннектом к источнику
- таски для создания инфры
- несколько таск групп с небольшим селектом из источника (проверить, что всё ок и источник отдает данные)
- заварил 🫖 и стал налюдать за даграном
.
Всё шло хорошо до момента тестирования вьюхи G. В логах вижу инфра создается, как только дело доходит до забора данных, то таска ждет и падает по
SIGTERM - явно что-то идет не так..
В процессе обсуждения с разработчиком со стороны источника выяснилось:
- про десятки JOIN
- там в таблице 10+млн строк
- .....
.
Но тут я подумал: ведь я же батчами забираю, причем здесь млн строк🤔.
.
Код для загрузки батчами тривиален:
<code class="language-python"><code class="language-python">import psycopg2
con = psycopg2.connect(.....)
...
for chunk in pd.read_sql(stmt, con=con, chunk_size=100500):
yield chunk
.
Крутил, вертел никак, надо идти курить доку (тимлид подкинул про именованные курсоры). И от тут истина и открылась, если делать так как выше, то:
-
stmt должно выполниться полностью на стороне сервера- полные данные передаются на клиент
- и батчи получаются на стороне клиента - то есть у нас клиентский курсор
И естественно дождаться не получается пока собирутся 10+млн строк.
.
Из доки psycopg2 узнал про реализацию серверного курсора (тот который будет формировать батчи на стороне сервера и отдавать их). Для организиации серверного курсора меняем код, использовать красивую pandas-обертку уже не получится:
<code class="language-python">import psycopg2
from psycopg2.extras import RealDictCursor
with psycopg2.connect(...) as conn:
with conn.cursor(name="It's server cursor", cursor_factory=RealDictCursor()) as cursor:
cur.execute(stmt)
chunk = cur.fetchmany(chunk_size)
while chunk:
yield pd.DataFrame(chunk)
chunk = cur.fetchmany(chunk_size)
.
Бинго, теперь батчи отдаются по мере готовности и не нужно ждать сбора всех данных - пошло чтение данных. Далее я дописал загрузку в Clickhouse.
.
ps: на источнике окаалось 36+млн строк 🤨
#case #work #psycopg2 #def
🔥6
Clickhouse-notes 📔
.
Буду делиться лайфхаками, которые использую в работе. Отмечу, что на работе клик распределенный и это накладывает некоторые ограничения или нюансы в работе ( а вы как хотели, только плюсы чтоль)
.
0️⃣Стоит отметить такой факт: клик распределенный -> нет мастер ноды -> координирует работу Zookeeper -> запросы можно выполнять как
В первом подходе организуется
.
Операции
.
Локально у меня всегда в docker запущен clickhouse (однонодовый) для экспериментов, с однонодовым в разы легче и проще, а скорость его работы, ну вы знаете 🚀
.
ps: где-то было видео со сравнением работы одного и того же запроса на Postgres и Clickhouse, найду, отправлю в комменты. Понятно что сравнение ежа со слоном, но когда я первый раз так перешел был приятно удивлен 🙃
#clickhouse #lifehacks
.
Буду делиться лайфхаками, которые использую в работе. Отмечу, что на работе клик распределенный и это накладывает некоторые ограничения или нюансы в работе ( а вы как хотели, только плюсы чтоль)
.
0️⃣Стоит отметить такой факт: клик распределенный -> нет мастер ноды -> координирует работу Zookeeper -> запросы можно выполнять как
ON CLUSTER так и на каждом хосте отдельноВ первом подходе организуется
distributed_ddl_queue, которая иногда очень долго рассасывается, при втором подходе мы обходим эту очередь, выполняя запросы на каждом хосте отдельно - это можно назвать лайфхаком номер 0.
Операции
DELETE\ UPDATE дорогие для клика (это мутации, выпоняются через ALTER TABLE) - их вообще следует избегать, используя семейство движков MergeTree. Но иногда без них нельзя, аналитикам только дай, что поделитить или поапдейтить -> копиться очередь -> её надо обходить.
Локально у меня всегда в docker запущен clickhouse (однонодовый) для экспериментов, с однонодовым в разы легче и проще, а скорость его работы, ну вы знаете 🚀
.
ps: где-то было видео со сравнением работы одного и того же запроса на Postgres и Clickhouse, найду, отправлю в комменты. Понятно что сравнение ежа со слоном, но когда я первый раз так перешел был приятно удивлен 🙃
#clickhouse #lifehacks
👍2
🚛 Как грузить в клик
.
Из ответа на вопрос в комментариях родился маленький пост.
Для загрузки данных в clickhouse в команде используем два подхода:
1️⃣ Pythonic way с использованием clickhouse_driver
Тут два метода:
-
-
Кому, что больше нравиться, встречаются ошибки с типами данных
2️⃣ Native way с использованием linux клиента clickhouse-client
Например, способом ниже загружаются csv файлы
Оба подхода используют TCP соединение.
Есть еще третий, с использованием HTTP, ниже пример bash скрипта:
Вероятно, бывает иногда полезный, пока использовать не приходилось. У 3 способа есть особенности, о них лучше почитать в доке,например, у меня завелась передача user\pass только через заголовки.
#clickhouse #de #dataload #load
.
Из ответа на вопрос в комментариях родился маленький пост.
Для загрузки данных в clickhouse в команде используем два подхода:
1️⃣ Pythonic way с использованием clickhouse_driver
Тут два метода:
-
execute-
insert_dataframeКому, что больше нравиться, встречаются ошибки с типами данных
2️⃣ Native way с использованием linux клиента clickhouse-client
Например, способом ниже загружаются csv файлы
<code class="language-shell"><code class="language-bash">cat file.csv | clickhouse-client --host=$CH_HOST --user=$CH_USER --password=$CH_PASSWORD --query="INSERT INTO $CH_SCHEMA.$CH_TABLE FORMAT CSVWithNames"
Оба подхода используют TCP соединение.
Есть еще третий, с использованием HTTP, ниже пример bash скрипта:
<code class="language-bash">#!/bin/bash
#CH
CLUSTER_NAME=
CH_HOST=192.168.55.121
CH_PORT=8123
CH_SCHEMA=stage
CH_USER=clickadmin
CH_PASSWORD=aLpjr5HMq
CH_TABLE=TMP_CURL2CH
CH_URL="http://${CH_HOST}:${CH_PORT}"
DDL_QUERY="CREATE OR REPLACE TABLE $CH_SCHEMA.$CH_TABLE
(
user_id String,
name Nullable(String),
email Nullable(String),
phone Nullable(String),
address Nullable(String),
birth_date Nullable(Date)
)
ENGINE = MergeTree
ORDER BY (birth_date, name, phone)
SETTINGS index_granularity = 8192, allow_nullable_key=1;"
echo "☠️ DDL Executing...."
echo $DDL_QUERY | curl -H "X-ClickHouse-User: $CH_USER" -H "X-ClickHouse-Key: $CH_PASSWORD" "$CH_URL?query=" --data-binary @-
CSV_FILE="src/data.csv"
# Определение запроса на загрузку данных
INSERT_QUERY="INSERT+INTO+$CH_SCHEMA.$CH_TABLE+(user_id,name,email,phone,address,birth_date)+FORMAT+CSVWithNames"
echo "🚰 Inserting data from file: $CSV_FILE...."
echo "$CH_URL?query=$INSERT_QUERY"
cat $CSV_FILE | curl --data-binary @- -H "X-ClickHouse-User: $CH_USER" -H "X-ClickHouse-Key: $CH_PASSWORD" "$CH_URL?query=$INSERT_QUERY"
Вероятно, бывает иногда полезный, пока использовать не приходилось. У 3 способа есть особенности, о них лучше почитать в доке,например, у меня завелась передача user\pass только через заголовки.
#clickhouse #de #dataload #load
GitHub
GitHub - mymarilyn/clickhouse-driver: ClickHouse Python Driver with native interface support
ClickHouse Python Driver with native interface support - mymarilyn/clickhouse-driver
👍2
Clickhouse-notes⚡️
.
Предикат
.
Простыми словами: указанием полей в этой секции можно рассматривать как индекс, то есть сюда следует включать все столбцы, которые используются при фильтрации: это позволяет при чтении данных пропускать неподходящие куски -> то есть не читать лишнего (а иногда это ОЧЕНЬ много лишнего).
Если заранее неизвестно что и как будет фильтроваться, использую общее правило:
Конечно не стоит увлекаться по все поля, но условно интуитивно понятные🙃
.
На чтение кол-ва данных также влияет партицирование, задаётся в секции
.
Для того чтобы оценить эффективность ваших действий по управлению секциями
.
Подбираю так, чтобы на самых частых запросах были минимальные параметры (на глазок👀), конечно для этого бы придумать какой-то тул, но это уже другая история.
.
#clickhouse #2 orderby
.
Предикат
ORDER BY при создании таблицы очень важная штука, при неверном выборе производительность запроса может быть крайне низкой..
Простыми словами: указанием полей в этой секции можно рассматривать как индекс, то есть сюда следует включать все столбцы, которые используются при фильтрации: это позволяет при чтении данных пропускать неподходящие куски -> то есть не читать лишнего (а иногда это ОЧЕНЬ много лишнего).
Если заранее неизвестно что и как будет фильтроваться, использую общее правило:
В секции ORDER BY указываю все поля в порядке увеличения кардинальности (то есть ближе в ORDER BY будет поле с наименьшим кол-вом уникальных значений)
Конечно не стоит увлекаться по все поля, но условно интуитивно понятные🙃
.
На чтение кол-ва данных также влияет партицирование, задаётся в секции
PARTITION BY - об этом есть в доке..
Для того чтобы оценить эффективность ваших действий по управлению секциями
ORDER BY\PARTITION BY использую перед запросом указание explain estimate, результат показывает сколько партов и строк будет прочитано в результате запроса, пример ниже:<code class="language-markdown">
database|table |parts|rows|marks|
--------+-------+-----+----+-----+
stg |tmp_bpr| 1| 210| 1|
.
Подбираю так, чтобы на самых частых запросах были минимальные параметры (на глазок👀), конечно для этого бы придумать какой-то тул, но это уже другая история.
.
#clickhouse #2 orderby
🔥7👍1
Clickhouse-notes ⚡️
.
Продолжаем грузить клик
.
В предыдущих notes рассмотрели загрузку:
- из файла CSV
- из датафрейма
- или сериализованых данных через HTTP интерфейс
.
Но есть и другие варианты: не всегда же источником являются файлы на локальной машине:
- S3 (наиболее частый случай, поставщик данных в S3 нас не интересует)
- Kafka и всё стримоподобное
- другие базы, например, Postgres\MySQL
,
В каждом из кейсов могут свои оптимальные шаблоны, мы рассмотрим только возможности, имеющиеся в Clickhouse.
.
1️⃣Для загрузки из S3 используется S3 Engine (у нас еще будет задачка с S3 😉).
Тут всё довольно просто, нужны креды (access_key, access_secret_key), сам файл на S3 и табличная фукнция:
Что здесь хитрого:
- бакет public-bucket-6
- папка reddit
- дальше магические звезды ⭐️ (и это не распаковка Python)
- формат файла Parquet
Особенность при загрузке: необходимо указать схему данных (наименование поля и его тип, если схема не совпадает с тем, что есть на самом деле будет ошибка ).
⭐️() - нужны для pattern matching - чтобы загрузить данные из всех файлов в папке reddit - первая * = даты (партиционирование, обычно по датам), вторая * = просто все файлы с расширением .parquet.
.
В процесcе ETL обычно создаётся VIEW над S3 из нее данные загружаются в STG table (чтобы изменения на S3 не влияли на дальнейший процесс прогрузки).
ps: креды на чтение оставлю в комментах, чтобы вы могли попробовать😉.
Настройка, max_threads распараллеливает чтение😎
,
2️⃣ Следующий способ: движки баз данных или движки таблиц, на примере Postgres.
Довольно интересный способ, но в рабочей среде доводилось только экспериментировать. Например, при помощи движка таблицы можно легко получить структуру таблицы и перенести её в Clickhouse, так как он считает нужным:
А вообще в команде принятым способом доставки данных из реляционок является Debezium (это уже история про потоковые данные). Но если нет инфры под Debezium и Кафка - движки баз данных и таблиц - хороший выбор👌
.
3️⃣ Последний кейс: потоковые данные из Кафка.
Хотя и в Clickhouse есть специальный движок, но даже экспериментировать не приходилось, тк для этого в команде есть Kafka-Connect.
ETL выглядит так: Kafka -> Kafka-Connect -> raw table in Clickhouse -> MV -> data table:
1. Kafka-Connect формирует собщение простой структуры:
2. Структуру выше хранит raw table
3. MV парсит JSON сообщение и записывает их в data table
4. Пользователь ходит уже в data table
Вообще парадигма MV (materialized view)\Projection очень крутая, возможно надо ей уделить пару заметок.
#clickhouse #3 #extract #load
.
Продолжаем грузить клик
.
В предыдущих notes рассмотрели загрузку:
- из файла CSV
- из датафрейма
- или сериализованых данных через HTTP интерфейс
.
Но есть и другие варианты: не всегда же источником являются файлы на локальной машине:
- S3 (наиболее частый случай, поставщик данных в S3 нас не интересует)
- Kafka и всё стримоподобное
- другие базы, например, Postgres\MySQL
,
В каждом из кейсов могут свои оптимальные шаблоны, мы рассмотрим только возможности, имеющиеся в Clickhouse.
.
1️⃣Для загрузки из S3 используется S3 Engine (у нас еще будет задачка с S3 😉).
Тут всё довольно просто, нужны креды (access_key, access_secret_key), сам файл на S3 и табличная фукнция:
SELECT , toDate(now(), 'UTC') as row_inserion_date
FROM s3('https://storage.yandexcloud.net/public-bucket-6/reddit/.parquet',
'$AWS_ACCESS_KEY',
'$AWS_SECRET_ACCESS_KEY',
'Parquet',
'id String,
noscript String,
score Nullable(Int64),
num_comments Nullable(Int64),
author String,
created_utc DateTime64,
url String,
upvote_ratio Float,
over_18 Bool,
edited Bool,
spoiler Bool,
stickied Bool,
subreddit_name_prefixed String
')
SETTINGS input_format_allow_errors_num = 2000,
max_threads = 16;
Что здесь хитрого:
- бакет public-bucket-6
- папка reddit
- дальше магические звезды ⭐️ (и это не распаковка Python)
- формат файла Parquet
Особенность при загрузке: необходимо указать схему данных (наименование поля и его тип, если схема не совпадает с тем, что есть на самом деле будет ошибка ).
⭐️() - нужны для pattern matching - чтобы загрузить данные из всех файлов в папке reddit - первая * = даты (партиционирование, обычно по датам), вторая * = просто все файлы с расширением .parquet.
.
В процесcе ETL обычно создаётся VIEW над S3 из нее данные загружаются в STG table (чтобы изменения на S3 не влияли на дальнейший процесс прогрузки).
ps: креды на чтение оставлю в комментах, чтобы вы могли попробовать😉.
Настройка, max_threads распараллеливает чтение😎
,
2️⃣ Следующий способ: движки баз данных или движки таблиц, на примере Postgres.
Довольно интересный способ, но в рабочей среде доводилось только экспериментировать. Например, при помощи движка таблицы можно легко получить структуру таблицы и перенести её в Clickhouse, так как он считает нужным:
CREATE TABLE stage.TMP_PG AS SELECT * FROM postgresql('192.168.55.121:5432', 'tmp', 'kp_search_results', 'shpz', '12345', 'stage') WHERE 1; А вообще в команде принятым способом доставки данных из реляционок является Debezium (это уже история про потоковые данные). Но если нет инфры под Debezium и Кафка - движки баз данных и таблиц - хороший выбор👌
.
3️⃣ Последний кейс: потоковые данные из Кафка.
Хотя и в Clickhouse есть специальный движок, но даже экспериментировать не приходилось, тк для этого в команде есть Kafka-Connect.
ETL выглядит так: Kafka -> Kafka-Connect -> raw table in Clickhouse -> MV -> data table:
1. Kafka-Connect формирует собщение простой структуры:
record_timestamp DateTime64 - время записи сообщения
record_value JSON - тело сообщения
2. Структуру выше хранит raw table
3. MV парсит JSON сообщение и записывает их в data table
4. Пользователь ходит уже в data table
Вообще парадигма MV (materialized view)\Projection очень крутая, возможно надо ей уделить пару заметок.
#clickhouse #3 #extract #load
Telegram
Where is data, Lebowski
🚛 Как грузить в клик
.
Из ответа на вопрос в комментариях родился маленький пост.
Для загрузки данных в clickhouse в команде используем два подхода:
1️⃣ Pythonic way с использованием clickhouse_driver
Тут два метода:
- execute
- insert_dataframe
Кому, что…
.
Из ответа на вопрос в комментариях родился маленький пост.
Для загрузки данных в clickhouse в команде используем два подхода:
1️⃣ Pythonic way с использованием clickhouse_driver
Тут два метода:
- execute
- insert_dataframe
Кому, что…
Маленький, но крайне полезный
.
Сегодня для вас маленький хук, при создании таблицы в клике по образу и подобию уже существующей не обязательно переписывать схему, достаточно указать эту аналогичную таблицу:
#clickhouse #4 #liketable
.
Сегодня для вас маленький хук, при создании таблицы в клике по образу и подобию уже существующей не обязательно переписывать схему, достаточно указать эту аналогичную таблицу:
CREATE TABLE sandbox.table as stg.another_tableЭто полезно, например при тестировании различных настроек: кодеки сжатия, партицирование, движки, секция ORDER BY.
ENGINE=MergeTree
ORDER BY .....
SETTINGS ....
#clickhouse #4 #liketable
👍2
С Новым годом, все причастные к миру данных🎄
.
ps: не будет долгих речей, просто будьте счастливы🦄
И напишите в комментах ваш любимый новогодний фильм 🎥
.
#newyear #2023
.
ps: не будет долгих речей, просто будьте счастливы🦄
И напишите в комментах ваш любимый новогодний фильм 🎥
.
#newyear #2023
❤4
Праздники пришли когда не ждали
.
Раскопал интересный нюанс, в процессе парсинга дат. Попробуйте выполнить такой код:
.
Результатом будите удивлены😳
#clickhouse #причуды
.
Раскопал интересный нюанс, в процессе парсинга дат. Попробуйте выполнить такой код:
SELECT
parseDateTimeBestEffort('1950-01-01');
.
Результатом будите удивлены😳
#clickhouse #причуды
⚡️Clickhouse-notes - ответы (просвещаемся на каникулах 🙃)
.
Под одним из постом был комментарий:
.
Вероятно, предполагается
.
Проверим применяется ли секция
Для экспериментов написал небольшой pipeline (github repo) для получения текущей погоды по API openweathermap.
DDL raw таблицы:
Pipeline выполняется по
.
Какой нюанс стоит учитывать:
только что вставленный парт может не быть отсортирован (см скрин 2): только что вставленная строка оказывается в начале данных, спустя некоторое время она в фоне будет отсортирована.
.
GIthub репу еще будем использовать для разбора других интересных особенностей clickhouse.
#clickhouse #orderby
.
Под одним из постом был комментарий:
Если не ошибаюсь, то стоит помнить, что order by сортирует только в рамках партиции, а не по всей таблице
.
Вероятно, предполагается
парт данных, партиции - это про деление данных на части по какому-либо признаку (чаще всего встречается по времени, например, партицией может быть день\неделя\месяц).Парт данных в контексте семейства Merge Tree - некоторый кусок неслитых данных, например, при вставке - это блок вставляемых данных (условно 1000 или 100000 строк)..
Проверим применяется ли секция
ORDER BY ко всей таблице. Для экспериментов написал небольшой pipeline (github repo) для получения текущей погоды по API openweathermap.
DDL raw таблицы:
CREATE DATABASE cdc;
CREATE TABLE cdc.openweathermap_raw
(
record_timestamp DateTime64(6),
record_value String
)
ENGINE=MergeTree
ORDER BY (record_timestamp)
;
Pipeline выполняется по
cron каждые 5 минут. Секция ORDER BY указывает сортировку по record_timestamp - это говорит, что сам парт будет отсортирован по указанному полю и все слитые парты (то есть таблица) также будут отсортированы по record_timestamp, что подтверждается экспериментально (см скрин 1 в комментах)..
Какой нюанс стоит учитывать:
только что вставленный парт может не быть отсортирован (см скрин 2): только что вставленная строка оказывается в начале данных, спустя некоторое время она в фоне будет отсортирована.
.
GIthub репу еще будем использовать для разбора других интересных особенностей clickhouse.
#clickhouse #orderby
🦆Утки или 🐍 змеи ?
.
Мир данных изменяется очень быстро, не успел приготовить утку по-duckdb-овски, на повестке дня уже новый схожий инструмент и в твоём любимом питончике - chdb (от создателей Clickhouse).
.
Инструменты уже успели сравнить - тут 🤔
.
Парочку статей для ознакомления:
🦆 Переводная статья о duckdb
🐍 О внутреннем устройстве
🐍 Про chdb от Антона Жиянова (человек, который развивает и много разрабатывает для SQLite)
.
А вы что-то трогали, использовали?
ps: будет серия заметок про duckdb (построим небольшой пайплайн)
#duckdb #chdb
.
Мир данных изменяется очень быстро, не успел приготовить утку по-duckdb-овски, на повестке дня уже новый схожий инструмент и в твоём любимом питончике - chdb (от создателей Clickhouse).
.
Инструменты уже успели сравнить - тут 🤔
.
Парочку статей для ознакомления:
🦆 Переводная статья о duckdb
🐍 О внутреннем устройстве
🐍 Про chdb от Антона Жиянова (человек, который развивает и много разрабатывает для SQLite)
.
А вы что-то трогали, использовали?
ps: будет серия заметок про duckdb (построим небольшой пайплайн)
#duckdb #chdb
🔥2👍1
⚡️Clickhouse-notes - Оператор EXCHANGE
.
Довольно занятный оператор, с ним познакомил меня коллега. Когда я поэкспериментировал с ним, то был приятно удивлен простоте использования и тем возможностям которые он даёт. Синтаксис маскимально прост:
Для предыдущего поста, использовал его, чтобы сменить ORDER BY для таблицы
.
Как следует из названия, оператор что-то где-то обменивает♻️, а именно:
- атомарно обменивает имена двух таблиц или словарей (читай обмениваются ссылки на данные)
.
Какие +:
🎈 можно атомарно подменять данные разных таблиц, партиций (настолько быстро, насколько возможно и для пользователя downtime -> 0️⃣). Как обычно проиходит батчевая загрузка: загружаем батч в stg, удаляем из целевой таблицы, перегружаем из stg в target. Всё бы ничего, но такой паттерн не для Clickhouse, операции update\delete для него тяжелые и лучше бы обойтись без них. EXCHANGE даёт такую возможность: загрузили всю таблицу (партицию) в stg , обменяли c target и DROP или TRUNCATE. Да, есть минус: необходимо место для хранения дубликата всей таблицы (если перегрузка происходит полностью) - но порой это оправданные затраты
🎈 можно менять DDL таблицы фактически без downtime (ведь если меняются имена таблиц, то можно поменять и их определение). Например, выставили вы неправильную секцию PARTITION BY или ORDER BY или в целом захотели их изменить или начали использовать кодеки для сжатия (кстати, тоже интересная тема, говорят, что узким местом в любом случае является чтение с диска, а разжатие данных происходит очень быстро, поэтому важнее сжать, чтобы меньше читать с диска ☝️).
Паттерн такой: создаете рядом таблицу с нужным DDL и обмениваете их -> старая таблица имеет новый DDL (новые данные сортируются\сжимаются\партицируются по-новому), старые данные нужно только перелить. Или пока данные льются в подменную таблицу, модифируем старый DDL (добавляем сжатия, меняем партиционирование ....) -> обмениваем обратно, новый кусок данных в подменной таблице заливаем.
.
💪На практике так меняли движки таблиц (для стрима аппметрики), добавляли сжатие
.
#clickhouse #exchange
.
Довольно занятный оператор, с ним познакомил меня коллега. Когда я поэкспериментировал с ним, то был приятно удивлен простоте использования и тем возможностям которые он даёт. Синтаксис маскимально прост:
EXCHANGE TABLES stg.exchange_table AND odm.table;
Для предыдущего поста, использовал его, чтобы сменить ORDER BY для таблицы
cdc.openweathermap_raw 😉.
Как следует из названия, оператор что-то где-то обменивает♻️, а именно:
- атомарно обменивает имена двух таблиц или словарей (читай обмениваются ссылки на данные)
.
Какие +:
🎈 можно атомарно подменять данные разных таблиц, партиций (настолько быстро, насколько возможно и для пользователя downtime -> 0️⃣). Как обычно проиходит батчевая загрузка: загружаем батч в stg, удаляем из целевой таблицы, перегружаем из stg в target. Всё бы ничего, но такой паттерн не для Clickhouse, операции update\delete для него тяжелые и лучше бы обойтись без них. EXCHANGE даёт такую возможность: загрузили всю таблицу (партицию) в stg , обменяли c target и DROP или TRUNCATE. Да, есть минус: необходимо место для хранения дубликата всей таблицы (если перегрузка происходит полностью) - но порой это оправданные затраты
🎈 можно менять DDL таблицы фактически без downtime (ведь если меняются имена таблиц, то можно поменять и их определение). Например, выставили вы неправильную секцию PARTITION BY или ORDER BY или в целом захотели их изменить или начали использовать кодеки для сжатия (кстати, тоже интересная тема, говорят, что узким местом в любом случае является чтение с диска, а разжатие данных происходит очень быстро, поэтому важнее сжать, чтобы меньше читать с диска ☝️).
Паттерн такой: создаете рядом таблицу с нужным DDL и обмениваете их -> старая таблица имеет новый DDL (новые данные сортируются\сжимаются\партицируются по-новому), старые данные нужно только перелить. Или пока данные льются в подменную таблицу, модифируем старый DDL (добавляем сжатия, меняем партиционирование ....) -> обмениваем обратно, новый кусок данных в подменной таблице заливаем.
.
💪На практике так меняли движки таблиц (для стрима аппметрики), добавляли сжатие
.
#clickhouse #exchange
🔥3👍1
⚡️Clickhouse-notes - MATERIALIZED VIEW
.
Для поста про ORDER BY была создана github репа, в ней есть пайплайн который каждый 5 минут получает погодные данные по API и складывает их в raw таблицу.
Глянуть схему 👀
.
MATERIALIZED VIEW (MV) - можно рассматривать как триггер, реагирующий на вставку данных (в отличие от триггеров в реляционках, реагирует на блок вставляемых данных, а не на отдельную строку ☝️). В Clickhouse MV отделено от целевой таблицы, поэтому для себя MV представляю как процесс, запускающийся для вставляемых данных и загружающий их в целевую таблицу.
.
При помощи MV можно решать ряд задач:
▪️парсинг сырых данных
▪️фильтрация сырья
▪️роутинг данных
▪️агрегация данных
.
На примере решим первую задачку - парсинг сырья. В нашем пайплайне исходные данные сохраняются в таблицу
где
Пишем DDL целевой таблицы:
Вытаскиваем поля: время (оно в UTC), общее описание погоды, детальное описание, температура, ощущаемая температура, давление (ГПаскаль), влажность.
Именно MV и будет парсить и перекладывать данные из сырья в
Чтобы превратить тыкву в золушку необходимо добавить код создания MV: по классике что создаем, где создаем и для для MV куда пишем данные (этот кусочек ниже):
.
Для поста про ORDER BY была создана github репа, в ней есть пайплайн который каждый 5 минут получает погодные данные по API и складывает их в raw таблицу.
Глянуть схему 👀
.
MATERIALIZED VIEW (MV) - можно рассматривать как триггер, реагирующий на вставку данных (в отличие от триггеров в реляционках, реагирует на блок вставляемых данных, а не на отдельную строку ☝️). В Clickhouse MV отделено от целевой таблицы, поэтому для себя MV представляю как процесс, запускающийся для вставляемых данных и загружающий их в целевую таблицу.
.
При помощи MV можно решать ряд задач:
▪️парсинг сырых данных
▪️фильтрация сырья
▪️роутинг данных
▪️агрегация данных
.
На примере решим первую задачку - парсинг сырья. В нашем пайплайне исходные данные сохраняются в таблицу
cdc.openweathermap_raw:CREATE TABLE cdc.openweathermap_raw
(
record_timestamp DateTime64(6),
record_value String
)
ENGINE=MergeTree
ORDER BY (record_timestamp)
где
record_value - json объект с погодой, который получаем из api. Создадим MV, который будет парсить json и сохранять в таблицу cdc.openweathermap. Посмотреть пример json можно на сайте.Пишем DDL целевой таблицы:
CREATE OR REPLACE TABLE cdc.openweathermap
(
record_timestamp DateTime64,
dt DateTime,
main String,
denoscription String,
temp Float64,
feels_like Float64,
pressure Float64,
humidity Float64
)
ENGINE=MergeTree
PARTITION BY toStartOfWeek(record_timestamp)
ORDER BY (main, denoscription, record_timestamp)
Вытаскиваем поля: время (оно в UTC), общее описание погоды, детальное описание, температура, ощущаемая температура, давление (ГПаскаль), влажность.
Именно MV и будет парсить и перекладывать данные из сырья в
cdc.openweathermap. Напишем запрос, который парсит данные:SELECT record_timestamp ,
FROM_UNIXTIME(toUInt64(JSONExtractString(record_value, 'dt'))) AS dt,
JSONExtractString(arrayElement(JSONExtractArrayRaw(record_value, 'weather'), 1), 'main') AS main,
JSONExtractString(arrayElement(JSONExtractArrayRaw(record_value, 'weather'), 1), 'denoscription') AS denoscription,
JSONExtractFloat(JSONExtractString(record_value, 'main'), 'temp') AS temp ,
JSONExtractFloat(JSONExtractString(record_value, 'main'), 'feels_like') AS feels_like,
0.750062 * JSONExtractUInt(JSONExtractString(record_value, 'main'), 'pressure') AS pressure,
JSONExtractUInt(JSONExtractString(record_value, 'main'), 'humidity') AS humidity
FROM cdc.openweathermap_raw
Чтобы превратить тыкву в золушку необходимо добавить код создания MV: по классике что создаем, где создаем и для для MV куда пишем данные (этот кусочек ниже):
CREATE MATERIALIZED VIEW cdc.openweathermap_mv
TO cdc.openweathermap
...
🔥1
Полный код найдете в репозитории
.
Наш процесс парсинга готов - теперь только НОВЫЕ поступающие данные будут последовательно проходить стадии: вставка в raw, выполнение MV, вставка в целевую таблицу (сам процесс происходит автоматически в фоне).
Чтобы и старые данные прошли через MV нужно дополнительно присесть:
- можно через обмен таблицами
- можно до создания MV выполнить соответствующий инсерт в целевую таблицу, после создать MV
.
Это не очень удобно, но очень гибко: на практике так парсятся логи аппметрики (в Q1 хотим роутить данные тем же механизмом) + делал кейс, когда N топиков кафки парсятся в одну таблицу событий (просто все MV смотрят в одну целевую + структуру единая).
.
В теме MV существуют проекции (projection) - аналогичный механизм, только процесс создания упрощен и менее гибок, но содержит большой +, все данные имеющиеся в исходной таблице будут пропущены через проекцию (об этом я с ужасом узнал на продовом кластере😱).
Естественно тестить надо на чем-то большом и мощном, выбрал аппметрику (сотни млн событий ежедневно, лог за пару последних лет). В рамках одной из задач требуется оценка кол-ва данных за день, создал проекцию (
.
Для глубокого погружения рекомендую отличное видео 🎥
#clickhouse #materializedview #mv #view
.
Наш процесс парсинга готов - теперь только НОВЫЕ поступающие данные будут последовательно проходить стадии: вставка в raw, выполнение MV, вставка в целевую таблицу (сам процесс происходит автоматически в фоне).
Чтобы и старые данные прошли через MV нужно дополнительно присесть:
- можно через обмен таблицами
- можно до создания MV выполнить соответствующий инсерт в целевую таблицу, после создать MV
.
Это не очень удобно, но очень гибко: на практике так парсятся логи аппметрики (в Q1 хотим роутить данные тем же механизмом) + делал кейс, когда N топиков кафки парсятся в одну таблицу событий (просто все MV смотрят в одну целевую + структуру единая).
.
В теме MV существуют проекции (projection) - аналогичный механизм, только процесс создания упрощен и менее гибок, но содержит большой +, все данные имеющиеся в исходной таблице будут пропущены через проекцию (об этом я с ужасом узнал на продовом кластере😱).
Естественно тестить надо на чем-то большом и мощном, выбрал аппметрику (сотни млн событий ежедневно, лог за пару последних лет). В рамках одной из задач требуется оценка кол-ва данных за день, создал проекцию (
group by date) и думаю, только новые данные будут обрабатываться. Каково же было моё удивление, когда в результате запрос я обнаружил результаты всей истории (стоит отметить, что получились они за пару секунд🚀, в то время как обычный запрос агрегации будет работать десятки минут, если не упадет по памяти)..
Для глубокого погружения рекомендую отличное видео 🎥
#clickhouse #materializedview #mv #view
🔥2👍1
♻️ Апдейт к посту про ORDER BY
.
В репе используется Python pipeline для обращения к API (решили и решили). Но в ClickHouse есть табличная функция url, используя которую можно описать альтернативный способ загрузки данных.
.
Например, вот так получаем ответ от API:
.
Добавляем дополнительное поле с
и получаем готовый код загрузки сырья из API
Теперь достаточно по расписанию выполнять данный скрипт☝️
.
ps: в работе стараюсь искать наиболее нативный способ (с использованием встроенного функционала) решения задачи - а как вы предпочитаете:
✈️ строить самолет
🎧 или использовать минимум средств
❓
.
#clickhouse #url #alternative
.
В репе используется Python pipeline для обращения к API (решили и решили). Но в ClickHouse есть табличная функция url, используя которую можно описать альтернативный способ загрузки данных.
.
Например, вот так получаем ответ от API:
SELECT *
FROM url('https://api.openweathermap.org/data/2.5/weather?lat=55.567586&lon=38.225004&appid=YOUR_APPID&units=metric',
JSONAsString, 'record_value String')
.
Добавляем дополнительное поле с
record_timestamp, синтаксис INSERTи получаем готовый код загрузки сырья из API
Теперь достаточно по расписанию выполнять данный скрипт☝️
.
ps: в работе стараюсь искать наиболее нативный способ (с использованием встроенного функционала) решения задачи - а как вы предпочитаете:
✈️ строить самолет
🎧 или использовать минимум средств
❓
.
#clickhouse #url #alternative
👍2