А пока вы вспоминаете SQL
.
Принес вам забавный (ну не очень) случай из работы.
.
На скрине выше:
- первое поле есть в таблице
- второго нет (подчеркнуто красным)
.
А где же разница? А разница в букве
.
Написать код, забирающий данные - 15 минут, найти такую ошибку - бесценно❤️
.
Принес вам забавный (ну не очень) случай из работы.
.
На скрине выше:
- первое поле есть в таблице
- второго нет (подчеркнуто красным)
.
А где же разница? А разница в букве
C - в существующем поле она кириллическая🤷♂️🤯.
Написать код, забирающий данные - 15 минут, найти такую ошибку - бесценно❤️
🥴2
Задача 1️⃣
.
На очереди первая задачка по SQL, кажется, что она самая популярная,она была в двух вариантах:
1. Даны следующие таблицы
.
Ответы оставляем в комментариях👇 ps: тут конечно могут помочь диаграммы Венна (кружочки), но они имеют изъян.
#вопросы #собес #sql
.
На очереди первая задачка по SQL, кажется, что она самая популярная,она была в двух вариантах:
1. Даны следующие таблицы
a - 5 rowsВыполняется такой запрос:
b - 10 rows
select count(*)2. Даны таблицы t1 и t2
from a
unknown join b on unknown (a.a=b.b)
Какое максимальное и минимальное количество может быть для разных join? Примечание: значения в таблицах уникальны.
t1 t2
1 3
2 4
3 5
4 6
5 7
Что получится при разных видах JOIN
.
Ответы оставляем в комментариях👇 ps: тут конечно могут помочь диаграммы Венна (кружочки), но они имеют изъян.
#вопросы #собес #sql
Задачки 2️⃣ и 3️⃣
+ дополнительный вопрос от меня
——————————————————
.
Жду ваших решений в комментариях и помните, у задачки необязательно есть одно единственное решение😉
#вопросы #собес #sql
Дана таблица:
CREATE TABLE IF NOT EXISTS prices (
id bigint not null,
price int4 not null,
dt date not null
);
Пример данных:
id price dt
1 100 2021-01-01
1 110 2021-05-05
В таблице prices хранятся данные по ценам товаров. В этой таблице есть другие цены и другие товары, эти приведены для примера.
При изменении цены записывается новая строка с датой начиная с которой это цена действует.
Цена действует до тех пор, пока она не сменится другой ценой.
Надо написать параметризованный запрос, который по id и dt вернет цену товара на этот день.
Например:id=1, dt=2021-01-02 => price=100id=1, dt=2021-06-01 => price=110.
+ дополнительный вопрос от меня
Какой механизм реализован в этой таблице?——————————————————
Дана таблица Client (id, email, phone)
1. Найти все email которые встречаются в таблице более 2х раз.
2. Вывести id, email, email_дуплицирован(1,0)
☝️1 и 2 - два разных запроса
.
Жду ваших решений в комментариях и помните, у задачки необязательно есть одно единственное решение😉
#вопросы #собес #sql
Задача 4️⃣ (в двух частях)
.
.
Жду ваших верных решений😎
#вопросы #собес #sql
.
Дана таблица:
CREATE TABLE IF NOT EXISTS deliveries (
id bigint not null,
dt date not null,
id_supplier bigint not null,
id_product bigint not null,
quantity int4 not null,
price decimal(16, 4)
);
Пример данных:
id dt id_supplier id_product quantity price
1 2021-01-01 2 134 5 10.5
2 2021-05-05 1 135 10 11.0
Задача 2.1
В таблице хранятся данные о поставках, каждая поставка имеет:
свой уникальный id, дату совершения поставки dt, данные о поставщике id_supplier и товаре id_product, количестве штук товара в поставке quantity, цене одной штуки price.
Необходимо найти поставщика, который поставил нам товаров на наибольшую сумму денег.
Задача 2.2
Дополнительно дан справочник:
CREATE TABLE IF NOT EXISTS supplier (
id bigint not null,
name VARCHAR(200) not null
);
Пример данных:
id name
1 Поставщик1
2 Поставщик2
Как найти поставщиков которые ничего не поставляли, если рядом есть справочник поставщиков?
.
Жду ваших верных решений😎
#вопросы #собес #sql
Задача 5️⃣
.
Продолжаем серию SQL задачек, на очереди аналитическая задачка.
.
.
Дерзайте, задачку точно можно решить не одним способом😉 Используйте все ваши знания и творческий подход😎
#вопросы #собес #sql
.
Продолжаем серию SQL задачек, на очереди аналитическая задачка.
.
Посчитать среднее время нахождения в статусе "Подтверждён" , за которым следовал статус "Доставлен" для заказов , созданных в этом году.
-- Таблица, со статусами заказа
create table OrderStatusChangeLog
(
order_id INTEGER
, status_id INTEGER
, time_changed DATETIME
);
comment on column OrderStatusChangeLog.order_id is 'ID заказа';
comment on column OrderStatusChangeLog.status_id is 'ID статуса заказа';
comment on column OrderStatusChangeLog.time_changed is 'Время изменения заказа';
Пример (сэмпл) данных в таблице:
+--------+---------+-------------------+
|order_id|status_id|time_changed |
+--------+---------+-------------------+
|14324 |1 |01.05.2022 10:00:01|
|14324 |2 |01.05.2022 10:25:17|
|14324 |10 |01.05.2022 10:30:55|
|14324 |7 |01.05.2022 10:31:24|
|14324 |10 |01.05.2022 15:30:54|
|14324 |5 |04.05.2022 12:22:32|
|1468 |1 |01.05.2022 10:00:01|
|1468 |2 |01.05.2022 11:25:23|
|1468 |10 |01.05.2022 11:30:48|
|67825 |1 |01.05.2022 10:00:01|
|67825 |2 |01.05.2022 10:25:44|
|67825 |10 |01.05.2022 10:30:05|
|67825 |5 |08.05.2022 16:32:49|
+--------+---------+-------------------+
-- Таблица-справочник статусов
create table OrderStatus
(
status_id INTEGER
, status_name VARCHAR(255)
);
comment on column OrderStatus.status_id is 'ID статуса заказа';
comment on column OrderStatus.status_name is 'Наименование статуса заказа';
Пример (сэмпл) данных в таблице:
+---------+-----------+
|status_id|status_name|
+---------+-----------+
|1 |Новый |
|2 |Оплачен |
|10 |Подтверждён|
+---------+-----------+
-- Таблица с заказами
create table Orders
(
order_id INTEGER PRIMARY KEY
, time_created DATETIME
, client_id INTEGER
, status_id INTEGER
);
comment on column Orders.order_id is 'ID заказа';
comment on column Orders.time_created is 'Время создания заказа';
comment on column Orders.client_id is 'ID клиента';
comment on column Orders.status_id is 'ID текущего статуса заказа';
Пример (сэмпл) данных в таблице:
+--------+-------------------+---------+---------+
|order_id|time_created |client_id|status_id|
+--------+-------------------+---------+---------+
|1468 |01.05.2022 10:00:01|234 |10 |
|14324 |01.05.2022 10:00:01|738294 |5 |
|3421987 |10.03.2021 19:03:55|761285 |5 |
+--------+-------------------+---------+---------+
.
Дерзайте, задачку точно можно решить не одним способом😉 Используйте все ваши знания и творческий подход😎
#вопросы #собес #sql
👍2
Задачки с собесов - 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 #причуды