Merge pull request 'CLICK HOUSE kapko' (#17) from test into main
Reviewed-on: https://gitea.de-infra.servehttp.com/de-infrastructure/DWH/pulls/17 Reviewed-by: aleksey bogatyrev <abogatyrev@example.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# DWH
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
"""
|
||||||
|
DAG для запуска dbt run команд
|
||||||
|
"""
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from airflow import DAG
|
||||||
|
from airflow.operators.bash import BashOperator
|
||||||
|
|
||||||
|
default_args = {
|
||||||
|
'owner': 'airflow',
|
||||||
|
'depends_on_past': False,
|
||||||
|
'email_on_failure': False,
|
||||||
|
'email_on_retry': False,
|
||||||
|
'retries': 1,
|
||||||
|
'retry_delay': timedelta(minutes=5),
|
||||||
|
}
|
||||||
|
|
||||||
|
with DAG(
|
||||||
|
'dbt_run_example',
|
||||||
|
default_args=default_args,
|
||||||
|
description='Пример DAG для запуска dbt run',
|
||||||
|
schedule_interval=None, # Запуск вручную
|
||||||
|
start_date=datetime(2024, 1, 1),
|
||||||
|
catchup=False,
|
||||||
|
tags=['dbt', 'example'],
|
||||||
|
) as dag:
|
||||||
|
|
||||||
|
# Проверка версии dbt
|
||||||
|
dbt_debug = BashOperator(
|
||||||
|
task_id='dbt_debug',
|
||||||
|
bash_command='cd /dbt && dbt debug --project-dir . --profiles-dir /home/airflow/.dbt',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Установка зависимостей dbt
|
||||||
|
dbt_deps = BashOperator(
|
||||||
|
task_id='dbt_deps',
|
||||||
|
bash_command='cd /dbt && dbt deps --project-dir . --profiles-dir /home/airflow/.dbt',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Запуск dbt run
|
||||||
|
dbt_run = BashOperator(
|
||||||
|
task_id='dbt_run',
|
||||||
|
bash_command='cd /dbt && dbt run --project-dir . --profiles-dir /home/airflow/.dbt',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Запуск dbt test (опционально)
|
||||||
|
dbt_test = BashOperator(
|
||||||
|
task_id='dbt_test',
|
||||||
|
bash_command='cd /dbt && dbt test --project-dir . --profiles-dir /home/airflow/.dbt',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Определяем порядок выполнения задач
|
||||||
|
dbt_debug >> dbt_deps >> dbt_run >> dbt_test
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
INSERT INTO pet_project.courses (course_id, title, category, created_at) VALUES
|
||||||
|
(1, 'SQL для начинающих', 'data', '2023-01-01 00:00:00'),
|
||||||
|
(2, 'Python для анализа данных', 'programming', '2023-01-15 00:00:00'),
|
||||||
|
(3, 'BI с нуля', 'business', '2023-03-01 00:00:00');
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
INSERT INTO pet_project.enrollments (id, user_id, course_id, enrolled_at) VALUES
|
||||||
|
(1, 1, 1, '2023-01-15'),
|
||||||
|
(2, 1, 2, '2023-02-01'),
|
||||||
|
(3, 2, 1, '2023-01-20'),
|
||||||
|
(4, 3, 2, '2023-03-05'),
|
||||||
|
(5, 4, 3, '2023-04-01');
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
INSERT INTO pet_project.fact_lesson_views (id, user_id, lesson_id, viewed_at) VALUES
|
||||||
|
(1, 1, 1, '2023-01-16 10:00:00'),
|
||||||
|
(2, 1, 2, '2023-01-16 10:15:00'),
|
||||||
|
(3, 2, 1, '2023-01-21 09:00:00'),
|
||||||
|
(4, 3, 3, '2023-03-06 12:00:00'),
|
||||||
|
(5, 4, 4, '2023-04-02 10:00:00'),
|
||||||
|
(6, 4, 5, '2023-04-03 10:00:00');
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
INSERT INTO pet_project.lessons (lesson_id, course_id, title, duration_min) VALUES
|
||||||
|
(1, 1, 'SELECT и FROM', 10),
|
||||||
|
(2, 1, 'JOIN', 15),
|
||||||
|
(3, 2, 'Pandas', 20),
|
||||||
|
(4, 3, 'Основы BI', 12),
|
||||||
|
(5, 3, 'Метрики и дашборды', 18);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
INSERT INTO pet_project.users (user_id, name, age, email, registration_date) VALUES
|
||||||
|
(1, 'Alice', 25, 'alice@mail.com', '2023-01-10 00:00:00'),
|
||||||
|
(2, 'Bob', 30, 'bob@gmail.com', '2023-02-05 00:00:00'),
|
||||||
|
(3, 'Charlie', 22, 'charlie@mail.com', '2023-02-20 00:00:00'),
|
||||||
|
(4, 'Diana', 28, 'diana@mail.com', '2023-03-01 00:00:00'),
|
||||||
|
(5, 'Ethan', 35, 'ethan@gmail.com', '2023-03-10 00:00:00');
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
-- ### ✅ **Задание 5: Напиши SQL-запросы к витринам**
|
||||||
|
-- **Напиши свои вариации для практики.**
|
||||||
|
-- 📌 *Ниже — примеры.*
|
||||||
|
-- ### Топ-5 самых просматриваемых уроков
|
||||||
|
-- SELECT
|
||||||
|
-- lesson_title,
|
||||||
|
-- course_title,
|
||||||
|
-- total_views
|
||||||
|
-- FROM lesson_popularity_summary
|
||||||
|
-- ORDER BY total_views DESC
|
||||||
|
-- LIMIT 5;
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
SELECT * FROM pet_project.mv_lesson_popularity_summary
|
||||||
|
) AS top_lessons
|
||||||
|
LIMIT 5
|
||||||
|
;
|
||||||
|
|
||||||
|
WITH selected_top AS (SELECT *
|
||||||
|
FROM pet_project.mv_lesson_popularity_summary)
|
||||||
|
SELECT *
|
||||||
|
FROM selected_top
|
||||||
|
LIMIT 5
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ### Неактивные пользователи, записавшиеся на курсы
|
||||||
|
-- SELECT
|
||||||
|
-- name,
|
||||||
|
-- email,
|
||||||
|
-- registered_courses_count
|
||||||
|
-- FROM inactive_users_summary
|
||||||
|
-- WHERE registered_courses_count > 0
|
||||||
|
-- ORDER BY registration_date DESC;
|
||||||
|
|
||||||
|
-- дальше по аналогии как ВЫШЕ, подзапрос или CTE
|
||||||
|
|
||||||
|
-- ### Курсы с самым высоким процентом завершения
|
||||||
|
-- SELECT
|
||||||
|
-- course_title,
|
||||||
|
-- AVG(completion_rate) AS avg_completion
|
||||||
|
-- FROM course_completion_rate
|
||||||
|
-- GROUP BY course_title
|
||||||
|
-- ORDER BY avg_completion DESC
|
||||||
|
-- LIMIT 5;
|
||||||
|
|
||||||
|
-- дальше по аналогии как ВЫШЕ, подзапрос или CTE
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
-- ### ✅ **Задание 4: Создай витрину `course_completion_rate`**
|
||||||
|
--
|
||||||
|
-- **Цель:** проанализировать, насколько хорошо пользователи проходят курсы.
|
||||||
|
--
|
||||||
|
-- 📌 **Что нужно сделать:**
|
||||||
|
--
|
||||||
|
-- - Сформируй таблицу, где строка — это пользователь + курс.
|
||||||
|
-- - Для каждой пары нужно рассчитать:
|
||||||
|
-- - Общее число уроков в курсе
|
||||||
|
-- - Сколько из них просмотрел конкретный пользователь
|
||||||
|
-- - Коэффициент завершения (`lessons_viewed / lessons_in_course`)
|
||||||
|
--
|
||||||
|
-- **Как использовать метрику:**
|
||||||
|
--
|
||||||
|
-- Можно анализировать, какие курсы чаще всего "бросают", какие хорошо проходят, где стоит улучшить структуру или добавить мотивационные механики (геймификация, рассылки и т.п.).
|
||||||
|
WITH course_lesson AS (SELECT course_id, count() AS total_lessons
|
||||||
|
FROM pet_project.lessons
|
||||||
|
GROUP BY course_id)
|
||||||
|
SELECT concat(u.name, ', ', c.title) AS user_course,
|
||||||
|
any(cl.total_lessons) AS lessons_in_course,
|
||||||
|
count(DISTINCT flv.lesson_id) AS lessons_viewed,
|
||||||
|
round(count(DISTINCT flv.lesson_id) / any(cl.total_lessons), 2) AS coef
|
||||||
|
FROM pet_project.users u
|
||||||
|
JOIN pet_project.fact_lesson_views flv ON flv.user_id = u.user_id
|
||||||
|
JOIN pet_project.lessons l ON l.lesson_id = flv.lesson_id
|
||||||
|
JOIN pet_project.courses c ON c.course_id = l.course_id
|
||||||
|
JOIN course_lesson cl ON cl.course_id = l.course_id
|
||||||
|
GROUP BY u.name, c.title
|
||||||
|
ORDER BY user_course
|
||||||
|
;
|
||||||
|
|
||||||
|
-- создание mat view
|
||||||
|
CREATE MATERIALIZED VIEW pet_project.mv_user_course_progress
|
||||||
|
ENGINE = AggregatingMergeTree()
|
||||||
|
ORDER BY (user_id, course_id)
|
||||||
|
POPULATE
|
||||||
|
AS
|
||||||
|
SELECT flv.user_id AS user_id,
|
||||||
|
l.course_id AS course_id,
|
||||||
|
any(u.name) AS user_name,
|
||||||
|
any(c.title) AS course_title,
|
||||||
|
any(cl.total_lessons) AS lessons_in_course,
|
||||||
|
count(DISTINCT flv.lesson_id) AS lessons_viewed
|
||||||
|
FROM pet_project.fact_lesson_views flv
|
||||||
|
JOIN pet_project.users u ON u.user_id = flv.user_id
|
||||||
|
JOIN pet_project.lessons l ON l.lesson_id = flv.lesson_id
|
||||||
|
JOIN pet_project.courses c ON c.course_id = l.course_id
|
||||||
|
JOIN (
|
||||||
|
SELECT course_id, count() AS total_lessons
|
||||||
|
FROM pet_project.lessons
|
||||||
|
GROUP BY course_id
|
||||||
|
) cl ON cl.course_id = l.course_id
|
||||||
|
GROUP BY flv.user_id, l.course_id
|
||||||
|
;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
-- ### ✅ **Задание 3: Создай витрину `inactive_users_summary`**
|
||||||
|
--
|
||||||
|
-- **Цель:** выявить пользователей, которые **зарегистрировались, но ничего не посмотрели**.
|
||||||
|
--
|
||||||
|
-- 📌 **Что нужно сделать:**
|
||||||
|
--
|
||||||
|
-- - Подготовь таблицу, где каждая строка — один такой "неактивный" пользователь.
|
||||||
|
-- - Для каждого пользователя нужны:
|
||||||
|
-- - ID, имя, email, возраст
|
||||||
|
-- - Количество курсов, на которые он записался
|
||||||
|
-- - Дата регистрации
|
||||||
|
-- **Где пригодится:**
|
||||||
|
--
|
||||||
|
-- Эта витрина может использоваться для продуктовой аналитики, триггерных рассылок (например, напоминаний), анализа оттока, повышения вовлечённости.
|
||||||
|
SELECT u.user_id AS user_id,
|
||||||
|
any(u.name) AS user_name,
|
||||||
|
any(u.email) AS email,
|
||||||
|
any(u.age) AS age,
|
||||||
|
count() course_count,
|
||||||
|
any(u.registration_date) AS registration_date
|
||||||
|
FROM pet_project.users u
|
||||||
|
LEFT JOIN pet_project.enrollments e USING (user_id)
|
||||||
|
GROUP BY u.user_id
|
||||||
|
ORDER BY u.user_id
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Создание вьюшки
|
||||||
|
-- Я убрал countDistinctState(e.course_id) - потому что если e.course_id IS NULL, то считать нечего (курсов = 0 у всех).
|
||||||
|
CREATE MATERIALIZED VIEW pet_project.mv_inactive_users_summary
|
||||||
|
ENGINE AggregatingMergeTree()
|
||||||
|
ORDER BY (user_id)
|
||||||
|
AS
|
||||||
|
SELECT u.user_id AS user_id,
|
||||||
|
any(u.name) AS user_name,
|
||||||
|
any(u.email) AS email,
|
||||||
|
any(u.age) AS age,
|
||||||
|
any(u.registration_date) AS registration_date
|
||||||
|
FROM pet_project.users u
|
||||||
|
LEFT JOIN pet_project.enrollments e USING (user_id)
|
||||||
|
WHERE e.user_id IS NULL
|
||||||
|
GROUP BY u.user_id;
|
||||||
|
-- проверка
|
||||||
|
SELECT * FROM pet_project.mv_inactive_users_summary;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
-- ### ✅ **Задание 2: Подготовь структуру витрины `lesson_popularity_summary`**
|
||||||
|
--
|
||||||
|
-- **Цель:** анализировать популярность каждого урока.
|
||||||
|
--
|
||||||
|
-- 📌 **Что нужно сделать:**
|
||||||
|
--
|
||||||
|
-- - Спроектируй таблицу, где каждая строка — один урок.
|
||||||
|
-- - Для каждого урока должны храниться:
|
||||||
|
-- - ID и название урока
|
||||||
|
-- - ID и название курса, к которому он относится
|
||||||
|
-- - Общее число просмотров
|
||||||
|
-- - Количество уникальных пользователей, посмотревших урок
|
||||||
|
-- - Дата первого и последнего просмотра
|
||||||
|
--
|
||||||
|
-- **Зачем это нужно:**
|
||||||
|
--
|
||||||
|
-- Эта витрина поможет выявлять наиболее популярные уроки и курсы, следить за актуальностью контента, понимать вовлечённость студентов по отдельным материалам.
|
||||||
|
SELECT l.lesson_id AS lesson_id,
|
||||||
|
l.title AS lesson_name,
|
||||||
|
c.course_id AS course_id,
|
||||||
|
c.title AS course_name,
|
||||||
|
countOrNull() AS total_view,
|
||||||
|
uniqOrNull(flv.user_id) AS unique_users,
|
||||||
|
min(flv.viewed_at) AS first_date,
|
||||||
|
max(flv.viewed_at) AS last_date
|
||||||
|
FROM pet_project.lessons l
|
||||||
|
LEFT JOIN pet_project.courses c ON c.course_id = l.course_id
|
||||||
|
LEFT JOIN pet_project.fact_lesson_views flv ON flv.lesson_id = l.lesson_id
|
||||||
|
GROUP BY l.lesson_id, l.title, c.course_id, c.title;
|
||||||
|
|
||||||
|
-- Создание мат view
|
||||||
|
CREATE MATERIALIZED VIEW pet_project.mv_lesson_popularity_summary
|
||||||
|
ENGINE = AggregatingMergeTree()
|
||||||
|
ORDER BY (lesson_id, course_id)
|
||||||
|
POPULATE
|
||||||
|
AS
|
||||||
|
SELECT l.lesson_id AS lesson_id,
|
||||||
|
anyState(l.title) AS lesson_name,
|
||||||
|
c.course_id AS course_id,
|
||||||
|
anyState(c.title) AS course_name,
|
||||||
|
countState() AS total_views,
|
||||||
|
uniq(flv.user_id) AS unique_users,
|
||||||
|
min(flv.viewed_at) AS first_date,
|
||||||
|
max(flv.viewed_at) AS last_date
|
||||||
|
FROM pet_project.lessons l
|
||||||
|
LEFT JOIN pet_project.courses c ON c.course_id = l.course_id
|
||||||
|
LEFT JOIN pet_project.fact_lesson_views flv ON flv.lesson_id = l.lesson_id
|
||||||
|
GROUP BY l.lesson_id, c.course_id;
|
||||||
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
-- create users table
|
||||||
|
CREATE TABLE pet_project.users
|
||||||
|
(
|
||||||
|
user_id UInt32,
|
||||||
|
name String,
|
||||||
|
age UInt16,
|
||||||
|
email String,
|
||||||
|
registration_date DateTime
|
||||||
|
)
|
||||||
|
ENGINE MergeTree()
|
||||||
|
ORDER BY (user_id);
|
||||||
|
|
||||||
|
-- create table course
|
||||||
|
DROP TABLE IF EXISTS pet_project.courses;
|
||||||
|
CREATE TABLE pet_project.courses
|
||||||
|
(
|
||||||
|
course_id UInt32,
|
||||||
|
title String,
|
||||||
|
category String,
|
||||||
|
created_at DateTime
|
||||||
|
)
|
||||||
|
ENGINE ReplacingMergeTree(created_at)
|
||||||
|
ORDER BY (course_id);
|
||||||
|
|
||||||
|
-- create table dim_lesson
|
||||||
|
DROP TABLE pet_project.lessons;
|
||||||
|
CREATE TABLE pet_project.lessons
|
||||||
|
(
|
||||||
|
lesson_id UInt32,
|
||||||
|
title String,
|
||||||
|
duration_min UInt16,
|
||||||
|
course_id UInt32
|
||||||
|
)
|
||||||
|
ENGINE MergeTree()
|
||||||
|
ORDER BY (lesson_id, course_id);
|
||||||
|
|
||||||
|
-- create table fact_lesson_views
|
||||||
|
DROP TABLE pet_project.fact_lesson_views;
|
||||||
|
CREATE TABLE pet_project.fact_lesson_views
|
||||||
|
(
|
||||||
|
id UInt32,
|
||||||
|
user_id UInt32,
|
||||||
|
lesson_id UInt32,
|
||||||
|
course_id UInt32,
|
||||||
|
viewed_at Datetime
|
||||||
|
)
|
||||||
|
ENGINE MergeTree()
|
||||||
|
PARTITION BY toYYYYMM(viewed_at)
|
||||||
|
ORDER BY (course_id, lesson_id, user_id);
|
||||||
|
ALTER TABLE pet_project.fact_lesson_views
|
||||||
|
ADD PROJECTION user_lookup (
|
||||||
|
SELECT * ORDER BY (user_id, lesson_id, course_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE pet_project.fact_lesson_views
|
||||||
|
MATERIALIZE PROJECTION user_lookup;
|
||||||
|
|
||||||
|
-- create table enrollments
|
||||||
|
CREATE TABLE pet_project.enrollments
|
||||||
|
(
|
||||||
|
id UInt32,
|
||||||
|
user_id UInt32,
|
||||||
|
course_id UInt32,
|
||||||
|
enrolled_at DateTime
|
||||||
|
)
|
||||||
|
ENGINE MergeTree()
|
||||||
|
ORDER BY (user_id, course_id);
|
||||||
Reference in New Issue
Block a user