{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Yuriy Gavrilov: posts tagged ETL",
    "_rss_description": "Welcome to my personal place for love, peace and happiness 🤖 Yuiry Gavrilov",
    "_rss_language": "en",
    "_itunes_email": "yvgavrilov@gmail.com",
    "_itunes_categories_xml": "",
    "_itunes_image": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic-square@2x.jpg?1643451008",
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/gavrilov.info\/tags\/etl\/",
    "feed_url": "https:\/\/gavrilov.info\/tags\/etl\/json\/",
    "icon": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic@2x.jpg?1643451008",
    "authors": [
        {
            "name": "Yuriy Gavrilov - B[u]g - for charity.gavrilov.eth",
            "url": "https:\/\/gavrilov.info\/",
            "avatar": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic@2x.jpg?1643451008"
        }
    ],
    "items": [
        {
            "id": "350",
            "url": "https:\/\/gavrilov.info\/all\/sovremenny-semanticheskiy-sloy-na-dbt-metricflow-duckdb-makrosy\/",
            "title": "Современный семантический слой на dbt + MetricFlow + DuckDB: макросы вместо пакетов",
            "content_html": "<p>В этой статье мы построим полностью рабочий семантический слой для аналитики на данных Superstore.csv (от Tableau Desktop, можно скачать его где-то), используя <b>dbt<\/b>, <b>MetricFlow<\/b> и <b>DuckDB<\/b>. Вместо устаревшего пакета `dbt_metrics` (который несовместим с dbt 1.12+), мы применим <b>современный подход<\/b> — вынесем логику метрик в <b>макросы dbt<\/b>. Это позволяет централизованно управлять расчётами, автоматически обновлять витрины при изменении метрик и использовать семантический слой для ad-hoc-запросов через `mf`. Все шаги проверены на последних версиях инструментов и готовы к использованию в реальных проектах.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/gavrilov.info\/pictures\/image-245.png\" width=\"2088\" height=\"456\" alt=\"\" \/>\n<\/div>\n<hr \/>\n<h3>1. Зачем нужен семантический слой и почему макросы — это современный подход?<\/h3>\n<p>Семантический слой решает ключевые проблемы аналитики:<\/p>\n<ul>\n<li><b>Единое место определения метрик<\/b> — бизнес-логика хранится в одном файле.<\/li>\n<li><b>Автоматическая генерация SQL<\/b> — не нужно писать `GROUP BY`, `JOIN` и агрегации вручную для ad-hoc-запросов.<\/li>\n<li><b>Согласованность<\/b> — аналитики и BI-инструменты используют одни и те же метрики.<\/li>\n<\/ul>\n<p>Ранее для использования метрик в моделях применялся пакет `dbt_metrics`, но он <b>несовместим с dbt 1.12 и выше<\/b> (требует версию <1.6.0). Современный подход — **выносить выражения метрик в макросы dbt**. Это:<\/p>\n<ul>\n<li>Не требует внешних пакетов.<\/li>\n<li>Работает с любой версией dbt.<\/li>\n<li>Даёт полный контроль над SQL.<\/li>\n<li>Легко поддерживается и версионируется.<\/li>\n<\/ul>\n<p>Мы будем использовать:<\/p>\n<ul>\n<li><b>dbt<\/b> 1.12.4 — для управления моделями и витринами.<\/li>\n<li><b>MetricFlow<\/b> (встроенный в dbt) — для семантического слоя и ad-hoc-запросов через `mf`.<\/li>\n<li><b>DuckDB<\/b> 1.5.5 — лёгкая БД для разработки.<\/li>\n<li><b>Макросы dbt<\/b> — для переиспользования логики метрик в витринах.<\/li>\n<\/ul>\n<hr \/>\n<h3>2. Установка инструментов и создание проекта<\/h3>\n<p>Используем `uv` — быстрый менеджер пакетов Python.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mkdir dbtflow_duck\ncd dbtflow_duck\n\nuv init\nuv venv\nsource .venv\/bin\/activate\n\nuv pip install dbt-duckdb dbt-metricflow pandas duckdb<\/code><\/pre><p>Проверяем версии (на момент написания):<\/p>\n<ul>\n<li>dbt-core: 1.12.4<\/li>\n<li>duckdb: 1.5.5<\/li>\n<li>metricflow: 0.212.0<\/li>\n<\/ul>\n<hr \/>\n<h3>3. Загрузка данных Superstore<\/h3>\n<p>Скачайте `Superstore.csv` (например, с Kaggle) и поместите в корень проекта.<\/p>\n<p>Создайте `load_data.py`:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">import pandas as pd\nimport duckdb\n\ndf = pd.read_csv('Superstore.csv', sep='\\t', encoding='latin1')\ndf.columns = [col.lower().replace(' ', '_').replace('\/', '_').replace('-', '_') for col in df.columns]\n\nfor col in ['sales', 'discount', 'profit']:\n    if col in df.columns:\n        df[col] = df[col].astype(str).str.replace(',', '.').astype(float)\n\ndf['order_date'] = pd.to_datetime(df['order_date'], dayfirst=True)\ndf['ship_date'] = pd.to_datetime(df['ship_date'], dayfirst=True)\ndf['postal_code'] = df['postal_code'].astype(str)\n\ndb_path = 'dbtflow_duck.duckdb'\ncon = duckdb.connect(db_path)\n\ncon.execute(&quot;DROP TABLE IF EXISTS superstore&quot;)\ncon.execute(&quot;&quot;&quot;\nCREATE TABLE superstore (\n    row_id INTEGER, order_id VARCHAR, order_date DATE, ship_date DATE,\n    ship_mode VARCHAR, customer_id VARCHAR, customer_name VARCHAR, segment VARCHAR,\n    country_region VARCHAR, city VARCHAR, state VARCHAR, postal_code VARCHAR,\n    region VARCHAR, product_id VARCHAR, category VARCHAR, sub_category VARCHAR,\n    product_name VARCHAR, sales DOUBLE, quantity INTEGER, discount DOUBLE, profit DOUBLE\n)\n&quot;&quot;&quot;)\n\ncon.execute(&quot;INSERT INTO superstore SELECT * FROM df&quot;)\nprint(f&quot;✅ Загружено {len(df)} строк в {db_path}&quot;)\ncon.close()<\/code><\/pre><p>Запуск:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">python load_data.py<\/code><\/pre><hr \/>\n<h3>4. Инициализация dbt-проекта вручную<\/h3>\n<p>Создаём папку проекта и файлы конфигурации (без `dbt init`, чтобы избежать проблем):<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mkdir dbt_project\ncd dbt_project<\/code><\/pre><p><b>dbt_project.yml<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">name: 'dbt_project'\nversion: '1.0.0'\nprofile: 'dbt_project'\n\nmodel-paths: [&quot;models&quot;]\nanalysis-paths: [&quot;analyses&quot;]\ntest-paths: [&quot;tests&quot;]\nseed-paths: [&quot;seeds&quot;]\nmacro-paths: [&quot;macros&quot;]\nsnapshot-paths: [&quot;snapshots&quot;]\n\nclean-targets:\n  - &quot;target&quot;\n  - &quot;dbt_packages&quot;\n\nmodels:\n  dbt_project:\n    +materialized: table<\/code><\/pre><p><b>profiles.yml<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dbt_project:\n  target: dev\n  outputs:\n    dev:\n      type: duckdb\n      path: ..\/dbtflow_duck.duckdb\n      schema: main\n      threads: 4<\/code><\/pre><p>Создаём структуру папок:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mkdir -p models analyses tests seeds macros snapshots\nexport DBT_PROFILES_DIR=$(pwd)\ndbt debug   # должно быть All checks passed!<\/code><\/pre><hr \/>\n<h3>5. Модели данных<\/h3>\n<p><b>models\/sources.yml<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">version: 2\n\nsources:\n  - name: default\n    schema: main\n    tables:\n      - name: superstore<\/code><\/pre><p><b>models\/superstore_clean.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT\n    row_id,\n    order_id,\n    order_date,\n    ship_date,\n    ship_mode,\n    customer_id,\n    customer_name,\n    segment,\n    country_region,\n    city,\n    state,\n    postal_code,\n    region,\n    product_id,\n    category,\n    sub_category,\n    product_name,\n    sales,\n    quantity,\n    discount,\n    profit\nFROM {{ source('default', 'superstore') }}<\/code><\/pre><p><b>models\/time_spine.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT \n    CAST(generate_series AS DATE) AS date_day\nFROM generate_series(DATE '2020-01-01', DATE '2026-12-31', INTERVAL '1' DAY)<\/code><\/pre><p><b>models\/metricflow_time_spine.yml<\/b> (обязательно для MetricFlow):<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">models:\n  - name: time_spine\n    description: &quot;A time spine with one row per day for MetricFlow.&quot;\n    time_spine:\n      standard_granularity_column: date_day\n    columns:\n      - name: date_day\n        granularity: day<\/code><\/pre><hr \/>\n<h3>6. Семантическая модель и метрики<\/h3>\n<p><b>models\/superstore.yml<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">semantic_models:\n  - name: superstore\n    model: ref('superstore_clean')\n    description: &quot;Superstore sales data&quot;\n    defaults:\n      agg_time_dimension: order_date\n    \n    entities:\n      - name: order_id\n        type: primary\n        \n    dimensions:\n      - name: order_date\n        type: time\n        type_params:\n          time_granularity: day\n      - name: category\n        type: categorical\n      - name: region\n        type: categorical\n    \n    measures:\n      - name: total_sales\n        agg: sum\n        expr: sales\n      - name: total_profit\n        agg: sum\n        expr: profit\n      - name: total_discount\n        agg: average          # Внимание: не &quot;avg&quot;, а &quot;average&quot;!\n        expr: discount\n\nmetrics:\n  - name: total_sales\n    label: Total Sales\n    type: simple\n    type_params:\n      measure: total_sales\n  - name: total_profit\n    label: Total Profit\n    type: simple\n    type_params:\n      measure: total_profit\n  - name: avg_discount\n    label: Average Discount\n    type: simple\n    type_params:\n      measure: total_discount\n  - name: profit_margin\n    label: Profit Margin\n    type: derived\n    type_params:\n      expr: total_profit \/ total_sales\n      metrics:\n        - total_profit\n        - total_sales<\/code><\/pre><p>Выполняем сборку и генерацию артефактов:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dbt run\ndbt parse<\/code><\/pre><hr \/>\n<h3>7. Ad-hoc-запросы через MetricFlow CLI (`mf`)<\/h3>\n<p>Проверяем конфигурацию:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mf validate-configs<\/code><\/pre><p>Список метрик:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mf list metrics<\/code><\/pre><p>Вывод:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">• avg_discount: metric_time, order_id__category, order_id__order_date, order_id__region\n• profit_margin: metric_time, order_id__category, order_id__order_date, order_id__region\n• total_profit: metric_time, order_id__category, order_id__order_date, order_id__region\n• total_sales: metric_time, order_id__category, order_id__order_date, order_id__region<\/code><\/pre><p>Примеры запросов:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mf query --metrics total_sales --group-by order_id__category\nmf query --metrics profit_margin --group-by order_id__region\nmf query --metrics avg_discount --group-by order_id__category<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-09-09-v-22.44.49.png\" width=\"1638\" height=\"630\" alt=\"\" \/>\n<\/div>\n<p>MetricFlow генерирует SQL автоматически — мы не пишем ни строчки кода для этих запросов.<\/p>\n<hr \/>\n<h3>8. Современный подход: макросы для переиспользования метрик в витринах<\/h3>\n<p>Вместо устаревшего пакета `dbt_metrics` мы создадим <b>макросы<\/b>, которые возвращают SQL-выражение для каждой метрики. Это позволяет:<\/p>\n<ul>\n<li>Централизованно управлять логикой расчёта.<\/li>\n<li>Использовать одну и ту же логику во всех витринах.<\/li>\n<li>Легко изменять метрику в одном месте.<\/li>\n<\/ul>\n<p><b>macros\/get_metric_expr.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{% macro get_total_sales_expr() %}\n    SUM(sales)\n{% endmacro %}\n\n{% macro get_total_profit_expr() %}\n    SUM(profit)\n{% endmacro %}\n\n{% macro get_avg_discount_expr() %}\n    AVG(discount)\n{% endmacro %}\n\n{% macro get_profit_margin_expr() %}\n    {{ get_total_profit_expr() }} \/ NULLIF({{ get_total_sales_expr() }}, 0)\n{% endmacro %}<\/code><\/pre><p>Теперь мы можем строить витрины, используя эти макросы.<\/p>\n<p><b>models\/sales_by_category.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT\n    category,\n    {{ get_total_sales_expr() }} AS total_sales\nFROM {{ ref('superstore_clean') }}\nGROUP BY category<\/code><\/pre><p><b>models\/profit_by_region.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT\n    region,\n    {{ get_total_profit_expr() }} AS total_profit,\n    {{ get_profit_margin_expr() }} AS profit_margin\nFROM {{ ref('superstore_clean') }}\nGROUP BY region<\/code><\/pre><p><b>models\/avg_discount_by_category.sql<\/b>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT\n    category,\n    {{ get_avg_discount_expr() }} AS avg_discount\nFROM {{ ref('superstore_clean') }}\nGROUP BY category<\/code><\/pre><p>После добавления новых моделей выполняем `dbt run` — все витрины создаются с актуальной логикой метрик.<\/p>\n<hr \/>\n<h3>9. Преимущества подхода с макросами<\/h3>\n<ul>\n<li><b>Совместимость<\/b> — работает с любой версией dbt, без внешних пакетов.<\/li>\n<li><b>Гибкость<\/b> — можно легко добавлять фильтры, условия, использовать оконные функции.<\/li>\n<li><b>Прозрачность<\/b> — SQL-код виден и контролируется, его легко отлаживать.<\/li>\n<li><b>Единый источник истины<\/b> — метрики определены как в YAML (для `mf`), так и в макросах (для витрин).<\/li>\n<li><b>Автоматизация<\/b> — изменения в макросах автоматически обновляют все витрины при следующем `dbt run`.<\/li>\n<\/ul>\n<hr \/>\n<h3>10. Расширенный пример: добавление фильтра в метрику<\/h3>\n<p>Предположим, нам нужна выручка только для категории “Technology”. Мы можем создать отдельный макрос:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{% macro get_tech_sales_expr() %}\n    SUM(CASE WHEN category = 'Technology' THEN sales ELSE 0 END)\n{% endmacro %}<\/code><\/pre><p>И использовать его в витрине:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">{{ config(materialized='table') }}\n\nSELECT\n    region,\n    {{ get_tech_sales_expr() }} AS tech_sales\nFROM {{ ref('superstore_clean') }}\nGROUP BY region<\/code><\/pre><p>Это демонстрирует, насколько легко расширять систему без изменения основной семантической модели.<\/p>\n<hr \/>\n<h3>11. Автоматизация пайплайнов<\/h3>\n<p>Настройте регулярный запуск `dbt run` в CI\/CD или Airflow. При каждом запуске:<\/p>\n<ul>\n<li>Обновляются сырые данные (если они загружаются заново).<\/li>\n<li>Пересчитываются модели `superstore_clean` и `time_spine`.<\/li>\n<li>Пересчитываются все витрины с актуальной логикой метрик из макросов.<\/li>\n<\/ul>\n<p>Таким образом, ваши отчёты всегда актуальны, а бизнес-логика централизована.<\/p>\n<hr \/>\n<h3>12. Заключение<\/h3>\n<p>Мы построили современный семантический слой на стеке dbt + MetricFlow + DuckDB, используя макросы для переиспользования логики метрик в витринах. Этот подход:<\/p>\n<ul>\n<li>Не требует устаревших пакетов.<\/li>\n<li>Совместим с последними версиями dbt.<\/li>\n<li>Даёт полный контроль над SQL.<\/li>\n<li>Легко масштабируется и поддерживается.<\/li>\n<\/ul>\n<p>Все команды проверены и работают на практике. Вы можете адаптировать этот проект под свои данные и метрики, получая все преимущества семантического слоя без лишних зависимостей.<\/p>\n<p><b>Полезные ссылки:<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/docs.getdbt.com\/docs\/use-dbt-semantic-layer\/dbt-sl\">dbt Semantic Layer docs<\/a><\/li>\n<li><a href=\"https:\/\/duckdb.org\/docs\/guides\/dbt\">DuckDB + dbt <\/a><\/li>\n<li><a href=\"https:\/\/docs.astral.sh\/uv\/\">uv package manager <\/a><\/li>\n<\/ul>\n<hr \/>\n",
            "date_published": "2026-09-09T22:52:12+03:00",
            "date_modified": "2026-09-09T22:52:04+03:00",
            "tags": [
                "Data",
                "Data Engineer",
                "ETL"
            ],
            "image": "https:\/\/gavrilov.info\/pictures\/image-245.png",
            "_date_published_rfc2822": "Wed, 09 Sep 2026 22:52:12 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "350",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/gavrilov.info\/pictures\/image-245.png",
                    "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-09-09-v-22.44.49.png"
                ]
            }
        },
        {
            "id": "292",
            "url": "https:\/\/gavrilov.info\/all\/dbt-otkryvaet-ishodny-kod-metricflow-upravlyaemye-metriki-dlya-a\/",
            "title": "dbt открывает исходный код MetricFlow: Управляемые метрики для AI и аналитики",
            "content_html": "<p>Компания dbt Labs объявила о важном изменении в своей стратегии: `MetricFlow`, ключевая технология, лежащая в основе `dbt Semantic Layer`, становится полностью открытой. Проект переводится под лицензию Apache 2.0, что позволяет любому использовать, изменять и встраивать его в свои продукты. Это стратегический шаг, направленный на создание единого отраслевого стандарта для определения бизнес-метрик, особенно в свете бурного развития AI-систем.<\/p>\n<p>Оригинал тут: <a href=\"https:\/\/www.getdbt.com\/blog\/open-source-metricflow-governed-metrics\">https:\/\/www.getdbt.com\/blog\/open-source-metricflow-governed-metrics<\/a><br \/>\nА гит тут: <a href=\"https:\/\/github.com\/dbt-labs\/metricflow\">https:\/\/github.com\/dbt-labs\/metricflow<\/a><\/p>\n<p>Еще кстати есть <a href=\"https:\/\/github.com\/memiiso\/opendbt\">https:\/\/github.com\/memiiso\/opendbt<\/a> ( Make dbt great again! :) Может они сольются с метриками, интересно.<\/p>\n<h3>Проблема: почему семантический слой стал критически важен<\/h3>\n<p>Концепция семантического слоя, который служит промежуточным слоем для определения бизнес-логики (метрик, измерений, связей), не нова. Она уже много лет используется в BI-системах для обеспечения согласованности отчетов. Однако с появлением больших языковых моделей (LLM) и инструментов в стиле “Chat with your data” проблема вышла на новый уровень.<\/p>\n<p>Когда AI-агент или LLM пытается ответить на вопрос, обращаясь напрямую к базе данных, он вынужден самостоятельно генерировать SQL-запрос. При этом модель “угадывает”, какие таблицы нужно соединить (`JOIN`), как правильно отфильтровать данные, какую использовать гранулярность по времени и какие оконные функции применить.<\/p>\n<p><b>Проблемы такого подхода:<\/b><\/p>\n<ol start=\"1\">\n<li><b>Несогласованность:<\/b> Две разные модели (или даже одна и та же, но с другим запросом) могут сгенерировать разный SQL для расчета, казалось бы, одной и той же метрики. Это приводит к разным цифрам в отчетах.<\/li>\n<li><b>Ошибки:<\/b> LLM может не знать о тонкостях бизнес-логики, например, о том, что при расчете выручки нужно учитывать возвраты или использовать специальный финансовый календарь.<\/li>\n<li><b>Потеря доверия:<\/b> Когда пользователи получают противоречивые или неверные данные, доверие ко всей системе аналитики быстро падает.<\/li>\n<\/ol>\n<blockquote>\n<p>Метрики не должны быть вероятностными, зависящими от “догадок” LLM при каждом вызове. <b>Они должны быть детерминированными.<\/b><\/p>\n<\/blockquote>\n<p>`MetricFlow` решает именно эту задачу.<\/p>\n<h3>Что такое MetricFlow и как он работает<\/h3>\n<p>`MetricFlow` — это движок, который преобразует семантические определения бизнес-понятий в готовый к выполнению и оптимизированный SQL-код. Аналитик один раз определяет метрику “Валовая маржа” на языке `MetricFlow`, и после этого любая система (BI-инструмент, AI-агент, Python-скрипт) может запросить эту метрику по имени, будучи уверенной, что получит корректный и одинаковый результат.<\/p>\n<h3>Ключевые изменения и их значение<\/h3>\n<ol start=\"1\">\n<li><b>Лицензия Apache 2.0:<\/b> Это одно из главных нововведений. Apache 2.0 — это разрешительная лицензия, которая позволяет другим компаниям свободно встраивать `MetricFlow` в свои коммерческие и открытые продукты. Это снимает барьеры для принятия технологии и способствует ее распространению как стандарта.<\/li>\n<li><b>Сотрудничество с Open Semantic Interchange (OSI):<\/b> dbt Labs будет развивать `MetricFlow` совместно с такими партнерами, как Snowflake и Salesforce, в рамках инициативы OSI. Цель — создать единый стандарт для семантической совместимости между разными платформами, чтобы метрики, определенные один раз, одинаково работали во всех инструментах.<\/li>\n<\/ol>\n<h3>Как MetricFlow обеспечивает надежность AI<\/h3>\n<p>`MetricFlow` предоставляет открытый стандарт для метаданных и расширяемый движок, который превращает намерение (“покажи валовую маржу”) в SQL-запрос для хранилища данных.<\/p>\n<p><b>Пример работы:<\/b><\/p>\n<p>Предположим, пользователь задает AI-агенту вопрос:<\/p>\n<blockquote>\n<p>“Покажи валовую маржу (%) по месяцам за прошлый квартал для Северной Америки (за вычетом скидок и возвратов, по финансовому календарю).”<\/p>\n<\/blockquote>\n<p>Без семантического слоя LLM пришлось бы конструировать сложный запрос с нуля. С `MetricFlow` процесс выглядит так:<\/p>\n<ol start=\"1\">\n<li>Агент распознает намерение и запрашивает у `MetricFlow` метрику `gross_margin_pct` с нужными измерениями (`region`, `fiscal_month`) и фильтрами.<\/li>\n<li>`MetricFlow`, на основе заранее созданных определений, строит план запроса:\n<ul>\n  <li>Находит нужные таблицы: `orders`, `discounts`, `returns`, `cogs` (себестоимость).<\/li>\n  <li>Применяет правильные `JOIN` между ними.<\/li>\n  <li>Применяет фильтр по региону (`North America`).<\/li>\n  <li>Группирует данные по месяцам финансового, а не календарного, года.<\/li>\n  <li>Рассчитывает числитель (выручка) и знаменатель (себестоимость) с учетом того, что популяция данных для них должна быть одинаковой.<\/li>\n  <li>Вычисляет итоговое соотношение.<\/li>\n<\/ul>\n<\/li>\n<li>`MetricFlow` компилирует этот план в оптимизированный SQL-запрос, специфичный для диалекта конкретного хранилища (Snowflake, BigQuery, Databricks и т.д.).<\/li>\n<li>Запрос выполняется в хранилище, и результат возвращается пользователю.<\/li>\n<\/ol>\n<p>При этом весь сгенерированный SQL доступен для проверки, что обеспечивает <b>прозрачность и объяснимость<\/b> вычислений.<\/p>\n<h3>Основные возможности движка:<\/h3>\n<ul>\n<li><b>Единое определение, выполнение где угодно:<\/b> Метрики и измерения определяются один раз, а `MetricFlow` компилирует их в SQL для разных диалектов.<\/li>\n<li><b>Оптимизация производительности:<\/b> Движок строит эффективные запросы, чтобы избежать лишних сканирований и снизить нагрузку на хранилище данных.<\/li>\n<li><b>Поддержка сложных вычислений:<\/b> `MetricFlow` из коробки обрабатывает сложные соединения, оконные функции, расчеты по когортам и полуаддитивные метрики (например, остатки на счетах, которые нельзя просто суммировать по времени).<\/li>\n<\/ul>\n<h3>`MetricFlow` vs. `dbt Semantic Layer`<\/h3>\n<p>Важно понимать различие между двумя компонентами:<\/p>\n<ul>\n<li><b>`MetricFlow`<\/b> — это движок с открытым исходным кодом для <b>определения и вычисления<\/b> метрик. Это “сердце” системы, которое выполняет всю сложную работу по генерации SQL.<\/li>\n<li><b>`dbt Semantic Layer`<\/b> — это коммерческий продукт dbt Labs, построенный *поверх* `MetricFlow`. Он добавляет функциональность корпоративного уровня:\n<ul>\n  <li>Управление доступом (`RBAC`).<\/li>\n  <li>Версионирование определений метрик.<\/li>\n  <li>Аудит и отслеживание происхождения данных (`lineage`).<\/li>\n  <li>Надежные API и коннекторы для интеграции с BI- и AI-инструментами.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Таким образом, `MetricFlow` становится общедоступным строительным блоком, а `dbt Semantic Layer` — готовым решением для его безопасного и управляемого внедрения в компаниях.<\/p>\n<h3>Итог<\/h3>\n<ol start=\"1\">\n<li><b>dbt Labs сделала `MetricFlow` (движок для расчета метрик) полностью открытым под лицензией Apache 2.0.<\/b> Это позволяет всем желающим использовать его без ограничений.<\/li>\n<li><b>Главная цель — создать открытый стандарт для определения бизнес-метрик.<\/b> Это особенно актуально для AI-систем, которые часто ошибаются при самостоятельной генерации SQL.<\/li>\n<li><b>`MetricFlow` позволяет AI и BI-инструментам запрашивать данные по имени метрики (например, `revenue`), получая детерминированный и корректный SQL-запрос.<\/b> Это повышает надежность и согласованность данных.<\/li>\n<li><b>Этот шаг способствует совместимости инструментов (`interoperability`) и снижает зависимость от конкретного вендора (`vendor lock-in`).<\/b> Метрики, определенные один раз, будут работать одинаково в разных системах.<\/li>\n<li><b>Коммерческий продукт `dbt Semantic Layer` продолжит развиваться<\/b> как решение для управления жизненным циклом метрик в корпоративной среде (безопасность, контроль версий, аудит).<\/li>\n<\/ol>\n",
            "date_published": "2025-11-01T01:03:55+03:00",
            "date_modified": "2025-11-01T01:04:30+03:00",
            "tags": [
                "Data",
                "Data Engineer",
                "dbt",
                "ETL"
            ],
            "_date_published_rfc2822": "Sat, 01 Nov 2025 01:03:55 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "292",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "272",
            "url": "https:\/\/gavrilov.info\/all\/novaya-era-transformacii-dannyh-dbt-protiv-bruin-i-aac\/",
            "title": "Новая эра трансформации данных: dbt против Bruin и aaC",
            "content_html": "<p>В мире данных произошла тихая, но фундаментальная революция. На смену традиционному подходу <b>ETL (Extract, Transform, Load)<\/b>, где данные преобразовывались до загрузки в хранилище, пришла новая парадигма — <b>ELT (Extract, Load, Transform)<\/b>. Благодаря мощности современных облачных хранилищ (таких как Snowflake, BigQuery, Databricks, Starburst\\Trino) стало выгоднее сначала загружать сырые данные, а уже затем трансформировать их непосредственно в хранилище.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/gavrilov.info\/pictures\/demo.gif\" width=\"1200\" height=\"900\" alt=\"\" \/>\n<\/div>\n<p>Этот сдвиг породил потребность в инструментах, которые специализируются на последнем шаге — трансформации (T). Именно в этой нише dbt (data build tool) стал безоговорочным лидером, но на его поле появляются и новые сильные игроки, такие как Bruin. Давайте разберемся, что это за инструменты, какой подход они олицетворяют и в чем их ключевые различия.<\/p>\n<h4>Подход «Аналитика как код»<\/h4>\n<p>И dbt, и Bruin являются яркими представителями движения <b>“Analytics as Code”<\/b> (аналитика как код). Это не просто инструменты, а целая философия, которая переносит лучшие практики разработки программного обеспечения в мир аналитики данных.<\/p>\n<p><b>Основные принципы и идеи:<\/b><\/p>\n<ol start=\"1\">\n<li><b>Версионирование:<\/b> Все трансформации данных описываются в виде кода (в основном SQL), который хранится в системе контроля версий, такой как Git. Это позволяет отслеживать изменения, совместно работать и откатываться к предыдущим версиям.<\/li>\n<li><b>Модульность и переиспользование (DRY – Don’t Repeat Yourself):<\/b> Сложные трансформации разбиваются на небольшие, логически завершенные модели, которые могут ссылаться друг на друга. Это делает код чище, понятнее и позволяет повторно использовать уже написанную логику.<\/li>\n<li><b>Тестирование:<\/b> Код трансформаций должен быть протестирован. Инструменты позволяют автоматически проверять качество данных после преобразований: на уникальность ключей, отсутствие `NULL` значений, соответствие заданным условиям и т.д.<\/li>\n<li><b>Документация и прозрачность:<\/b> Процесс трансформации становится самодокументируемым. Инструменты могут автоматически генерировать документацию и строить графы зависимостей моделей (data lineage), показывая, как данные текут и преобразуются от источника к конечному виду. <a href=\"https:\/\/www.element61.be\/en\/resource\/when-use-dbt-or-delta-live-tables\">element61.be<\/a><\/li>\n<li><b>CI\/CD (Continuous Integration \/ Continuous Deployment):<\/b> Изменения в коде трансформаций могут автоматически тестироваться и разворачиваться в продуктивную среду, что значительно ускоряет циклы разработки.<\/li>\n<\/ol>\n<p><b>Решаемые проблемы:<\/b><\/p>\n<ul>\n<li><b>“Черные ящики” ETL:<\/b> Заменяют сложные, трудноподдерживаемые и непрозрачные ETL-процессы на понятный и документированный код.<\/li>\n<li><b>Рассинхронизация команд:<\/b> Стирают границы между инженерами данных и аналитиками, позволяя аналитикам, владеющим SQL, самостоятельно создавать надежные модели данных.<\/li>\n<li><b>Низкое качество данных:<\/b> Встроенные механизмы тестирования помогают обеспечить надежность и согласованность данных.<\/li>\n<\/ul>\n<p>---<\/p>\n<h4>dbt (data build tool): Золотой стандарт трансформации<\/h4>\n<p><b>dbt<\/b> — это инструмент с открытым исходным кодом, который позволяет аналитикам и инженерам трансформировать данные в их хранилищах с помощью простых SQL-запросов. Важно понимать, что dbt <b>не извлекает и не загружает данные<\/b>. Он специализируется исключительно на шаге <b>“T”<\/b> в ELT  <a href=\"https:\/\/vutr.substack.com\/p\/why-is-dbt-so-popular\">vutr.substack.com<\/a>. <a href=\"https:\/\/github.com\/dbt-labs\/dbt-core\">dbt git<\/a>.<\/p>\n<p>Он работает как компилятор и исполнитель: вы пишете модели данных в `.sql` файлах, используя шаблонизатор Jinja для добавления логики (циклы, условия, макросы). Затем dbt компилирует этот код в чистый SQL и выполняет его в вашем хранилище данных <a href=\"https:\/\/www.element61.be\/en\/resource\/when-use-dbt-or-delta-live-tables\">element61.be<\/a>.<\/p>\n<h5>Плюсы dbt<\/h5>\n<ul>\n<li><b>Огромное сообщество и экосистема:<\/b> dbt стал де-факто стандартом индустрии. Существует огромное количество статей, курсов, готовых пакетов (библиотек) и экспертов.<\/li>\n<li><b>Фокус на SQL:<\/b> Низкий порог входа для аналитиков, которые уже знают SQL. Это демократизирует процесс трансформации данных.<\/li>\n<li><b>Мощное тестирование и документирование:<\/b> Встроенные команды для тестирования данных и автоматической генерации проектной документации с графом зависимостей.<\/li>\n<li><b>Зрелость и надежность:<\/b> Инструмент проверен временем и используется тысячами компаний по всему миру.<\/li>\n<li><b>Гибкость:<\/b> Благодаря шаблонизатору Jinja можно создавать очень сложные и переиспользуемые макросы, адаптируя dbt под любые нужды.<\/li>\n<\/ul>\n<h5>Минусы dbt<\/h5>\n<ul>\n<li><b>Только трансформация:<\/b> dbt не занимается извлечением (E) и загрузкой (L). Для этого вам понадобятся отдельные инструменты (например, Fivetran, Airbyte), что усложняет стек технологий.<\/li>\n<li><b>Кривая обучения:<\/b> Хотя основы просты, освоение продвинутых возможностей Jinja, макросов и структуры проекта требует времени.<\/li>\n<li><b>Зависимость от Python-моделей:<\/b> Хотя недавно появилась поддержка моделей на Python, она все еще не так нативна и проста, как основной SQL-подход, и требует дополнительных настроек.<\/li>\n<\/ul>\n<p>---<\/p>\n<h4>Bruin Data: Универсальный боец<\/h4>\n<p><b>Bruin<\/b> — это более новый игрок на рынке, который позиционирует себя как инструмент для создания “end-to-end” пайплайнов данных. В отличие от dbt, он не ограничивается только трансформацией, а стремится охватить больше этапов работы с данными, включая их загрузку (ingestion) <a href=\"https:\/\/github.com\/bruin-data\/bruin\">https:\/\/github.com\/bruin-data\/bruin<\/a>.<\/p>\n<p>Bruin разделяет ту же философию “Analytics as Code”, но предлагает более интегрированный опыт, где SQL и Python являются равноправными гражданами.<\/p>\n<h5>Плюсы Bruin<\/h5>\n<ul>\n<li><b>Универсальность:<\/b> Один инструмент для определения всего пайплайна: от загрузки из источников до финальных витрин данных. Это может упростить стек технологий.<\/li>\n<li><b>Нативная поддержка SQL и Python:<\/b> Позволяет легко комбинировать задачи на разных языках в одном пайплайне без дополнительных настроек. Это идеально для задач, где чистый SQL громоздок (например, работа с API, машинное обучение).<\/li>\n<li><b>Простота конфигурации:<\/b> Зачастую требует меньше шаблонного кода (boilerplate) для определения ассетов и пайплайнов по сравнению с dbt.<\/li>\n<li><b>Встроенное качество данных:<\/b> Как и dbt, делает акцент на проверках качества на каждом шаге.<\/li>\n<\/ul>\n<h5>Минусы Bruin<\/h5>\n<ul>\n<li><b> Пока маленькое сообщество:<\/b> Как у нового инструмента, у Bruin гораздо меньше пользователей, готовых решений и обсуждений на форумах по сравнению с dbt. Найти помощь или готовый пакет для решения специфической задачи сложнее.<\/li>\n<li><b>Незрелость:<\/b> Инструмент моложе, а значит, наверное, потенциально менее стабилен и может иметь меньше интеграций по сравнению с проверенным dbt. Пока нет облачных функция за деньги. Я так думал, но все же есть <a href=\"https:\/\/getbruin.com.\">https:\/\/getbruin.com.<\/a><\/li>\n<li><b>“Мастер на все руки — эксперт ни в чем?”:<\/b> Стремление охватить все этапы (E, L, T) может означать, что в каждом отдельном компоненте Bruin может уступать лучшим в своем классе специализированным инструментам (например, Fivetran в загрузке, dbt в трансформации), но это конечно субъективно.<\/li>\n<\/ul>\n<h4>Сводное сравнение<\/h4>\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"e2-text-table\">\n<tr>\n<td style=\"text-align: center\">Характеристика<\/td>\n<td style=\"text-align: center\">dbt (data build tool)<\/td>\n<td style=\"text-align: center\">Bruin Data<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\"><b>Основная задача<\/b><\/td>\n<td style=\"text-align: center\">Трансформация (T в ELT)<\/td>\n<td style=\"text-align: center\">Весь пайплайн (E, L, T)<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\"><b>Ключевые языки<\/b><\/td>\n<td style=\"text-align: center\">SQL с шаблонизатором Jinja<\/td>\n<td style=\"text-align: center\">SQL и Python как равноправные<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\"><b>Экосистема<\/b><\/td>\n<td style=\"text-align: center\">Огромная, стандарт индустрии<\/td>\n<td style=\"text-align: center\">Маленькая, развивающаяся<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\"><b>Зрелость<\/b><\/td>\n<td style=\"text-align: center\">Высокая, проверен временем<\/td>\n<td style=\"text-align: center\">Низкая\/Средняя<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\"><b>Стек инструментов<\/b><\/td>\n<td style=\"text-align: center\">Требует отдельных E\/L инструментов<\/td>\n<td style=\"text-align: center\">Стремится быть самодостаточным<\/td>\n<\/tr>\n<\/table>\n<h4>Итого<\/h4>\n<p>Выбор между dbt и Bruin — это выбор между двумя стратегиями построения современного стека данных.<\/p>\n<p><b>Выбирайте dbt, если:<\/b><\/p>\n<ul>\n<li>Вы строите гибкий стек из лучших в своем классе инструментов (“best-of-breed”): один для загрузки, другой для хранения, третий для трансформации.<\/li>\n<li>Ваша команда в основном состоит из аналитиков, сильных в SQL.<\/li>\n<li>Для вас критически важны поддержка сообщества, стабильность и наличие готовых решений.<\/li>\n<li>Вы работаете в большой организации, где принятие отраслевых стандартов является преимуществом.<\/li>\n<li>Вы готовы переехать к ним в платное облако, когда нибудь. Большая часть функционала доступна там.<\/li>\n<\/ul>\n<p><b>Выбирайте Bruin, если:<\/b><\/p>\n<ul>\n<li>Вы предпочитаете единый, интегрированный инструмент для управления всеми пайплайнами, чтобы упростить архитектуру<\/li>\n<li>Вы любите open source и End-to-end дата framework: фор data ingestion + transformations + кволити. :)<\/li>\n<li>Ваши пайплайны требуют тесной связки SQL и Python для трансформаций (например, обогащение данных через вызовы API или модели ML).<\/li>\n<li>Вы начинаете новый проект или работаете в небольшой команде и цените скорость настройки и меньшее количество движущихся частей.<\/li>\n<li>Вы Go’шник :) –  Bruin написан на Go почти на 100%.<\/li>\n<\/ul>\n<p>И dbt, и Bruin — мощные инструменты, воплощающие современные подходы к инженерии данных. dbt предлагает проверенный, сфокусированный и невероятно мощный движок для трансформаций, ставший стандартом. Bruin же предлагает более универсальный и интегрированный подход, который может быть привлекателен для команд, стремящихся к простоте и нативной поддержке Python.<\/p>\n<h4>А что такое “Аналитика как код” (Analytics as Code, AaC)?<\/h4>\n<p><b>Аналитика как код<\/b> — это подход к управлению аналитическими процессами, при котором все компоненты аналитики — от моделей данных и метрик до отчетов и правил доступа — определяются в виде кода в человекочитаемых файлах. Эти файлы затем управляются так же, как исходный код любого другого программного обеспечения: с помощью систем контроля версий, автоматизированного тестирования и развертывания <a href=\"https:\/\/medium.com\/gooddata-developers\/analytics-as-code-managing-analytics-solutions-like-any-other-software-504372ba6a61\">medium.com<\/a>.<\/p>\n<p>Самая близкая и известная аналогия — это <b>Infrastructure as Code (IaC)<\/b>. Как IaC (например, с помощью Terraform) позволил инженерам описывать серверы, сети и базы данных в коде вместо ручной настройки через веб-интерфейсы, так и AaC позволяет описывать в коде всё, что связано с данными <a href=\"https:\/\/medium.com\/@terezacihelkova\/analytics-as-code-what-is-it-and-how-does-it-help-you-93e9a3c179ee\">medium.com<\/a>.<\/p>\n<blockquote>\n<p>Идея проста и убедительна: “настройте свои системы один раз, выразите это в виде кода, а затем поместите в систему контроля версий” <a href=\"https:\/\/www.holistics.io\/blog\/analytics-as-code\/\">holistics.io<\/a>.<\/p>\n<\/blockquote>\n<h4>Проблема: Как было раньше?<\/h4>\n<p>Чтобы понять ценность AaC, нужно посмотреть на проблемы, которые он решает. В традиционном подходе аналитика часто была разрозненной и хрупкой:<\/p>\n<ul>\n<li><b>Логика в “черных ящиках”:<\/b> Сложные преобразования данных были скрыты внутри GUI-интерфейсов старых ETL-инструментов или непосредственно в настройках BI-платформы (например, Tableau, Power BI). Никто, кроме автора, не мог легко понять, как рассчитывается та или иная метрика.<\/li>\n<li><b>Разрозненные SQL-скрипты:<\/b> Аналитики хранили важные SQL-запросы на своих локальных машинах, в общих папках или на wiki-страницах. Не было единой версии правды, код дублировался и быстро устаревал.<\/li>\n<li><b>Отсутствие контроля версий:<\/b> Невозможно было отследить, кто, когда и почему изменил логику расчета ключевого показателя. Откат к предыдущей работающей версии был настоящей головной болью.<\/li>\n<li><b>“Ручное” тестирование:<\/b> Проверка качества данных после изменений была ручным, подверженным ошибкам процессом. Часто о проблемах узнавали уже от бизнес-пользователей, которые видели неверные цифры в отчетах.<\/li>\n<li><b>Рассинхронизация:<\/b> Инженеры данных готовили сырые таблицы, а аналитики строили свою логику поверх них. Любые изменения с одной стороны могли сломать всю цепочку, не будучи замеченными вовремя.<\/li>\n<\/ul>\n<p>Этот хаос приводил к главному — <b>недоверию к данным<\/b>. Никто не мог быть уверен, что цифры в дашборде верны.<\/p>\n<h4>Ключевые принципы “Аналитики как код”<\/h4>\n<p>AaC решает эти проблемы, внедряя практики из мира разработки ПО.<\/p>\n<ol start=\"1\">\n<li><b>Декларативное определение:<\/b> Все аналитические артефакты описываются в файлах.\n<ul>\n  <li>Модели данных:** `SELECT * FROM ...` в `.sql` файлах.<\/li>\n  <li>Тесты:** `not_null`, `unique` в `.yml` файлах.<\/li>\n  <li>Документация:** Описания таблиц и полей в `.yml` файлах.<\/li>\n  <li>Метрики и дашборды:** Определения в `.yml` или специализированных файлах <a href=\"https:\/\/medium.com\/gooddata-developers\/analytics-as-code-managing-analytics-solutions-like-any-other-software-504372ba6a61\">medium.com<\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol start=\"2\">\n<li><b>Контроль версий (Git):<\/b> Весь код хранится в репозитории (например, на GitHub или GitLab).\n<ul>\n  <li>Прозрачность:** Каждое изменение — это `commit` с понятным описанием.<\/li>\n  <li>Совместная работа:** Аналитики работают в отдельных ветках, а изменения вносятся через `Pull Request` (или `Merge Request`), что позволяет проводить ревью кода (code review).<\/li>\n  <li>Восстанавливаемость:** Если что-то пошло не так, можно легко откатиться к предыдущей версии.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol start=\"3\">\n<li><b>Автоматизированное тестирование:<\/b> Тесты являются неотъемлемой частью кода. Они запускаются автоматически при каждом изменении, чтобы гарантировать, что данные по-прежнему соответствуют ожиданиям (например, `user_id` всегда уникален и не равен `NULL`).<\/li>\n<\/ol>\n<ol start=\"4\">\n<li><b>CI\/CD (Непрерывная интеграция и развертывание):<\/b> Процессы полностью автоматизированы.\n<ul>\n  <li>Когда аналитик вносит изменения в `Pull Request`, автоматически запускаются тесты.<\/li>\n  <li>После одобрения и слияния ветки изменения автоматически развертываются в продуктивной среде (например, dbt Cloud или Jenkins запускает команду `dbt run`).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol start=\"5\">\n<li><b>Модульность и переиспользование (DRY – Don’t Repeat Yourself):<\/b> Сложные потоки данных разбиваются на небольшие, логичные и переиспользуемые модели. Одна модель может ссылаться на другую, создавая четкий граф зависимостей (lineage), который можно визуализировать.<\/li>\n<\/ol>\n<h4>Преимущества подхода AaC<\/h4>\n<p>Принятие этой философии дает компании ощутимые выгоды:<\/p>\n<ul>\n<li><b>Надежность и доверие:<\/b> Благодаря автоматическому тестированию и ревью кода значительно повышается качество данных, а вместе с ним и доверие бизнеса к аналитике.<\/li>\n<li><b>Скорость и гибкость:<\/b> Аналитики могут вносить изменения гораздо быстрее. Цикл от идеи до готового отчета сокращается с недель до дней или даже часов.<\/li>\n<li><b>Масштабируемость:<\/b> Кодовая база легко поддерживается и расширяется. Новые члены команды могут быстро разобраться в проекте благодаря документации и прозрачности.<\/li>\n<li><b>Прозрачность и обнаруживаемость:<\/b> Автоматически сгенерированная документация и графы зависимостей позволяют любому сотруднику понять, откуда берутся данные и как они рассчитываются.<\/li>\n<li><b>Демократизация:<\/b> AaC дает возможность аналитикам, владеющим SQL, самостоятельно создавать надежные и протестированные модели данных, не дожидаясь инженеров данных. Это стирает барьеры между командами.<\/li>\n<\/ul>\n<p>В конечном итоге, “Аналитика как код” — это культурный сдвиг, который превращает аналитику из ремесленного занятия в зрелую инженерную дисциплину, обеспечивая скорость, надежность и масштабируемость, необходимые современному бизнесу.<\/p>\n",
            "date_published": "2025-08-23T16:04:02+03:00",
            "date_modified": "2025-08-24T11:51:29+03:00",
            "tags": [
                "BI",
                "Data Engineer",
                "Data Quality",
                "dbt",
                "ETL"
            ],
            "image": "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2025-08-23-v-15.37.26.png",
            "_date_published_rfc2822": "Sat, 23 Aug 2025 16:04:02 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "272",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2025-08-23-v-15.37.26.png",
                    "https:\/\/gavrilov.info\/pictures\/demo.gif"
                ]
            }
        }
    ],
    "_e2_version": 4171,
    "_e2_ua_string": "Aegea 11.4 (v4171e)"
}