Where is data, Lebowski – Telegram
Where is data, Lebowski
237 subscribers
83 photos
2 videos
83 links
Канал про разное в data-мире:
- от библиотек визуализации до data egineering
- от графиков до элементов разработки
- от .csv до API
Download Telegram
​​Задачки с собесов - 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
🔥1
https://bar-or-pie.dianov.org/result-1300.html
Бар о пай

📈Это однозначно лучшее про датавиз-гигиену
.
Пройдите тест и узнайте:
- в каких случаях стоит использовать цветовую кодировку, а когда нет
- когда обводка это зло
- когда следует повернуть ваш барплот
- или когда не следует подписывать все числа на графике
.
И наконец ответьте себе на главный вопрос: Bar or Pie😉
ps: а еще там есть ссылки, в которых более подробно изложена та или иная идея
.
#plot #data #bar #pie
3👍1
​​😎А вы уже еBASH.....
.
Не перестаю удивляться магии линукса и простых (но это не точно) консольных команд.
.
Разбираясь с уткой по-пекински 🦆 (про неё тоже будет пост, довольно интересная альтернатива sqlite3, особенно если хочется практиковать SQL) в доке обнаружил утилиту для построения графиков в терминале youplot 😈. В кратком tutorial можно найти довольно приличный набор графиков:
- столбчатые
- линейные
- гистограммы или графики плотности
- 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)
История умалчивает подробности и даже почему выбран такой способ загрузки: целевая таблица полностью перегружается каждый день.
.
Работа шла стандартным флоу (практикую частичное решение задач):
- написал даг с коннектом к источнику
- таски для создания инфры
- несколько таск групп с небольшим селектом из источника (проверить, что всё ок и источник отдает данные)
- заварил 🫖 и стал налюдать за даграном
.
Всё шло хорошо до момента тестирования вьюхи 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 -> запросы можно выполнять как 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

Тут два метода:
- 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
👍2
​​Clickhouse-notes⚡️
.
Предикат  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
Channel name was changed to «Where is data, Lebowski»
Clickhouse-notes ⚡️
.
Продолжаем грузить клик
.
 В предыдущих 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
Маленький, но крайне полезный
.
Сегодня для вас маленький хук, при создании таблицы в клике по образу и подобию уже существующей не обязательно переписывать схему, достаточно указать эту аналогичную таблицу:
CREATE TABLE sandbox.table as stg.another_table
ENGINE=MergeTree
ORDER BY .....
SETTINGS ....
Это полезно, например при тестировании различных настроек: кодеки сжатия, партицирование, движки, секция ORDER BY.

#clickhouse #4 #liketable
👍2
С Новым годом, все причастные к миру данных🎄
.
ps: не будет долгих речей, просто будьте счастливы🦄

И напишите в комментах ваш любимый новогодний фильм 🎥
.
#newyear #2023
4
Праздники пришли когда не ждали
.
Раскопал интересный нюанс, в процессе парсинга дат. Попробуйте выполнить такой код:
SELECT 
parseDateTimeBestEffort('1950-01-01');

.
Результатом будите удивлены😳

#clickhouse #причуды
​​⚡️Clickhouse-notes - ответы (просвещаемся на каникулах 🙃)
.
Под одним из постом был комментарий:
Если не ошибаюсь, то стоит помнить, что 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
🔥2👍1
⚡️Clickhouse-notes - Оператор 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 можно решать ряд задач:
▪️парсинг сырых данных
▪️фильтрация сырья
▪️роутинг данных
▪️агрегация данных
.
На примере решим первую задачку - парсинг сырья. В нашем пайплайне исходные данные сохраняются в таблицу 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) - аналогичный механизм, только процесс создания упрощен и менее гибок, но содержит большой +, все данные имеющиеся в исходной таблице будут пропущены через проекцию (об этом я с ужасом узнал на продовом кластере😱).
Естественно тестить надо на чем-то большом и мощном, выбрал аппметрику (сотни млн событий ежедневно, лог за пару последних лет). В рамках одной из задач требуется оценка кол-ва данных за день, создал проекцию (group by date) и думаю, только новые данные будут обрабатываться. Каково же было моё удивление, когда в результате запрос я обнаружил результаты всей истории (стоит отметить, что получились они за пару секунд🚀, в то время как обычный запрос агрегации будет работать десятки минут, если не упадет по памяти).
.
Для глубокого погружения рекомендую отличное видео 🎥
#clickhouse #materializedview #mv #view
🔥2👍1
♻️ Апдейт к посту про ORDER BY
.
В репе используется 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