[{"data":1,"prerenderedAt":3104},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fru\u002Fdata\u002Fdbt-bigquery-sovremenniy-marketing-data-stack":13},{"i18nKey":4,"paths":5},"data-002-2026-06",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Fdata\u002Fdbt-bigquery-moderner-marketing-data-stack","\u002Fen\u002Fdata\u002Fdbt-bigquery-modern-marketing-data-stack","\u002Fes\u002Fdata\u002Fdbt-bigquery-modern-marketing-data-stack","\u002Ffr\u002Fdata\u002Fdbt-bigquery-modern-marketing-data-stack","\u002Fit\u002Fdata\u002Fdbt-bigquery-modern-pazarlama-data-stack","\u002Fru\u002Fdata\u002Fdbt-bigquery-sovremenniy-marketing-data-stack","\u002Ftr\u002Fdata\u002Fdbt-bigquery-ile-modern-pazarlama-data-stack",{"_path":11,"_dir":14,"_draft":15,"_partial":15,"_locale":16,"title":17,"description":18,"publishedAt":19,"modifiedAt":19,"category":14,"i18nKey":4,"tags":20,"readingTime":26,"author":27,"body":28,"_type":3098,"_id":3099,"_source":3100,"_file":3101,"_stem":3102,"_extension":3103},"data",false,"","dbt + BigQuery: Современный маркетинговый data stack","От source mapping к semantic layer: как превратить маркетинговые данные в основу решений? Слой моделирования dbt, определение exposures и production-grade архитектура pipeline.","2026-06-14",[21,22,23,24,25],"dbt","bigquery","data-modeling","semantic-layer","marketing-analytics",8,"Roibase",{"type":29,"children":30,"toc":3089},"root",[31,39,46,84,350,379,400,406,418,701,714,1043,1102,1108,1120,1483,1488,1520,1526,1546,1750,1770,1783,1890,1895,1901,1914,2191,2204,2217,2479,2498,2504,2509,2762,2767,2780,2954,2959,2965,2970,2975,2980,3083],{"type":32,"tag":33,"props":34,"children":35},"element","p",{},[36],{"type":37,"value":38},"text","Маркетинговые команды в 2026 году принимают решения на основе данных, а не борются с ними. GA4, Meta Ads, Google Ads, CRM, CDP, server-side GTM — всё это падает в разные таблицы. Команда вручную объединяет информацию в электронных таблицах, цифры меняются каждую неделю, никто не доверяет результатам. Этот хаос исчезает с современным data stack'ом: BigQuery как источник, слой трансформации dbt, семантический слой как граф метрик. Вы версионируете код в репозитории, каждое изменение проходит тесты, метрики берутся из единого источника истины. Эта статья показывает, как комбинация dbt + BigQuery превращает маркетинговый pipeline в production-grade систему.",{"type":32,"tag":40,"props":41,"children":43},"h2",{"id":42},"source-mapping-стандартизация-сырых-данных",[44],{"type":37,"value":45},"Source mapping: стандартизация сырых данных",{"type":32,"tag":33,"props":47,"children":48},{},[49,51,58,60,66,68,74,76,82],{"type":37,"value":50},"Первая задача dbt — source mapping, приведение сырых данных из разных систем к единой схеме. В BigQuery таблица ",{"type":32,"tag":52,"props":53,"children":55},"code",{"className":54},[],[56],{"type":37,"value":57},"analytics_123456.events_*",{"type":37,"value":59}," приходит из GA4, ",{"type":32,"tag":52,"props":61,"children":63},{"className":62},[],[64],{"type":37,"value":65},"facebook_ads.ads_insights",{"type":37,"value":67}," из Meta API, ",{"type":32,"tag":52,"props":69,"children":71},{"className":70},[],[72],{"type":37,"value":73},"crm.transactions",{"type":37,"value":75}," из Shopify. Каждый источник имеет свой формат timestamp'а, разные идентификаторы пользователей, разные названия колонок валюты. Вы определяете эти сырые таблицы в ",{"type":32,"tag":52,"props":77,"children":79},{"className":78},[],[80],{"type":37,"value":81},"sources.yml",{"type":37,"value":83},":",{"type":32,"tag":85,"props":86,"children":90},"pre",{"className":87,"code":88,"language":89,"meta":16,"style":16},"language-yaml shiki shiki-themes github-dark","version: 2\nsources:\n  - name: ga4\n    database: analytics_123456\n    tables:\n      - name: events_\n        identifier: \"events_*\"\n        loaded_at_field: event_timestamp\n  - name: meta_ads\n    database: facebook_ads\n    schema: public\n    tables:\n      - name: ads_insights\n        loaded_at_field: date_start\n","yaml",[91],{"type":32,"tag":52,"props":92,"children":93},{"__ignoreMap":16},[94,118,132,156,174,187,209,227,244,265,282,300,312,333],{"type":32,"tag":95,"props":96,"children":99},"span",{"class":97,"line":98},"line",1,[100,106,112],{"type":32,"tag":95,"props":101,"children":103},{"style":102},"--shiki-default:#85E89D",[104],{"type":37,"value":105},"version",{"type":32,"tag":95,"props":107,"children":109},{"style":108},"--shiki-default:#E1E4E8",[110],{"type":37,"value":111},": ",{"type":32,"tag":95,"props":113,"children":115},{"style":114},"--shiki-default:#79B8FF",[116],{"type":37,"value":117},"2\n",{"type":32,"tag":95,"props":119,"children":121},{"class":97,"line":120},2,[122,127],{"type":32,"tag":95,"props":123,"children":124},{"style":102},[125],{"type":37,"value":126},"sources",{"type":32,"tag":95,"props":128,"children":129},{"style":108},[130],{"type":37,"value":131},":\n",{"type":32,"tag":95,"props":133,"children":135},{"class":97,"line":134},3,[136,141,146,150],{"type":32,"tag":95,"props":137,"children":138},{"style":108},[139],{"type":37,"value":140},"  - ",{"type":32,"tag":95,"props":142,"children":143},{"style":102},[144],{"type":37,"value":145},"name",{"type":32,"tag":95,"props":147,"children":148},{"style":108},[149],{"type":37,"value":111},{"type":32,"tag":95,"props":151,"children":153},{"style":152},"--shiki-default:#9ECBFF",[154],{"type":37,"value":155},"ga4\n",{"type":32,"tag":95,"props":157,"children":159},{"class":97,"line":158},4,[160,165,169],{"type":32,"tag":95,"props":161,"children":162},{"style":102},[163],{"type":37,"value":164},"    database",{"type":32,"tag":95,"props":166,"children":167},{"style":108},[168],{"type":37,"value":111},{"type":32,"tag":95,"props":170,"children":171},{"style":152},[172],{"type":37,"value":173},"analytics_123456\n",{"type":32,"tag":95,"props":175,"children":177},{"class":97,"line":176},5,[178,183],{"type":32,"tag":95,"props":179,"children":180},{"style":102},[181],{"type":37,"value":182},"    tables",{"type":32,"tag":95,"props":184,"children":185},{"style":108},[186],{"type":37,"value":131},{"type":32,"tag":95,"props":188,"children":190},{"class":97,"line":189},6,[191,196,200,204],{"type":32,"tag":95,"props":192,"children":193},{"style":108},[194],{"type":37,"value":195},"      - ",{"type":32,"tag":95,"props":197,"children":198},{"style":102},[199],{"type":37,"value":145},{"type":32,"tag":95,"props":201,"children":202},{"style":108},[203],{"type":37,"value":111},{"type":32,"tag":95,"props":205,"children":206},{"style":152},[207],{"type":37,"value":208},"events_\n",{"type":32,"tag":95,"props":210,"children":212},{"class":97,"line":211},7,[213,218,222],{"type":32,"tag":95,"props":214,"children":215},{"style":102},[216],{"type":37,"value":217},"        identifier",{"type":32,"tag":95,"props":219,"children":220},{"style":108},[221],{"type":37,"value":111},{"type":32,"tag":95,"props":223,"children":224},{"style":152},[225],{"type":37,"value":226},"\"events_*\"\n",{"type":32,"tag":95,"props":228,"children":229},{"class":97,"line":26},[230,235,239],{"type":32,"tag":95,"props":231,"children":232},{"style":102},[233],{"type":37,"value":234},"        loaded_at_field",{"type":32,"tag":95,"props":236,"children":237},{"style":108},[238],{"type":37,"value":111},{"type":32,"tag":95,"props":240,"children":241},{"style":152},[242],{"type":37,"value":243},"event_timestamp\n",{"type":32,"tag":95,"props":245,"children":247},{"class":97,"line":246},9,[248,252,256,260],{"type":32,"tag":95,"props":249,"children":250},{"style":108},[251],{"type":37,"value":140},{"type":32,"tag":95,"props":253,"children":254},{"style":102},[255],{"type":37,"value":145},{"type":32,"tag":95,"props":257,"children":258},{"style":108},[259],{"type":37,"value":111},{"type":32,"tag":95,"props":261,"children":262},{"style":152},[263],{"type":37,"value":264},"meta_ads\n",{"type":32,"tag":95,"props":266,"children":268},{"class":97,"line":267},10,[269,273,277],{"type":32,"tag":95,"props":270,"children":271},{"style":102},[272],{"type":37,"value":164},{"type":32,"tag":95,"props":274,"children":275},{"style":108},[276],{"type":37,"value":111},{"type":32,"tag":95,"props":278,"children":279},{"style":152},[280],{"type":37,"value":281},"facebook_ads\n",{"type":32,"tag":95,"props":283,"children":285},{"class":97,"line":284},11,[286,291,295],{"type":32,"tag":95,"props":287,"children":288},{"style":102},[289],{"type":37,"value":290},"    schema",{"type":32,"tag":95,"props":292,"children":293},{"style":108},[294],{"type":37,"value":111},{"type":32,"tag":95,"props":296,"children":297},{"style":152},[298],{"type":37,"value":299},"public\n",{"type":32,"tag":95,"props":301,"children":303},{"class":97,"line":302},12,[304,308],{"type":32,"tag":95,"props":305,"children":306},{"style":102},[307],{"type":37,"value":182},{"type":32,"tag":95,"props":309,"children":310},{"style":108},[311],{"type":37,"value":131},{"type":32,"tag":95,"props":313,"children":315},{"class":97,"line":314},13,[316,320,324,328],{"type":32,"tag":95,"props":317,"children":318},{"style":108},[319],{"type":37,"value":195},{"type":32,"tag":95,"props":321,"children":322},{"style":102},[323],{"type":37,"value":145},{"type":32,"tag":95,"props":325,"children":326},{"style":108},[327],{"type":37,"value":111},{"type":32,"tag":95,"props":329,"children":330},{"style":152},[331],{"type":37,"value":332},"ads_insights\n",{"type":32,"tag":95,"props":334,"children":336},{"class":97,"line":335},14,[337,341,345],{"type":32,"tag":95,"props":338,"children":339},{"style":102},[340],{"type":37,"value":234},{"type":32,"tag":95,"props":342,"children":343},{"style":108},[344],{"type":37,"value":111},{"type":32,"tag":95,"props":346,"children":347},{"style":152},[348],{"type":37,"value":349},"date_start\n",{"type":32,"tag":33,"props":351,"children":352},{},[353,355,361,363,369,371,377],{"type":37,"value":354},"Это определение говорит dbt: \"эти таблицы — upstream источник, я их не трогаю, но проверяю свежесть\". Команда ",{"type":32,"tag":52,"props":356,"children":358},{"className":357},[],[359],{"type":37,"value":360},"dbt source freshness",{"type":37,"value":362}," контролирует, когда последний раз пришли данные — если Meta API опаздывает, система отправляет алерт. Без source mapping вы пишете в каждой модели прямое обращение ",{"type":32,"tag":52,"props":364,"children":366},{"className":365},[],[367],{"type":37,"value":368},"SELECT * FROM analytics_123456.events_20260614",{"type":37,"value":370},", и при изменении названия таблицы ломаются 40 моделей. С mapping'ом ссылка становится ",{"type":32,"tag":52,"props":372,"children":374},{"className":373},[],[375],{"type":37,"value":376},"{{ source('ga4', 'events_') }}",{"type":37,"value":378},", изменение распространяется из одного места.",{"type":32,"tag":33,"props":380,"children":381},{},[382,384,390,392,398],{"type":37,"value":383},"GA4 использует Unix microsecond для event_timestamp, Meta Ads — ISO строки для date_start, CRM — UTC datetime для created_at. Source mapping нормализует это: в GA4 ",{"type":32,"tag":52,"props":385,"children":387},{"className":386},[],[388],{"type":37,"value":389},"TIMESTAMP_MICROS(event_timestamp) AS event_time",{"type":37,"value":391},", в Meta ",{"type":32,"tag":52,"props":393,"children":395},{"className":394},[],[396],{"type":37,"value":397},"PARSE_TIMESTAMP('%Y-%m-%d', date_start) AS event_time",{"type":37,"value":399},". Эта нормализация обеспечивает чистый входной сигнал для downstream моделей.",{"type":32,"tag":40,"props":401,"children":403},{"id":402},"слой-моделирования-staging-intermediate-mart",[404],{"type":37,"value":405},"Слой моделирования: staging, intermediate, mart",{"type":32,"tag":33,"props":407,"children":408},{},[409,411,417],{"type":37,"value":410},"Мощь dbt заключается в слоистом моделировании — staging, intermediate, mart слои. Staging модели берут данные 1:1 из источника, делают только переименование и приведение типов. ",{"type":32,"tag":52,"props":412,"children":414},{"className":413},[],[415],{"type":37,"value":416},"stg_ga4_events.sql",{"type":37,"value":83},{"type":32,"tag":85,"props":419,"children":423},{"className":420,"code":421,"language":422,"meta":16,"style":16},"language-sql shiki shiki-themes github-dark","SELECT\n  TIMESTAMP_MICROS(event_timestamp) AS event_time,\n  user_pseudo_id AS anonymous_id,\n  event_name,\n  (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'session_id') AS session_id,\n  geo.country,\n  device.category AS device_category\nFROM {{ source('ga4', 'events_') }}\nWHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY))\n  AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())\n","sql",[424],{"type":32,"tag":52,"props":425,"children":426},{"__ignoreMap":16},[427,436,454,471,479,551,573,600,633,680],{"type":32,"tag":95,"props":428,"children":429},{"class":97,"line":98},[430],{"type":32,"tag":95,"props":431,"children":433},{"style":432},"--shiki-default:#F97583",[434],{"type":37,"value":435},"SELECT\n",{"type":32,"tag":95,"props":437,"children":438},{"class":97,"line":120},[439,444,449],{"type":32,"tag":95,"props":440,"children":441},{"style":108},[442],{"type":37,"value":443},"  TIMESTAMP_MICROS(event_timestamp) ",{"type":32,"tag":95,"props":445,"children":446},{"style":432},[447],{"type":37,"value":448},"AS",{"type":32,"tag":95,"props":450,"children":451},{"style":108},[452],{"type":37,"value":453}," event_time,\n",{"type":32,"tag":95,"props":455,"children":456},{"class":97,"line":134},[457,462,466],{"type":32,"tag":95,"props":458,"children":459},{"style":108},[460],{"type":37,"value":461},"  user_pseudo_id ",{"type":32,"tag":95,"props":463,"children":464},{"style":432},[465],{"type":37,"value":448},{"type":32,"tag":95,"props":467,"children":468},{"style":108},[469],{"type":37,"value":470}," anonymous_id,\n",{"type":32,"tag":95,"props":472,"children":473},{"class":97,"line":158},[474],{"type":32,"tag":95,"props":475,"children":476},{"style":108},[477],{"type":37,"value":478},"  event_name,\n",{"type":32,"tag":95,"props":480,"children":481},{"class":97,"line":176},[482,487,492,497,502,507,512,517,522,527,532,537,542,546],{"type":32,"tag":95,"props":483,"children":484},{"style":108},[485],{"type":37,"value":486},"  (",{"type":32,"tag":95,"props":488,"children":489},{"style":432},[490],{"type":37,"value":491},"SELECT",{"type":32,"tag":95,"props":493,"children":494},{"style":114},[495],{"type":37,"value":496}," value",{"type":32,"tag":95,"props":498,"children":499},{"style":108},[500],{"type":37,"value":501},".",{"type":32,"tag":95,"props":503,"children":504},{"style":114},[505],{"type":37,"value":506},"string_value",{"type":32,"tag":95,"props":508,"children":509},{"style":432},[510],{"type":37,"value":511}," FROM",{"type":32,"tag":95,"props":513,"children":514},{"style":108},[515],{"type":37,"value":516}," UNNEST(event_params) ",{"type":32,"tag":95,"props":518,"children":519},{"style":432},[520],{"type":37,"value":521},"WHERE",{"type":32,"tag":95,"props":523,"children":524},{"style":432},[525],{"type":37,"value":526}," key",{"type":32,"tag":95,"props":528,"children":529},{"style":432},[530],{"type":37,"value":531}," =",{"type":32,"tag":95,"props":533,"children":534},{"style":152},[535],{"type":37,"value":536}," 'session_id'",{"type":32,"tag":95,"props":538,"children":539},{"style":108},[540],{"type":37,"value":541},") ",{"type":32,"tag":95,"props":543,"children":544},{"style":432},[545],{"type":37,"value":448},{"type":32,"tag":95,"props":547,"children":548},{"style":108},[549],{"type":37,"value":550}," session_id,\n",{"type":32,"tag":95,"props":552,"children":553},{"class":97,"line":189},[554,559,563,568],{"type":32,"tag":95,"props":555,"children":556},{"style":114},[557],{"type":37,"value":558},"  geo",{"type":32,"tag":95,"props":560,"children":561},{"style":108},[562],{"type":37,"value":501},{"type":32,"tag":95,"props":564,"children":565},{"style":114},[566],{"type":37,"value":567},"country",{"type":32,"tag":95,"props":569,"children":570},{"style":108},[571],{"type":37,"value":572},",\n",{"type":32,"tag":95,"props":574,"children":575},{"class":97,"line":211},[576,581,585,590,595],{"type":32,"tag":95,"props":577,"children":578},{"style":114},[579],{"type":37,"value":580},"  device",{"type":32,"tag":95,"props":582,"children":583},{"style":108},[584],{"type":37,"value":501},{"type":32,"tag":95,"props":586,"children":587},{"style":114},[588],{"type":37,"value":589},"category",{"type":32,"tag":95,"props":591,"children":592},{"style":432},[593],{"type":37,"value":594}," AS",{"type":32,"tag":95,"props":596,"children":597},{"style":108},[598],{"type":37,"value":599}," device_category\n",{"type":32,"tag":95,"props":601,"children":602},{"class":97,"line":26},[603,608,613,618,623,628],{"type":32,"tag":95,"props":604,"children":605},{"style":432},[606],{"type":37,"value":607},"FROM",{"type":32,"tag":95,"props":609,"children":610},{"style":108},[611],{"type":37,"value":612}," {{ source(",{"type":32,"tag":95,"props":614,"children":615},{"style":152},[616],{"type":37,"value":617},"'ga4'",{"type":32,"tag":95,"props":619,"children":620},{"style":108},[621],{"type":37,"value":622},", ",{"type":32,"tag":95,"props":624,"children":625},{"style":152},[626],{"type":37,"value":627},"'events_'",{"type":32,"tag":95,"props":629,"children":630},{"style":108},[631],{"type":37,"value":632},") }}\n",{"type":32,"tag":95,"props":634,"children":635},{"class":97,"line":246},[636,640,645,650,655,660,665,670,675],{"type":32,"tag":95,"props":637,"children":638},{"style":432},[639],{"type":37,"value":521},{"type":32,"tag":95,"props":641,"children":642},{"style":108},[643],{"type":37,"value":644}," _TABLE_SUFFIX ",{"type":32,"tag":95,"props":646,"children":647},{"style":432},[648],{"type":37,"value":649},"BETWEEN",{"type":32,"tag":95,"props":651,"children":652},{"style":108},[653],{"type":37,"value":654}," FORMAT_DATE(",{"type":32,"tag":95,"props":656,"children":657},{"style":152},[658],{"type":37,"value":659},"'%Y%m%d'",{"type":32,"tag":95,"props":661,"children":662},{"style":108},[663],{"type":37,"value":664},", DATE_SUB(CURRENT_DATE(), INTERVAL ",{"type":32,"tag":95,"props":666,"children":667},{"style":114},[668],{"type":37,"value":669},"90",{"type":32,"tag":95,"props":671,"children":672},{"style":432},[673],{"type":37,"value":674}," DAY",{"type":32,"tag":95,"props":676,"children":677},{"style":108},[678],{"type":37,"value":679},"))\n",{"type":32,"tag":95,"props":681,"children":682},{"class":97,"line":267},[683,688,692,696],{"type":32,"tag":95,"props":684,"children":685},{"style":432},[686],{"type":37,"value":687},"  AND",{"type":32,"tag":95,"props":689,"children":690},{"style":108},[691],{"type":37,"value":654},{"type":32,"tag":95,"props":693,"children":694},{"style":152},[695],{"type":37,"value":659},{"type":32,"tag":95,"props":697,"children":698},{"style":108},[699],{"type":37,"value":700},", CURRENT_DATE())\n",{"type":32,"tag":33,"props":702,"children":703},{},[704,706,712],{"type":37,"value":705},"Staging обеспечивает чистые данные, но без бизнес-логики. Intermediate модели добавляют логику: сессионизация, атрибуция, воронка событий. ",{"type":32,"tag":52,"props":707,"children":709},{"className":708},[],[710],{"type":37,"value":711},"int_sessions.sql",{"type":37,"value":713}," группирует GA4 события по сеансам:",{"type":32,"tag":85,"props":715,"children":717},{"className":420,"code":716,"language":422,"meta":16,"style":16},"WITH session_events AS (\n  SELECT\n    session_id,\n    MIN(event_time) AS session_start,\n    MAX(event_time) AS session_end,\n    COUNT(DISTINCT CASE WHEN event_name = 'page_view' THEN event_time END) AS pageviews,\n    MAX(CASE WHEN event_name = 'purchase' THEN 1 ELSE 0 END) AS converted\n  FROM {{ ref('stg_ga4_events') }}\n  GROUP BY session_id\n)\nSELECT\n  *,\n  TIMESTAMP_DIFF(session_end, session_start, SECOND) AS duration_seconds\nFROM session_events\n",[718],{"type":32,"tag":52,"props":719,"children":720},{"__ignoreMap":16},[721,743,751,759,781,802,873,943,965,978,986,993,1005,1031],{"type":32,"tag":95,"props":722,"children":723},{"class":97,"line":98},[724,729,734,738],{"type":32,"tag":95,"props":725,"children":726},{"style":432},[727],{"type":37,"value":728},"WITH",{"type":32,"tag":95,"props":730,"children":731},{"style":108},[732],{"type":37,"value":733}," session_events ",{"type":32,"tag":95,"props":735,"children":736},{"style":432},[737],{"type":37,"value":448},{"type":32,"tag":95,"props":739,"children":740},{"style":108},[741],{"type":37,"value":742}," (\n",{"type":32,"tag":95,"props":744,"children":745},{"class":97,"line":120},[746],{"type":32,"tag":95,"props":747,"children":748},{"style":432},[749],{"type":37,"value":750},"  SELECT\n",{"type":32,"tag":95,"props":752,"children":753},{"class":97,"line":134},[754],{"type":32,"tag":95,"props":755,"children":756},{"style":108},[757],{"type":37,"value":758},"    session_id,\n",{"type":32,"tag":95,"props":760,"children":761},{"class":97,"line":158},[762,767,772,776],{"type":32,"tag":95,"props":763,"children":764},{"style":114},[765],{"type":37,"value":766},"    MIN",{"type":32,"tag":95,"props":768,"children":769},{"style":108},[770],{"type":37,"value":771},"(event_time) ",{"type":32,"tag":95,"props":773,"children":774},{"style":432},[775],{"type":37,"value":448},{"type":32,"tag":95,"props":777,"children":778},{"style":108},[779],{"type":37,"value":780}," session_start,\n",{"type":32,"tag":95,"props":782,"children":783},{"class":97,"line":176},[784,789,793,797],{"type":32,"tag":95,"props":785,"children":786},{"style":114},[787],{"type":37,"value":788},"    MAX",{"type":32,"tag":95,"props":790,"children":791},{"style":108},[792],{"type":37,"value":771},{"type":32,"tag":95,"props":794,"children":795},{"style":432},[796],{"type":37,"value":448},{"type":32,"tag":95,"props":798,"children":799},{"style":108},[800],{"type":37,"value":801}," session_end,\n",{"type":32,"tag":95,"props":803,"children":804},{"class":97,"line":189},[805,810,815,820,825,830,835,840,845,850,855,860,864,868],{"type":32,"tag":95,"props":806,"children":807},{"style":114},[808],{"type":37,"value":809},"    COUNT",{"type":32,"tag":95,"props":811,"children":812},{"style":108},[813],{"type":37,"value":814},"(",{"type":32,"tag":95,"props":816,"children":817},{"style":432},[818],{"type":37,"value":819},"DISTINCT",{"type":32,"tag":95,"props":821,"children":822},{"style":432},[823],{"type":37,"value":824}," CASE",{"type":32,"tag":95,"props":826,"children":827},{"style":432},[828],{"type":37,"value":829}," WHEN",{"type":32,"tag":95,"props":831,"children":832},{"style":108},[833],{"type":37,"value":834}," event_name ",{"type":32,"tag":95,"props":836,"children":837},{"style":432},[838],{"type":37,"value":839},"=",{"type":32,"tag":95,"props":841,"children":842},{"style":152},[843],{"type":37,"value":844}," 'page_view'",{"type":32,"tag":95,"props":846,"children":847},{"style":432},[848],{"type":37,"value":849}," THEN",{"type":32,"tag":95,"props":851,"children":852},{"style":108},[853],{"type":37,"value":854}," event_time ",{"type":32,"tag":95,"props":856,"children":857},{"style":432},[858],{"type":37,"value":859},"END",{"type":32,"tag":95,"props":861,"children":862},{"style":108},[863],{"type":37,"value":541},{"type":32,"tag":95,"props":865,"children":866},{"style":432},[867],{"type":37,"value":448},{"type":32,"tag":95,"props":869,"children":870},{"style":108},[871],{"type":37,"value":872}," pageviews,\n",{"type":32,"tag":95,"props":874,"children":875},{"class":97,"line":211},[876,880,884,889,893,897,901,906,910,915,920,925,930,934,938],{"type":32,"tag":95,"props":877,"children":878},{"style":114},[879],{"type":37,"value":788},{"type":32,"tag":95,"props":881,"children":882},{"style":108},[883],{"type":37,"value":814},{"type":32,"tag":95,"props":885,"children":886},{"style":432},[887],{"type":37,"value":888},"CASE",{"type":32,"tag":95,"props":890,"children":891},{"style":432},[892],{"type":37,"value":829},{"type":32,"tag":95,"props":894,"children":895},{"style":108},[896],{"type":37,"value":834},{"type":32,"tag":95,"props":898,"children":899},{"style":432},[900],{"type":37,"value":839},{"type":32,"tag":95,"props":902,"children":903},{"style":152},[904],{"type":37,"value":905}," 'purchase'",{"type":32,"tag":95,"props":907,"children":908},{"style":432},[909],{"type":37,"value":849},{"type":32,"tag":95,"props":911,"children":912},{"style":114},[913],{"type":37,"value":914}," 1",{"type":32,"tag":95,"props":916,"children":917},{"style":432},[918],{"type":37,"value":919}," ELSE",{"type":32,"tag":95,"props":921,"children":922},{"style":114},[923],{"type":37,"value":924}," 0",{"type":32,"tag":95,"props":926,"children":927},{"style":432},[928],{"type":37,"value":929}," END",{"type":32,"tag":95,"props":931,"children":932},{"style":108},[933],{"type":37,"value":541},{"type":32,"tag":95,"props":935,"children":936},{"style":432},[937],{"type":37,"value":448},{"type":32,"tag":95,"props":939,"children":940},{"style":108},[941],{"type":37,"value":942}," converted\n",{"type":32,"tag":95,"props":944,"children":945},{"class":97,"line":26},[946,951,956,961],{"type":32,"tag":95,"props":947,"children":948},{"style":432},[949],{"type":37,"value":950},"  FROM",{"type":32,"tag":95,"props":952,"children":953},{"style":108},[954],{"type":37,"value":955}," {{ ref(",{"type":32,"tag":95,"props":957,"children":958},{"style":152},[959],{"type":37,"value":960},"'stg_ga4_events'",{"type":32,"tag":95,"props":962,"children":963},{"style":108},[964],{"type":37,"value":632},{"type":32,"tag":95,"props":966,"children":967},{"class":97,"line":246},[968,973],{"type":32,"tag":95,"props":969,"children":970},{"style":432},[971],{"type":37,"value":972},"  GROUP BY",{"type":32,"tag":95,"props":974,"children":975},{"style":108},[976],{"type":37,"value":977}," session_id\n",{"type":32,"tag":95,"props":979,"children":980},{"class":97,"line":267},[981],{"type":32,"tag":95,"props":982,"children":983},{"style":108},[984],{"type":37,"value":985},")\n",{"type":32,"tag":95,"props":987,"children":988},{"class":97,"line":284},[989],{"type":32,"tag":95,"props":990,"children":991},{"style":432},[992],{"type":37,"value":435},{"type":32,"tag":95,"props":994,"children":995},{"class":97,"line":302},[996,1001],{"type":32,"tag":95,"props":997,"children":998},{"style":432},[999],{"type":37,"value":1000},"  *",{"type":32,"tag":95,"props":1002,"children":1003},{"style":108},[1004],{"type":37,"value":572},{"type":32,"tag":95,"props":1006,"children":1007},{"class":97,"line":314},[1008,1013,1018,1022,1026],{"type":32,"tag":95,"props":1009,"children":1010},{"style":108},[1011],{"type":37,"value":1012},"  TIMESTAMP_DIFF(session_end, session_start, ",{"type":32,"tag":95,"props":1014,"children":1015},{"style":432},[1016],{"type":37,"value":1017},"SECOND",{"type":32,"tag":95,"props":1019,"children":1020},{"style":108},[1021],{"type":37,"value":541},{"type":32,"tag":95,"props":1023,"children":1024},{"style":432},[1025],{"type":37,"value":448},{"type":32,"tag":95,"props":1027,"children":1028},{"style":108},[1029],{"type":37,"value":1030}," duration_seconds\n",{"type":32,"tag":95,"props":1032,"children":1033},{"class":97,"line":335},[1034,1038],{"type":32,"tag":95,"props":1035,"children":1036},{"style":432},[1037],{"type":37,"value":607},{"type":32,"tag":95,"props":1039,"children":1040},{"style":108},[1041],{"type":37,"value":1042}," session_events\n",{"type":32,"tag":33,"props":1044,"children":1045},{},[1046,1048,1054,1056,1062,1063,1069,1070,1076,1078,1084,1086,1092,1094,1100],{"type":37,"value":1047},"Mart модели — финальный слой потребления, на них смотрят BI инструменты, Looker, внутренние дашборды. ",{"type":32,"tag":52,"props":1049,"children":1051},{"className":1050},[],[1052],{"type":37,"value":1053},"fct_marketing_performance.sql",{"type":37,"value":1055}," объединяет все каналы, считает расходы, доход, ROAS. Каждая mart модель сосредоточена на одной бизнес-сущности: ",{"type":32,"tag":52,"props":1057,"children":1059},{"className":1058},[],[1060],{"type":37,"value":1061},"dim_customers",{"type":37,"value":622},{"type":32,"tag":52,"props":1064,"children":1066},{"className":1065},[],[1067],{"type":37,"value":1068},"fct_orders",{"type":37,"value":622},{"type":32,"tag":52,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":37,"value":1075},"fct_sessions",{"type":37,"value":1077},". Naming convention в mart критичен — ",{"type":32,"tag":52,"props":1079,"children":1081},{"className":1080},[],[1082],{"type":37,"value":1083},"dim_",{"type":37,"value":1085}," для dimension (клиент, товар), ",{"type":32,"tag":52,"props":1087,"children":1089},{"className":1088},[],[1090],{"type":37,"value":1091},"fct_",{"type":37,"value":1093}," для fact (транзакция, событие), ",{"type":32,"tag":52,"props":1095,"children":1097},{"className":1096},[],[1098],{"type":37,"value":1099},"rpt_",{"type":37,"value":1101}," для report агрегатов.",{"type":32,"tag":40,"props":1103,"children":1105},{"id":1104},"семантический-слой-kpi-как-код",[1106],{"type":37,"value":1107},"Семантический слой: KPI как код",{"type":32,"tag":33,"props":1109,"children":1110},{},[1111,1113,1119],{"type":37,"value":1112},"Семантический слой переносит определения метрик из таблиц в dbt YAML — \"что такое доход\", \"как считается CAC\" теперь не в электронной таблице, а в версионируемом коде. В dbt v1.6+ вы определяете граф метрик в ",{"type":32,"tag":52,"props":1114,"children":1116},{"className":1115},[],[1117],{"type":37,"value":1118},"metrics.yml",{"type":37,"value":83},{"type":32,"tag":85,"props":1121,"children":1123},{"className":87,"code":1122,"language":89,"meta":16,"style":16},"version: 2\nmetrics:\n  - name: revenue\n    label: Revenue\n    model: ref('fct_orders')\n    calculation_method: sum\n    expression: order_amount\n    timestamp: order_date\n    time_grains: [day, week, month, quarter]\n    dimensions:\n      - channel\n      - country\n      - device_category\n\n  - name: cac\n    label: Customer Acquisition Cost\n    calculation_method: derived\n    expression: \"{{ metric('ad_spend') }} \u002F {{ metric('new_customers') }}\"\n    timestamp: acquisition_date\n    time_grains: [month, quarter]\n",[1124],{"type":32,"tag":52,"props":1125,"children":1126},{"__ignoreMap":16},[1127,1142,1154,1174,1191,1208,1225,1242,1259,1309,1321,1333,1345,1357,1366,1387,1404,1421,1438,1455],{"type":32,"tag":95,"props":1128,"children":1129},{"class":97,"line":98},[1130,1134,1138],{"type":32,"tag":95,"props":1131,"children":1132},{"style":102},[1133],{"type":37,"value":105},{"type":32,"tag":95,"props":1135,"children":1136},{"style":108},[1137],{"type":37,"value":111},{"type":32,"tag":95,"props":1139,"children":1140},{"style":114},[1141],{"type":37,"value":117},{"type":32,"tag":95,"props":1143,"children":1144},{"class":97,"line":120},[1145,1150],{"type":32,"tag":95,"props":1146,"children":1147},{"style":102},[1148],{"type":37,"value":1149},"metrics",{"type":32,"tag":95,"props":1151,"children":1152},{"style":108},[1153],{"type":37,"value":131},{"type":32,"tag":95,"props":1155,"children":1156},{"class":97,"line":134},[1157,1161,1165,1169],{"type":32,"tag":95,"props":1158,"children":1159},{"style":108},[1160],{"type":37,"value":140},{"type":32,"tag":95,"props":1162,"children":1163},{"style":102},[1164],{"type":37,"value":145},{"type":32,"tag":95,"props":1166,"children":1167},{"style":108},[1168],{"type":37,"value":111},{"type":32,"tag":95,"props":1170,"children":1171},{"style":152},[1172],{"type":37,"value":1173},"revenue\n",{"type":32,"tag":95,"props":1175,"children":1176},{"class":97,"line":158},[1177,1182,1186],{"type":32,"tag":95,"props":1178,"children":1179},{"style":102},[1180],{"type":37,"value":1181},"    label",{"type":32,"tag":95,"props":1183,"children":1184},{"style":108},[1185],{"type":37,"value":111},{"type":32,"tag":95,"props":1187,"children":1188},{"style":152},[1189],{"type":37,"value":1190},"Revenue\n",{"type":32,"tag":95,"props":1192,"children":1193},{"class":97,"line":176},[1194,1199,1203],{"type":32,"tag":95,"props":1195,"children":1196},{"style":102},[1197],{"type":37,"value":1198},"    model",{"type":32,"tag":95,"props":1200,"children":1201},{"style":108},[1202],{"type":37,"value":111},{"type":32,"tag":95,"props":1204,"children":1205},{"style":152},[1206],{"type":37,"value":1207},"ref('fct_orders')\n",{"type":32,"tag":95,"props":1209,"children":1210},{"class":97,"line":189},[1211,1216,1220],{"type":32,"tag":95,"props":1212,"children":1213},{"style":102},[1214],{"type":37,"value":1215},"    calculation_method",{"type":32,"tag":95,"props":1217,"children":1218},{"style":108},[1219],{"type":37,"value":111},{"type":32,"tag":95,"props":1221,"children":1222},{"style":152},[1223],{"type":37,"value":1224},"sum\n",{"type":32,"tag":95,"props":1226,"children":1227},{"class":97,"line":211},[1228,1233,1237],{"type":32,"tag":95,"props":1229,"children":1230},{"style":102},[1231],{"type":37,"value":1232},"    expression",{"type":32,"tag":95,"props":1234,"children":1235},{"style":108},[1236],{"type":37,"value":111},{"type":32,"tag":95,"props":1238,"children":1239},{"style":152},[1240],{"type":37,"value":1241},"order_amount\n",{"type":32,"tag":95,"props":1243,"children":1244},{"class":97,"line":26},[1245,1250,1254],{"type":32,"tag":95,"props":1246,"children":1247},{"style":102},[1248],{"type":37,"value":1249},"    timestamp",{"type":32,"tag":95,"props":1251,"children":1252},{"style":108},[1253],{"type":37,"value":111},{"type":32,"tag":95,"props":1255,"children":1256},{"style":152},[1257],{"type":37,"value":1258},"order_date\n",{"type":32,"tag":95,"props":1260,"children":1261},{"class":97,"line":246},[1262,1267,1272,1277,1281,1286,1290,1295,1299,1304],{"type":32,"tag":95,"props":1263,"children":1264},{"style":102},[1265],{"type":37,"value":1266},"    time_grains",{"type":32,"tag":95,"props":1268,"children":1269},{"style":108},[1270],{"type":37,"value":1271},": [",{"type":32,"tag":95,"props":1273,"children":1274},{"style":152},[1275],{"type":37,"value":1276},"day",{"type":32,"tag":95,"props":1278,"children":1279},{"style":108},[1280],{"type":37,"value":622},{"type":32,"tag":95,"props":1282,"children":1283},{"style":152},[1284],{"type":37,"value":1285},"week",{"type":32,"tag":95,"props":1287,"children":1288},{"style":108},[1289],{"type":37,"value":622},{"type":32,"tag":95,"props":1291,"children":1292},{"style":152},[1293],{"type":37,"value":1294},"month",{"type":32,"tag":95,"props":1296,"children":1297},{"style":108},[1298],{"type":37,"value":622},{"type":32,"tag":95,"props":1300,"children":1301},{"style":152},[1302],{"type":37,"value":1303},"quarter",{"type":32,"tag":95,"props":1305,"children":1306},{"style":108},[1307],{"type":37,"value":1308},"]\n",{"type":32,"tag":95,"props":1310,"children":1311},{"class":97,"line":267},[1312,1317],{"type":32,"tag":95,"props":1313,"children":1314},{"style":102},[1315],{"type":37,"value":1316},"    dimensions",{"type":32,"tag":95,"props":1318,"children":1319},{"style":108},[1320],{"type":37,"value":131},{"type":32,"tag":95,"props":1322,"children":1323},{"class":97,"line":284},[1324,1328],{"type":32,"tag":95,"props":1325,"children":1326},{"style":108},[1327],{"type":37,"value":195},{"type":32,"tag":95,"props":1329,"children":1330},{"style":152},[1331],{"type":37,"value":1332},"channel\n",{"type":32,"tag":95,"props":1334,"children":1335},{"class":97,"line":302},[1336,1340],{"type":32,"tag":95,"props":1337,"children":1338},{"style":108},[1339],{"type":37,"value":195},{"type":32,"tag":95,"props":1341,"children":1342},{"style":152},[1343],{"type":37,"value":1344},"country\n",{"type":32,"tag":95,"props":1346,"children":1347},{"class":97,"line":314},[1348,1352],{"type":32,"tag":95,"props":1349,"children":1350},{"style":108},[1351],{"type":37,"value":195},{"type":32,"tag":95,"props":1353,"children":1354},{"style":152},[1355],{"type":37,"value":1356},"device_category\n",{"type":32,"tag":95,"props":1358,"children":1359},{"class":97,"line":335},[1360],{"type":32,"tag":95,"props":1361,"children":1363},{"emptyLinePlaceholder":1362},true,[1364],{"type":37,"value":1365},"\n",{"type":32,"tag":95,"props":1367,"children":1369},{"class":97,"line":1368},15,[1370,1374,1378,1382],{"type":32,"tag":95,"props":1371,"children":1372},{"style":108},[1373],{"type":37,"value":140},{"type":32,"tag":95,"props":1375,"children":1376},{"style":102},[1377],{"type":37,"value":145},{"type":32,"tag":95,"props":1379,"children":1380},{"style":108},[1381],{"type":37,"value":111},{"type":32,"tag":95,"props":1383,"children":1384},{"style":152},[1385],{"type":37,"value":1386},"cac\n",{"type":32,"tag":95,"props":1388,"children":1390},{"class":97,"line":1389},16,[1391,1395,1399],{"type":32,"tag":95,"props":1392,"children":1393},{"style":102},[1394],{"type":37,"value":1181},{"type":32,"tag":95,"props":1396,"children":1397},{"style":108},[1398],{"type":37,"value":111},{"type":32,"tag":95,"props":1400,"children":1401},{"style":152},[1402],{"type":37,"value":1403},"Customer Acquisition Cost\n",{"type":32,"tag":95,"props":1405,"children":1407},{"class":97,"line":1406},17,[1408,1412,1416],{"type":32,"tag":95,"props":1409,"children":1410},{"style":102},[1411],{"type":37,"value":1215},{"type":32,"tag":95,"props":1413,"children":1414},{"style":108},[1415],{"type":37,"value":111},{"type":32,"tag":95,"props":1417,"children":1418},{"style":152},[1419],{"type":37,"value":1420},"derived\n",{"type":32,"tag":95,"props":1422,"children":1424},{"class":97,"line":1423},18,[1425,1429,1433],{"type":32,"tag":95,"props":1426,"children":1427},{"style":102},[1428],{"type":37,"value":1232},{"type":32,"tag":95,"props":1430,"children":1431},{"style":108},[1432],{"type":37,"value":111},{"type":32,"tag":95,"props":1434,"children":1435},{"style":152},[1436],{"type":37,"value":1437},"\"{{ metric('ad_spend') }} \u002F {{ metric('new_customers') }}\"\n",{"type":32,"tag":95,"props":1439,"children":1441},{"class":97,"line":1440},19,[1442,1446,1450],{"type":32,"tag":95,"props":1443,"children":1444},{"style":102},[1445],{"type":37,"value":1249},{"type":32,"tag":95,"props":1447,"children":1448},{"style":108},[1449],{"type":37,"value":111},{"type":32,"tag":95,"props":1451,"children":1452},{"style":152},[1453],{"type":37,"value":1454},"acquisition_date\n",{"type":32,"tag":95,"props":1456,"children":1458},{"class":97,"line":1457},20,[1459,1463,1467,1471,1475,1479],{"type":32,"tag":95,"props":1460,"children":1461},{"style":102},[1462],{"type":37,"value":1266},{"type":32,"tag":95,"props":1464,"children":1465},{"style":108},[1466],{"type":37,"value":1271},{"type":32,"tag":95,"props":1468,"children":1469},{"style":152},[1470],{"type":37,"value":1294},{"type":32,"tag":95,"props":1472,"children":1473},{"style":108},[1474],{"type":37,"value":622},{"type":32,"tag":95,"props":1476,"children":1477},{"style":152},[1478],{"type":37,"value":1303},{"type":32,"tag":95,"props":1480,"children":1481},{"style":108},[1482],{"type":37,"value":1308},{"type":32,"tag":33,"props":1484,"children":1485},{},[1486],{"type":37,"value":1487},"С семантическим слоем BI инструмент не считает CAC, это делает dbt. Когда Looker запрашивает CAC, dbt возвращает скомпилированный SQL, который join'ит таблицы расходов и новых клиентов, затем делит. Определение — это код, у него есть история в git: \"кто изменил формулу CAC, когда и почему\". Формула в электронной таблице теряется, здесь — версионируется.",{"type":32,"tag":33,"props":1489,"children":1490},{},[1491,1493,1502,1504,1510,1512,1518],{"type":37,"value":1492},"В проектах Roibase семантический слой входит в ",{"type":32,"tag":1494,"props":1495,"children":1499},"a",{"href":1496,"rel":1497},"https:\u002F\u002Fwww.roibase.com.tr\u002Fru\u002Fverianalizi",[1498],"nofollow",[1500],{"type":37,"value":1501},"анализ данных и инженерию внутренних метрик",{"type":37,"value":1503}," — не только дефиниция метрики, но иерархия KPI, mapping размерностей, стандартизация гранулярности. Пример: метрика \"revenue\" — это сумма ",{"type":32,"tag":52,"props":1505,"children":1507},{"className":1506},[],[1508],{"type":37,"value":1509},"fct_orders.order_amount",{"type":37,"value":1511},", но \"recognized_revenue\" из той же таблицы фильтруется по ",{"type":32,"tag":52,"props":1513,"children":1515},{"className":1514},[],[1516],{"type":37,"value":1517},"recognized_at",{"type":37,"value":1519}," timestamp (для SaaS с подписками). Одна таблица, две метрики, разная бизнес-логика.",{"type":32,"tag":40,"props":1521,"children":1523},{"id":1522},"exposures-видимость-downstream-зависимостей",[1524],{"type":37,"value":1525},"Exposures: видимость downstream зависимостей",{"type":32,"tag":33,"props":1527,"children":1528},{},[1529,1531,1537,1539,1545],{"type":37,"value":1530},"Exposure — способ dbt ответить на вопрос \"кто использует эту модель\". Если дашборд Looker смотрит на ",{"type":32,"tag":52,"props":1532,"children":1534},{"className":1533},[],[1535],{"type":37,"value":1536},"fct_marketing_performance",{"type":37,"value":1538},", вы определяете это в ",{"type":32,"tag":52,"props":1540,"children":1542},{"className":1541},[],[1543],{"type":37,"value":1544},"exposures.yml",{"type":37,"value":83},{"type":32,"tag":85,"props":1547,"children":1549},{"className":87,"code":1548,"language":89,"meta":16,"style":16},"version: 2\nexposures:\n  - name: marketing_dashboard\n    type: dashboard\n    maturity: high\n    owner:\n      name: Growth Team\n      email: growth@company.com\n    depends_on:\n      - ref('fct_marketing_performance')\n      - ref('dim_customers')\n    description: \"Executive marketing dashboard — daily refresh, 90-day rolling window\"\n    url: https:\u002F\u002Flooker.company.com\u002Fdashboards\u002F123\n",[1550],{"type":32,"tag":52,"props":1551,"children":1552},{"__ignoreMap":16},[1553,1568,1580,1600,1617,1634,1646,1663,1680,1692,1704,1716,1733],{"type":32,"tag":95,"props":1554,"children":1555},{"class":97,"line":98},[1556,1560,1564],{"type":32,"tag":95,"props":1557,"children":1558},{"style":102},[1559],{"type":37,"value":105},{"type":32,"tag":95,"props":1561,"children":1562},{"style":108},[1563],{"type":37,"value":111},{"type":32,"tag":95,"props":1565,"children":1566},{"style":114},[1567],{"type":37,"value":117},{"type":32,"tag":95,"props":1569,"children":1570},{"class":97,"line":120},[1571,1576],{"type":32,"tag":95,"props":1572,"children":1573},{"style":102},[1574],{"type":37,"value":1575},"exposures",{"type":32,"tag":95,"props":1577,"children":1578},{"style":108},[1579],{"type":37,"value":131},{"type":32,"tag":95,"props":1581,"children":1582},{"class":97,"line":134},[1583,1587,1591,1595],{"type":32,"tag":95,"props":1584,"children":1585},{"style":108},[1586],{"type":37,"value":140},{"type":32,"tag":95,"props":1588,"children":1589},{"style":102},[1590],{"type":37,"value":145},{"type":32,"tag":95,"props":1592,"children":1593},{"style":108},[1594],{"type":37,"value":111},{"type":32,"tag":95,"props":1596,"children":1597},{"style":152},[1598],{"type":37,"value":1599},"marketing_dashboard\n",{"type":32,"tag":95,"props":1601,"children":1602},{"class":97,"line":158},[1603,1608,1612],{"type":32,"tag":95,"props":1604,"children":1605},{"style":102},[1606],{"type":37,"value":1607},"    type",{"type":32,"tag":95,"props":1609,"children":1610},{"style":108},[1611],{"type":37,"value":111},{"type":32,"tag":95,"props":1613,"children":1614},{"style":152},[1615],{"type":37,"value":1616},"dashboard\n",{"type":32,"tag":95,"props":1618,"children":1619},{"class":97,"line":176},[1620,1625,1629],{"type":32,"tag":95,"props":1621,"children":1622},{"style":102},[1623],{"type":37,"value":1624},"    maturity",{"type":32,"tag":95,"props":1626,"children":1627},{"style":108},[1628],{"type":37,"value":111},{"type":32,"tag":95,"props":1630,"children":1631},{"style":152},[1632],{"type":37,"value":1633},"high\n",{"type":32,"tag":95,"props":1635,"children":1636},{"class":97,"line":189},[1637,1642],{"type":32,"tag":95,"props":1638,"children":1639},{"style":102},[1640],{"type":37,"value":1641},"    owner",{"type":32,"tag":95,"props":1643,"children":1644},{"style":108},[1645],{"type":37,"value":131},{"type":32,"tag":95,"props":1647,"children":1648},{"class":97,"line":211},[1649,1654,1658],{"type":32,"tag":95,"props":1650,"children":1651},{"style":102},[1652],{"type":37,"value":1653},"      name",{"type":32,"tag":95,"props":1655,"children":1656},{"style":108},[1657],{"type":37,"value":111},{"type":32,"tag":95,"props":1659,"children":1660},{"style":152},[1661],{"type":37,"value":1662},"Growth Team\n",{"type":32,"tag":95,"props":1664,"children":1665},{"class":97,"line":26},[1666,1671,1675],{"type":32,"tag":95,"props":1667,"children":1668},{"style":102},[1669],{"type":37,"value":1670},"      email",{"type":32,"tag":95,"props":1672,"children":1673},{"style":108},[1674],{"type":37,"value":111},{"type":32,"tag":95,"props":1676,"children":1677},{"style":152},[1678],{"type":37,"value":1679},"growth@company.com\n",{"type":32,"tag":95,"props":1681,"children":1682},{"class":97,"line":246},[1683,1688],{"type":32,"tag":95,"props":1684,"children":1685},{"style":102},[1686],{"type":37,"value":1687},"    depends_on",{"type":32,"tag":95,"props":1689,"children":1690},{"style":108},[1691],{"type":37,"value":131},{"type":32,"tag":95,"props":1693,"children":1694},{"class":97,"line":267},[1695,1699],{"type":32,"tag":95,"props":1696,"children":1697},{"style":108},[1698],{"type":37,"value":195},{"type":32,"tag":95,"props":1700,"children":1701},{"style":152},[1702],{"type":37,"value":1703},"ref('fct_marketing_performance')\n",{"type":32,"tag":95,"props":1705,"children":1706},{"class":97,"line":284},[1707,1711],{"type":32,"tag":95,"props":1708,"children":1709},{"style":108},[1710],{"type":37,"value":195},{"type":32,"tag":95,"props":1712,"children":1713},{"style":152},[1714],{"type":37,"value":1715},"ref('dim_customers')\n",{"type":32,"tag":95,"props":1717,"children":1718},{"class":97,"line":302},[1719,1724,1728],{"type":32,"tag":95,"props":1720,"children":1721},{"style":102},[1722],{"type":37,"value":1723},"    description",{"type":32,"tag":95,"props":1725,"children":1726},{"style":108},[1727],{"type":37,"value":111},{"type":32,"tag":95,"props":1729,"children":1730},{"style":152},[1731],{"type":37,"value":1732},"\"Executive marketing dashboard — daily refresh, 90-day rolling window\"\n",{"type":32,"tag":95,"props":1734,"children":1735},{"class":97,"line":314},[1736,1741,1745],{"type":32,"tag":95,"props":1737,"children":1738},{"style":102},[1739],{"type":37,"value":1740},"    url",{"type":32,"tag":95,"props":1742,"children":1743},{"style":108},[1744],{"type":37,"value":111},{"type":32,"tag":95,"props":1746,"children":1747},{"style":152},[1748],{"type":37,"value":1749},"https:\u002F\u002Flooker.company.com\u002Fdashboards\u002F123\n",{"type":32,"tag":33,"props":1751,"children":1752},{},[1753,1755,1760,1762,1768],{"type":37,"value":1754},"Без exposure вы меняете ",{"type":32,"tag":52,"props":1756,"children":1758},{"className":1757},[],[1759],{"type":37,"value":1536},{"type":37,"value":1761},", дашборд в Looker показывает нули, 2 часа отлаживаете проблему. С exposure ",{"type":32,"tag":52,"props":1763,"children":1765},{"className":1764},[],[1766],{"type":37,"value":1767},"dbt compile --select +exposure:marketing_dashboard",{"type":37,"value":1769}," показывает все upstream модели, вы оцениваете влияние изменения до merging.",{"type":32,"tag":33,"props":1771,"children":1772},{},[1773,1775,1781],{"type":37,"value":1774},"Exposure не только для BI инструментов — reverse ETL (Hightouch, Census) тоже exposure. Если вы отправляете таблицу ",{"type":32,"tag":52,"props":1776,"children":1778},{"className":1777},[],[1779],{"type":37,"value":1780},"customers",{"type":37,"value":1782}," в Meta CAPI:",{"type":32,"tag":85,"props":1784,"children":1786},{"className":87,"code":1785,"language":89,"meta":16,"style":16},"exposures:\n  - name: meta_capi_sync\n    type: application\n    maturity: high\n    depends_on:\n      - ref('dim_customers')\n    description: \"Meta Conversion API — incremental customer events, 5-minute delay\"\n",[1787],{"type":32,"tag":52,"props":1788,"children":1789},{"__ignoreMap":16},[1790,1801,1821,1837,1852,1863,1874],{"type":32,"tag":95,"props":1791,"children":1792},{"class":97,"line":98},[1793,1797],{"type":32,"tag":95,"props":1794,"children":1795},{"style":102},[1796],{"type":37,"value":1575},{"type":32,"tag":95,"props":1798,"children":1799},{"style":108},[1800],{"type":37,"value":131},{"type":32,"tag":95,"props":1802,"children":1803},{"class":97,"line":120},[1804,1808,1812,1816],{"type":32,"tag":95,"props":1805,"children":1806},{"style":108},[1807],{"type":37,"value":140},{"type":32,"tag":95,"props":1809,"children":1810},{"style":102},[1811],{"type":37,"value":145},{"type":32,"tag":95,"props":1813,"children":1814},{"style":108},[1815],{"type":37,"value":111},{"type":32,"tag":95,"props":1817,"children":1818},{"style":152},[1819],{"type":37,"value":1820},"meta_capi_sync\n",{"type":32,"tag":95,"props":1822,"children":1823},{"class":97,"line":134},[1824,1828,1832],{"type":32,"tag":95,"props":1825,"children":1826},{"style":102},[1827],{"type":37,"value":1607},{"type":32,"tag":95,"props":1829,"children":1830},{"style":108},[1831],{"type":37,"value":111},{"type":32,"tag":95,"props":1833,"children":1834},{"style":152},[1835],{"type":37,"value":1836},"application\n",{"type":32,"tag":95,"props":1838,"children":1839},{"class":97,"line":158},[1840,1844,1848],{"type":32,"tag":95,"props":1841,"children":1842},{"style":102},[1843],{"type":37,"value":1624},{"type":32,"tag":95,"props":1845,"children":1846},{"style":108},[1847],{"type":37,"value":111},{"type":32,"tag":95,"props":1849,"children":1850},{"style":152},[1851],{"type":37,"value":1633},{"type":32,"tag":95,"props":1853,"children":1854},{"class":97,"line":176},[1855,1859],{"type":32,"tag":95,"props":1856,"children":1857},{"style":102},[1858],{"type":37,"value":1687},{"type":32,"tag":95,"props":1860,"children":1861},{"style":108},[1862],{"type":37,"value":131},{"type":32,"tag":95,"props":1864,"children":1865},{"class":97,"line":189},[1866,1870],{"type":32,"tag":95,"props":1867,"children":1868},{"style":108},[1869],{"type":37,"value":195},{"type":32,"tag":95,"props":1871,"children":1872},{"style":152},[1873],{"type":37,"value":1715},{"type":32,"tag":95,"props":1875,"children":1876},{"class":97,"line":211},[1877,1881,1885],{"type":32,"tag":95,"props":1878,"children":1879},{"style":102},[1880],{"type":37,"value":1723},{"type":32,"tag":95,"props":1882,"children":1883},{"style":108},[1884],{"type":37,"value":111},{"type":32,"tag":95,"props":1886,"children":1887},{"style":152},[1888],{"type":37,"value":1889},"\"Meta Conversion API — incremental customer events, 5-minute delay\"\n",{"type":32,"tag":33,"props":1891,"children":1892},{},[1893],{"type":37,"value":1894},"Это говорит: \"если изменишь схему dim_customers, сломаешь CAPI sync\". Production: обновление модели → ошибка CAPI → потеря данных атрибуции. Exposure дает ранний сигнал.",{"type":32,"tag":40,"props":1896,"children":1898},{"id":1897},"production-pipeline-incremental-builds-и-покрытие-тестами",[1899],{"type":37,"value":1900},"Production pipeline: incremental builds и покрытие тестами",{"type":32,"tag":33,"props":1902,"children":1903},{},[1904,1906,1912],{"type":37,"value":1905},"В production dbt не делает full refresh каждый день — использует incremental модели. ",{"type":32,"tag":52,"props":1907,"children":1909},{"className":1908},[],[1910],{"type":37,"value":1911},"fct_orders.sql",{"type":37,"value":1913}," переобрабатывает только последние 3 дня:",{"type":32,"tag":85,"props":1915,"children":1917},{"className":420,"code":1916,"language":422,"meta":16,"style":16},"{{ config(\n    materialized='incremental',\n    unique_key='order_id',\n    partition_by={'field': 'order_date', 'data_type': 'date'},\n    cluster_by=['customer_id', 'channel']\n) }}\n\nSELECT\n  order_id,\n  customer_id,\n  order_date,\n  order_amount,\n  channel\nFROM {{ ref('stg_shopify_orders') }}\n\n{% if is_incremental() %}\nWHERE order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)\n{% endif %}\n",[1918],{"type":32,"tag":52,"props":1919,"children":1920},{"__ignoreMap":16},[1921,1929,1950,1971,2025,2042,2049,2056,2063,2071,2079,2087,2095,2103,2123,2130,2148,2183],{"type":32,"tag":95,"props":1922,"children":1923},{"class":97,"line":98},[1924],{"type":32,"tag":95,"props":1925,"children":1926},{"style":108},[1927],{"type":37,"value":1928},"{{ config(\n",{"type":32,"tag":95,"props":1930,"children":1931},{"class":97,"line":120},[1932,1937,1941,1946],{"type":32,"tag":95,"props":1933,"children":1934},{"style":108},[1935],{"type":37,"value":1936},"    materialized",{"type":32,"tag":95,"props":1938,"children":1939},{"style":432},[1940],{"type":37,"value":839},{"type":32,"tag":95,"props":1942,"children":1943},{"style":152},[1944],{"type":37,"value":1945},"'incremental'",{"type":32,"tag":95,"props":1947,"children":1948},{"style":108},[1949],{"type":37,"value":572},{"type":32,"tag":95,"props":1951,"children":1952},{"class":97,"line":134},[1953,1958,1962,1967],{"type":32,"tag":95,"props":1954,"children":1955},{"style":108},[1956],{"type":37,"value":1957},"    unique_key",{"type":32,"tag":95,"props":1959,"children":1960},{"style":432},[1961],{"type":37,"value":839},{"type":32,"tag":95,"props":1963,"children":1964},{"style":152},[1965],{"type":37,"value":1966},"'order_id'",{"type":32,"tag":95,"props":1968,"children":1969},{"style":108},[1970],{"type":37,"value":572},{"type":32,"tag":95,"props":1972,"children":1973},{"class":97,"line":158},[1974,1979,1983,1988,1993,1997,2002,2006,2011,2015,2020],{"type":32,"tag":95,"props":1975,"children":1976},{"style":108},[1977],{"type":37,"value":1978},"    partition_by",{"type":32,"tag":95,"props":1980,"children":1981},{"style":432},[1982],{"type":37,"value":839},{"type":32,"tag":95,"props":1984,"children":1985},{"style":108},[1986],{"type":37,"value":1987},"{",{"type":32,"tag":95,"props":1989,"children":1990},{"style":152},[1991],{"type":37,"value":1992},"'field'",{"type":32,"tag":95,"props":1994,"children":1995},{"style":108},[1996],{"type":37,"value":111},{"type":32,"tag":95,"props":1998,"children":1999},{"style":152},[2000],{"type":37,"value":2001},"'order_date'",{"type":32,"tag":95,"props":2003,"children":2004},{"style":108},[2005],{"type":37,"value":622},{"type":32,"tag":95,"props":2007,"children":2008},{"style":152},[2009],{"type":37,"value":2010},"'data_type'",{"type":32,"tag":95,"props":2012,"children":2013},{"style":108},[2014],{"type":37,"value":111},{"type":32,"tag":95,"props":2016,"children":2017},{"style":152},[2018],{"type":37,"value":2019},"'date'",{"type":32,"tag":95,"props":2021,"children":2022},{"style":108},[2023],{"type":37,"value":2024},"},\n",{"type":32,"tag":95,"props":2026,"children":2027},{"class":97,"line":176},[2028,2033,2037],{"type":32,"tag":95,"props":2029,"children":2030},{"style":108},[2031],{"type":37,"value":2032},"    cluster_by",{"type":32,"tag":95,"props":2034,"children":2035},{"style":432},[2036],{"type":37,"value":839},{"type":32,"tag":95,"props":2038,"children":2039},{"style":108},[2040],{"type":37,"value":2041},"['customer_id', 'channel']\n",{"type":32,"tag":95,"props":2043,"children":2044},{"class":97,"line":189},[2045],{"type":32,"tag":95,"props":2046,"children":2047},{"style":108},[2048],{"type":37,"value":632},{"type":32,"tag":95,"props":2050,"children":2051},{"class":97,"line":211},[2052],{"type":32,"tag":95,"props":2053,"children":2054},{"emptyLinePlaceholder":1362},[2055],{"type":37,"value":1365},{"type":32,"tag":95,"props":2057,"children":2058},{"class":97,"line":26},[2059],{"type":32,"tag":95,"props":2060,"children":2061},{"style":432},[2062],{"type":37,"value":435},{"type":32,"tag":95,"props":2064,"children":2065},{"class":97,"line":246},[2066],{"type":32,"tag":95,"props":2067,"children":2068},{"style":108},[2069],{"type":37,"value":2070},"  order_id,\n",{"type":32,"tag":95,"props":2072,"children":2073},{"class":97,"line":267},[2074],{"type":32,"tag":95,"props":2075,"children":2076},{"style":108},[2077],{"type":37,"value":2078},"  customer_id,\n",{"type":32,"tag":95,"props":2080,"children":2081},{"class":97,"line":284},[2082],{"type":32,"tag":95,"props":2083,"children":2084},{"style":108},[2085],{"type":37,"value":2086},"  order_date,\n",{"type":32,"tag":95,"props":2088,"children":2089},{"class":97,"line":302},[2090],{"type":32,"tag":95,"props":2091,"children":2092},{"style":108},[2093],{"type":37,"value":2094},"  order_amount,\n",{"type":32,"tag":95,"props":2096,"children":2097},{"class":97,"line":314},[2098],{"type":32,"tag":95,"props":2099,"children":2100},{"style":108},[2101],{"type":37,"value":2102},"  channel\n",{"type":32,"tag":95,"props":2104,"children":2105},{"class":97,"line":335},[2106,2110,2114,2119],{"type":32,"tag":95,"props":2107,"children":2108},{"style":432},[2109],{"type":37,"value":607},{"type":32,"tag":95,"props":2111,"children":2112},{"style":108},[2113],{"type":37,"value":955},{"type":32,"tag":95,"props":2115,"children":2116},{"style":152},[2117],{"type":37,"value":2118},"'stg_shopify_orders'",{"type":32,"tag":95,"props":2120,"children":2121},{"style":108},[2122],{"type":37,"value":632},{"type":32,"tag":95,"props":2124,"children":2125},{"class":97,"line":1368},[2126],{"type":32,"tag":95,"props":2127,"children":2128},{"emptyLinePlaceholder":1362},[2129],{"type":37,"value":1365},{"type":32,"tag":95,"props":2131,"children":2132},{"class":97,"line":1389},[2133,2138,2143],{"type":32,"tag":95,"props":2134,"children":2135},{"style":108},[2136],{"type":37,"value":2137},"{% ",{"type":32,"tag":95,"props":2139,"children":2140},{"style":432},[2141],{"type":37,"value":2142},"if",{"type":32,"tag":95,"props":2144,"children":2145},{"style":108},[2146],{"type":37,"value":2147}," is_incremental() %}\n",{"type":32,"tag":95,"props":2149,"children":2150},{"class":97,"line":1406},[2151,2155,2160,2165,2170,2175,2179],{"type":32,"tag":95,"props":2152,"children":2153},{"style":432},[2154],{"type":37,"value":521},{"type":32,"tag":95,"props":2156,"children":2157},{"style":108},[2158],{"type":37,"value":2159}," order_date ",{"type":32,"tag":95,"props":2161,"children":2162},{"style":432},[2163],{"type":37,"value":2164},">=",{"type":32,"tag":95,"props":2166,"children":2167},{"style":108},[2168],{"type":37,"value":2169}," DATE_SUB(CURRENT_DATE(), INTERVAL ",{"type":32,"tag":95,"props":2171,"children":2172},{"style":114},[2173],{"type":37,"value":2174},"3",{"type":32,"tag":95,"props":2176,"children":2177},{"style":432},[2178],{"type":37,"value":674},{"type":32,"tag":95,"props":2180,"children":2181},{"style":108},[2182],{"type":37,"value":985},{"type":32,"tag":95,"props":2184,"children":2185},{"class":97,"line":1423},[2186],{"type":32,"tag":95,"props":2187,"children":2188},{"style":108},[2189],{"type":37,"value":2190},"{% endif %}\n",{"type":32,"tag":33,"props":2192,"children":2193},{},[2194,2196,2202],{"type":37,"value":2195},"Incremental build снижает стоимость BigQuery на 90% — вместо сканирования 2TB сканируете 50GB. Partition + cluster улучшает performance: запрос ",{"type":32,"tag":52,"props":2197,"children":2199},{"className":2198},[],[2200],{"type":37,"value":2201},"WHERE customer_id = 'X'",{"type":37,"value":2203}," идет только в нужный cluster, full scan не нужен.",{"type":32,"tag":33,"props":2205,"children":2206},{},[2207,2209,2215],{"type":37,"value":2208},"Покрытие тестами критично. Вы пишете тесты в ",{"type":32,"tag":52,"props":2210,"children":2212},{"className":2211},[],[2213],{"type":37,"value":2214},"schema.yml",{"type":37,"value":2216}," для каждой модели:",{"type":32,"tag":85,"props":2218,"children":2220},{"className":87,"code":2219,"language":89,"meta":16,"style":16},"models:\n  - name: fct_orders\n    columns:\n      - name: order_id\n        tests:\n          - unique\n          - not_null\n      - name: order_amount\n        tests:\n          - not_null\n          - dbt_utils.expression_is_true:\n              expression: \">= 0\"\n      - name: order_date\n        tests:\n          - dbt_utils.recency:\n              datepart: day\n              interval: 7\n",[2221],{"type":32,"tag":52,"props":2222,"children":2223},{"__ignoreMap":16},[2224,2236,2256,2268,2288,2300,2313,2325,2344,2355,2366,2382,2399,2418,2429,2445,2462],{"type":32,"tag":95,"props":2225,"children":2226},{"class":97,"line":98},[2227,2232],{"type":32,"tag":95,"props":2228,"children":2229},{"style":102},[2230],{"type":37,"value":2231},"models",{"type":32,"tag":95,"props":2233,"children":2234},{"style":108},[2235],{"type":37,"value":131},{"type":32,"tag":95,"props":2237,"children":2238},{"class":97,"line":120},[2239,2243,2247,2251],{"type":32,"tag":95,"props":2240,"children":2241},{"style":108},[2242],{"type":37,"value":140},{"type":32,"tag":95,"props":2244,"children":2245},{"style":102},[2246],{"type":37,"value":145},{"type":32,"tag":95,"props":2248,"children":2249},{"style":108},[2250],{"type":37,"value":111},{"type":32,"tag":95,"props":2252,"children":2253},{"style":152},[2254],{"type":37,"value":2255},"fct_orders\n",{"type":32,"tag":95,"props":2257,"children":2258},{"class":97,"line":134},[2259,2264],{"type":32,"tag":95,"props":2260,"children":2261},{"style":102},[2262],{"type":37,"value":2263},"    columns",{"type":32,"tag":95,"props":2265,"children":2266},{"style":108},[2267],{"type":37,"value":131},{"type":32,"tag":95,"props":2269,"children":2270},{"class":97,"line":158},[2271,2275,2279,2283],{"type":32,"tag":95,"props":2272,"children":2273},{"style":108},[2274],{"type":37,"value":195},{"type":32,"tag":95,"props":2276,"children":2277},{"style":102},[2278],{"type":37,"value":145},{"type":32,"tag":95,"props":2280,"children":2281},{"style":108},[2282],{"type":37,"value":111},{"type":32,"tag":95,"props":2284,"children":2285},{"style":152},[2286],{"type":37,"value":2287},"order_id\n",{"type":32,"tag":95,"props":2289,"children":2290},{"class":97,"line":176},[2291,2296],{"type":32,"tag":95,"props":2292,"children":2293},{"style":102},[2294],{"type":37,"value":2295},"        tests",{"type":32,"tag":95,"props":2297,"children":2298},{"style":108},[2299],{"type":37,"value":131},{"type":32,"tag":95,"props":2301,"children":2302},{"class":97,"line":189},[2303,2308],{"type":32,"tag":95,"props":2304,"children":2305},{"style":108},[2306],{"type":37,"value":2307},"          - ",{"type":32,"tag":95,"props":2309,"children":2310},{"style":152},[2311],{"type":37,"value":2312},"unique\n",{"type":32,"tag":95,"props":2314,"children":2315},{"class":97,"line":211},[2316,2320],{"type":32,"tag":95,"props":2317,"children":2318},{"style":108},[2319],{"type":37,"value":2307},{"type":32,"tag":95,"props":2321,"children":2322},{"style":152},[2323],{"type":37,"value":2324},"not_null\n",{"type":32,"tag":95,"props":2326,"children":2327},{"class":97,"line":26},[2328,2332,2336,2340],{"type":32,"tag":95,"props":2329,"children":2330},{"style":108},[2331],{"type":37,"value":195},{"type":32,"tag":95,"props":2333,"children":2334},{"style":102},[2335],{"type":37,"value":145},{"type":32,"tag":95,"props":2337,"children":2338},{"style":108},[2339],{"type":37,"value":111},{"type":32,"tag":95,"props":2341,"children":2342},{"style":152},[2343],{"type":37,"value":1241},{"type":32,"tag":95,"props":2345,"children":2346},{"class":97,"line":246},[2347,2351],{"type":32,"tag":95,"props":2348,"children":2349},{"style":102},[2350],{"type":37,"value":2295},{"type":32,"tag":95,"props":2352,"children":2353},{"style":108},[2354],{"type":37,"value":131},{"type":32,"tag":95,"props":2356,"children":2357},{"class":97,"line":267},[2358,2362],{"type":32,"tag":95,"props":2359,"children":2360},{"style":108},[2361],{"type":37,"value":2307},{"type":32,"tag":95,"props":2363,"children":2364},{"style":152},[2365],{"type":37,"value":2324},{"type":32,"tag":95,"props":2367,"children":2368},{"class":97,"line":284},[2369,2373,2378],{"type":32,"tag":95,"props":2370,"children":2371},{"style":108},[2372],{"type":37,"value":2307},{"type":32,"tag":95,"props":2374,"children":2375},{"style":102},[2376],{"type":37,"value":2377},"dbt_utils.expression_is_true",{"type":32,"tag":95,"props":2379,"children":2380},{"style":108},[2381],{"type":37,"value":131},{"type":32,"tag":95,"props":2383,"children":2384},{"class":97,"line":302},[2385,2390,2394],{"type":32,"tag":95,"props":2386,"children":2387},{"style":102},[2388],{"type":37,"value":2389},"              expression",{"type":32,"tag":95,"props":2391,"children":2392},{"style":108},[2393],{"type":37,"value":111},{"type":32,"tag":95,"props":2395,"children":2396},{"style":152},[2397],{"type":37,"value":2398},"\">= 0\"\n",{"type":32,"tag":95,"props":2400,"children":2401},{"class":97,"line":314},[2402,2406,2410,2414],{"type":32,"tag":95,"props":2403,"children":2404},{"style":108},[2405],{"type":37,"value":195},{"type":32,"tag":95,"props":2407,"children":2408},{"style":102},[2409],{"type":37,"value":145},{"type":32,"tag":95,"props":2411,"children":2412},{"style":108},[2413],{"type":37,"value":111},{"type":32,"tag":95,"props":2415,"children":2416},{"style":152},[2417],{"type":37,"value":1258},{"type":32,"tag":95,"props":2419,"children":2420},{"class":97,"line":335},[2421,2425],{"type":32,"tag":95,"props":2422,"children":2423},{"style":102},[2424],{"type":37,"value":2295},{"type":32,"tag":95,"props":2426,"children":2427},{"style":108},[2428],{"type":37,"value":131},{"type":32,"tag":95,"props":2430,"children":2431},{"class":97,"line":1368},[2432,2436,2441],{"type":32,"tag":95,"props":2433,"children":2434},{"style":108},[2435],{"type":37,"value":2307},{"type":32,"tag":95,"props":2437,"children":2438},{"style":102},[2439],{"type":37,"value":2440},"dbt_utils.recency",{"type":32,"tag":95,"props":2442,"children":2443},{"style":108},[2444],{"type":37,"value":131},{"type":32,"tag":95,"props":2446,"children":2447},{"class":97,"line":1389},[2448,2453,2457],{"type":32,"tag":95,"props":2449,"children":2450},{"style":102},[2451],{"type":37,"value":2452},"              datepart",{"type":32,"tag":95,"props":2454,"children":2455},{"style":108},[2456],{"type":37,"value":111},{"type":32,"tag":95,"props":2458,"children":2459},{"style":152},[2460],{"type":37,"value":2461},"day\n",{"type":32,"tag":95,"props":2463,"children":2464},{"class":97,"line":1406},[2465,2470,2474],{"type":32,"tag":95,"props":2466,"children":2467},{"style":102},[2468],{"type":37,"value":2469},"              interval",{"type":32,"tag":95,"props":2471,"children":2472},{"style":108},[2473],{"type":37,"value":111},{"type":32,"tag":95,"props":2475,"children":2476},{"style":114},[2477],{"type":37,"value":2478},"7\n",{"type":32,"tag":33,"props":2480,"children":2481},{},[2482,2488,2490,2496],{"type":32,"tag":52,"props":2483,"children":2485},{"className":2484},[],[2486],{"type":37,"value":2487},"dbt test",{"type":37,"value":2489}," выполняет эти условия в BigQuery — если order_amount отрицательный, build падает. В production каждый commit проходит CI\u002FCD: ",{"type":32,"tag":52,"props":2491,"children":2493},{"className":2492},[],[2494],{"type":37,"value":2495},"dbt run --select state:modified+ → dbt test --select state:modified+",{"type":37,"value":2497},". Запускаются измененные модели + их зависимости downstream, затем тесты, только потом merge allowed.",{"type":32,"tag":40,"props":2499,"children":2501},{"id":2500},"оркестрация-airflow-prefect-dbt-cloud",[2502],{"type":37,"value":2503},"Оркестрация: Airflow, Prefect, dbt Cloud",{"type":32,"tag":33,"props":2505,"children":2506},{},[2507],{"type":37,"value":2508},"dbt сам по себе не оркестратор — вы schedule'ируете его через Airflow или Prefect. Пример Airflow DAG:",{"type":32,"tag":85,"props":2510,"children":2514},{"className":2511,"code":2512,"language":2513,"meta":16,"style":16},"language-python shiki shiki-themes github-dark","from airflow.providers.google.cloud.operators.bigquery import BigQueryInsertJobOperator\nfrom airflow.operators.bash import BashOperator\n\ndbt_run = BashOperator(\n    task_id='dbt_run',\n    bash_command='cd \u002Fopt\u002Fdbt && dbt run --profiles-dir .',\n    dag=dag\n)\n\ndbt_test = BashOperator(\n    task_id='dbt_test',\n    bash_command='cd \u002Fopt\u002Fdbt && dbt test',\n    dag=dag\n)\n\ndbt_run >> dbt_test\n","python",[2515],{"type":32,"tag":52,"props":2516,"children":2517},{"__ignoreMap":16},[2518,2541,2562,2569,2586,2608,2629,2646,2653,2660,2676,2696,2716,2731,2738,2745],{"type":32,"tag":95,"props":2519,"children":2520},{"class":97,"line":98},[2521,2526,2531,2536],{"type":32,"tag":95,"props":2522,"children":2523},{"style":432},[2524],{"type":37,"value":2525},"from",{"type":32,"tag":95,"props":2527,"children":2528},{"style":108},[2529],{"type":37,"value":2530}," airflow.providers.google.cloud.operators.bigquery ",{"type":32,"tag":95,"props":2532,"children":2533},{"style":432},[2534],{"type":37,"value":2535},"import",{"type":32,"tag":95,"props":2537,"children":2538},{"style":108},[2539],{"type":37,"value":2540}," BigQueryInsertJobOperator\n",{"type":32,"tag":95,"props":2542,"children":2543},{"class":97,"line":120},[2544,2548,2553,2557],{"type":32,"tag":95,"props":2545,"children":2546},{"style":432},[2547],{"type":37,"value":2525},{"type":32,"tag":95,"props":2549,"children":2550},{"style":108},[2551],{"type":37,"value":2552}," airflow.operators.bash ",{"type":32,"tag":95,"props":2554,"children":2555},{"style":432},[2556],{"type":37,"value":2535},{"type":32,"tag":95,"props":2558,"children":2559},{"style":108},[2560],{"type":37,"value":2561}," BashOperator\n",{"type":32,"tag":95,"props":2563,"children":2564},{"class":97,"line":134},[2565],{"type":32,"tag":95,"props":2566,"children":2567},{"emptyLinePlaceholder":1362},[2568],{"type":37,"value":1365},{"type":32,"tag":95,"props":2570,"children":2571},{"class":97,"line":158},[2572,2577,2581],{"type":32,"tag":95,"props":2573,"children":2574},{"style":108},[2575],{"type":37,"value":2576},"dbt_run ",{"type":32,"tag":95,"props":2578,"children":2579},{"style":432},[2580],{"type":37,"value":839},{"type":32,"tag":95,"props":2582,"children":2583},{"style":108},[2584],{"type":37,"value":2585}," BashOperator(\n",{"type":32,"tag":95,"props":2587,"children":2588},{"class":97,"line":176},[2589,2595,2599,2604],{"type":32,"tag":95,"props":2590,"children":2592},{"style":2591},"--shiki-default:#FFAB70",[2593],{"type":37,"value":2594},"    task_id",{"type":32,"tag":95,"props":2596,"children":2597},{"style":432},[2598],{"type":37,"value":839},{"type":32,"tag":95,"props":2600,"children":2601},{"style":152},[2602],{"type":37,"value":2603},"'dbt_run'",{"type":32,"tag":95,"props":2605,"children":2606},{"style":108},[2607],{"type":37,"value":572},{"type":32,"tag":95,"props":2609,"children":2610},{"class":97,"line":189},[2611,2616,2620,2625],{"type":32,"tag":95,"props":2612,"children":2613},{"style":2591},[2614],{"type":37,"value":2615},"    bash_command",{"type":32,"tag":95,"props":2617,"children":2618},{"style":432},[2619],{"type":37,"value":839},{"type":32,"tag":95,"props":2621,"children":2622},{"style":152},[2623],{"type":37,"value":2624},"'cd \u002Fopt\u002Fdbt && dbt run --profiles-dir .'",{"type":32,"tag":95,"props":2626,"children":2627},{"style":108},[2628],{"type":37,"value":572},{"type":32,"tag":95,"props":2630,"children":2631},{"class":97,"line":211},[2632,2637,2641],{"type":32,"tag":95,"props":2633,"children":2634},{"style":2591},[2635],{"type":37,"value":2636},"    dag",{"type":32,"tag":95,"props":2638,"children":2639},{"style":432},[2640],{"type":37,"value":839},{"type":32,"tag":95,"props":2642,"children":2643},{"style":108},[2644],{"type":37,"value":2645},"dag\n",{"type":32,"tag":95,"props":2647,"children":2648},{"class":97,"line":26},[2649],{"type":32,"tag":95,"props":2650,"children":2651},{"style":108},[2652],{"type":37,"value":985},{"type":32,"tag":95,"props":2654,"children":2655},{"class":97,"line":246},[2656],{"type":32,"tag":95,"props":2657,"children":2658},{"emptyLinePlaceholder":1362},[2659],{"type":37,"value":1365},{"type":32,"tag":95,"props":2661,"children":2662},{"class":97,"line":267},[2663,2668,2672],{"type":32,"tag":95,"props":2664,"children":2665},{"style":108},[2666],{"type":37,"value":2667},"dbt_test ",{"type":32,"tag":95,"props":2669,"children":2670},{"style":432},[2671],{"type":37,"value":839},{"type":32,"tag":95,"props":2673,"children":2674},{"style":108},[2675],{"type":37,"value":2585},{"type":32,"tag":95,"props":2677,"children":2678},{"class":97,"line":284},[2679,2683,2687,2692],{"type":32,"tag":95,"props":2680,"children":2681},{"style":2591},[2682],{"type":37,"value":2594},{"type":32,"tag":95,"props":2684,"children":2685},{"style":432},[2686],{"type":37,"value":839},{"type":32,"tag":95,"props":2688,"children":2689},{"style":152},[2690],{"type":37,"value":2691},"'dbt_test'",{"type":32,"tag":95,"props":2693,"children":2694},{"style":108},[2695],{"type":37,"value":572},{"type":32,"tag":95,"props":2697,"children":2698},{"class":97,"line":302},[2699,2703,2707,2712],{"type":32,"tag":95,"props":2700,"children":2701},{"style":2591},[2702],{"type":37,"value":2615},{"type":32,"tag":95,"props":2704,"children":2705},{"style":432},[2706],{"type":37,"value":839},{"type":32,"tag":95,"props":2708,"children":2709},{"style":152},[2710],{"type":37,"value":2711},"'cd \u002Fopt\u002Fdbt && dbt test'",{"type":32,"tag":95,"props":2713,"children":2714},{"style":108},[2715],{"type":37,"value":572},{"type":32,"tag":95,"props":2717,"children":2718},{"class":97,"line":314},[2719,2723,2727],{"type":32,"tag":95,"props":2720,"children":2721},{"style":2591},[2722],{"type":37,"value":2636},{"type":32,"tag":95,"props":2724,"children":2725},{"style":432},[2726],{"type":37,"value":839},{"type":32,"tag":95,"props":2728,"children":2729},{"style":108},[2730],{"type":37,"value":2645},{"type":32,"tag":95,"props":2732,"children":2733},{"class":97,"line":335},[2734],{"type":32,"tag":95,"props":2735,"children":2736},{"style":108},[2737],{"type":37,"value":985},{"type":32,"tag":95,"props":2739,"children":2740},{"class":97,"line":1368},[2741],{"type":32,"tag":95,"props":2742,"children":2743},{"emptyLinePlaceholder":1362},[2744],{"type":37,"value":1365},{"type":32,"tag":95,"props":2746,"children":2747},{"class":97,"line":1389},[2748,2752,2757],{"type":32,"tag":95,"props":2749,"children":2750},{"style":108},[2751],{"type":37,"value":2576},{"type":32,"tag":95,"props":2753,"children":2754},{"style":432},[2755],{"type":37,"value":2756},">>",{"type":32,"tag":95,"props":2758,"children":2759},{"style":108},[2760],{"type":37,"value":2761}," dbt_test\n",{"type":32,"tag":33,"props":2763,"children":2764},{},[2765],{"type":37,"value":2766},"Альтернатива — dbt Cloud (managed оркестрация, Web IDE, Slack алерты). Но большинство enterprise выбирают Airflow, потому что параллельно с dbt есть другие task'и: upstream API pull, downstream reverse ETL, snapshot таблицы.",{"type":32,"tag":33,"props":2768,"children":2769},{},[2770,2772,2778],{"type":37,"value":2771},"Стратегия schedule'ирования зависит от свежести данных. GA4 задерживается на 24 часа (processing_date ≠ event_date), Meta Ads API не real-time. Staging модели триггерятся свежестью источника — когда GA4 выгружает новую partition, ",{"type":32,"tag":52,"props":2773,"children":2775},{"className":2774},[],[2776],{"type":37,"value":2777},"stg_ga4_events",{"type":37,"value":2779}," refreshes, это распространяется на intermediate → mart цепь. Airflow sensor проверяет наличие новой partition BigQuery:",{"type":32,"tag":85,"props":2781,"children":2783},{"className":2511,"code":2782,"language":2513,"meta":16,"style":16},"wait_for_ga4 = BigQueryTableExistenceSensor(\n    task_id='wait_for_ga4_partition',\n    project_id='analytics_123456',\n    dataset_id='events_',\n    table_id=f\"events_{yesterday.strftime('%Y%m%d')}\",\n    poke_interval=300\n)\n",[2784],{"type":32,"tag":52,"props":2785,"children":2786},{"__ignoreMap":16},[2787,2804,2824,2845,2865,2930,2947],{"type":32,"tag":95,"props":2788,"children":2789},{"class":97,"line":98},[2790,2795,2799],{"type":32,"tag":95,"props":2791,"children":2792},{"style":108},[2793],{"type":37,"value":2794},"wait_for_ga4 ",{"type":32,"tag":95,"props":2796,"children":2797},{"style":432},[2798],{"type":37,"value":839},{"type":32,"tag":95,"props":2800,"children":2801},{"style":108},[2802],{"type":37,"value":2803}," BigQueryTableExistenceSensor(\n",{"type":32,"tag":95,"props":2805,"children":2806},{"class":97,"line":120},[2807,2811,2815,2820],{"type":32,"tag":95,"props":2808,"children":2809},{"style":2591},[2810],{"type":37,"value":2594},{"type":32,"tag":95,"props":2812,"children":2813},{"style":432},[2814],{"type":37,"value":839},{"type":32,"tag":95,"props":2816,"children":2817},{"style":152},[2818],{"type":37,"value":2819},"'wait_for_ga4_partition'",{"type":32,"tag":95,"props":2821,"children":2822},{"style":108},[2823],{"type":37,"value":572},{"type":32,"tag":95,"props":2825,"children":2826},{"class":97,"line":134},[2827,2832,2836,2841],{"type":32,"tag":95,"props":2828,"children":2829},{"style":2591},[2830],{"type":37,"value":2831},"    project_id",{"type":32,"tag":95,"props":2833,"children":2834},{"style":432},[2835],{"type":37,"value":839},{"type":32,"tag":95,"props":2837,"children":2838},{"style":152},[2839],{"type":37,"value":2840},"'analytics_123456'",{"type":32,"tag":95,"props":2842,"children":2843},{"style":108},[2844],{"type":37,"value":572},{"type":32,"tag":95,"props":2846,"children":2847},{"class":97,"line":158},[2848,2853,2857,2861],{"type":32,"tag":95,"props":2849,"children":2850},{"style":2591},[2851],{"type":37,"value":2852},"    dataset_id",{"type":32,"tag":95,"props":2854,"children":2855},{"style":432},[2856],{"type":37,"value":839},{"type":32,"tag":95,"props":2858,"children":2859},{"style":152},[2860],{"type":37,"value":627},{"type":32,"tag":95,"props":2862,"children":2863},{"style":108},[2864],{"type":37,"value":572},{"type":32,"tag":95,"props":2866,"children":2867},{"class":97,"line":176},[2868,2873,2877,2882,2887,2891,2896,2901,2906,2911,2916,2921,2926],{"type":32,"tag":95,"props":2869,"children":2870},{"style":2591},[2871],{"type":37,"value":2872},"    table_id",{"type":32,"tag":95,"props":2874,"children":2875},{"style":432},[2876],{"type":37,"value":839},{"type":32,"tag":95,"props":2878,"children":2879},{"style":432},[2880],{"type":37,"value":2881},"f",{"type":32,"tag":95,"props":2883,"children":2884},{"style":152},[2885],{"type":37,"value":2886},"\"events_",{"type":32,"tag":95,"props":2888,"children":2889},{"style":114},[2890],{"type":37,"value":1987},{"type":32,"tag":95,"props":2892,"children":2893},{"style":108},[2894],{"type":37,"value":2895},"yesterday.strftime(",{"type":32,"tag":95,"props":2897,"children":2898},{"style":152},[2899],{"type":37,"value":2900},"'%Y%m",{"type":32,"tag":95,"props":2902,"children":2903},{"style":114},[2904],{"type":37,"value":2905},"%d",{"type":32,"tag":95,"props":2907,"children":2908},{"style":152},[2909],{"type":37,"value":2910},"'",{"type":32,"tag":95,"props":2912,"children":2913},{"style":108},[2914],{"type":37,"value":2915},")",{"type":32,"tag":95,"props":2917,"children":2918},{"style":114},[2919],{"type":37,"value":2920},"}",{"type":32,"tag":95,"props":2922,"children":2923},{"style":152},[2924],{"type":37,"value":2925},"\"",{"type":32,"tag":95,"props":2927,"children":2928},{"style":108},[2929],{"type":37,"value":572},{"type":32,"tag":95,"props":2931,"children":2932},{"class":97,"line":189},[2933,2938,2942],{"type":32,"tag":95,"props":2934,"children":2935},{"style":2591},[2936],{"type":37,"value":2937},"    poke_interval",{"type":32,"tag":95,"props":2939,"children":2940},{"style":432},[2941],{"type":37,"value":839},{"type":32,"tag":95,"props":2943,"children":2944},{"style":114},[2945],{"type":37,"value":2946},"300\n",{"type":32,"tag":95,"props":2948,"children":2949},{"class":97,"line":211},[2950],{"type":32,"tag":95,"props":2951,"children":2952},{"style":108},[2953],{"type":37,"value":985},{"type":32,"tag":33,"props":2955,"children":2956},{},[2957],{"type":37,"value":2958},"Когда partition готова, dbt chain стартует. Этот паттерн решает проблему late-arriving data — API задержка не блокирует pipeline, она его ждет.",{"type":32,"tag":40,"props":2960,"children":2962},{"id":2961},"tradeoffs-что-dbt-не-решает",[2963],{"type":37,"value":2964},"Tradeoffs: что dbt не решает",{"type":32,"tag":33,"props":2966,"children":2967},{},[2968],{"type":37,"value":2969},"dbt — это transformation engine, не data loader. Кто загружает данные в BigQuery? Fivetran, Airbyte, custom Python скрипт. dbt предполагает, что сырые данные уже там. Паттерн ELT: Extract-Load-Transform. Отличие от ETL в том, что Transform происходит внутри warehouse'а. dbt отвечает за T, EL — это отдельный toolchain.",{"type":32,"tag":33,"props":2971,"children":2972},{},[2973],{"type":37,"value":2974},"dbt не поддерживает real-time streaming. Kafka → BigQuery streaming insert → dbt incremental model chain дает минутную задержку. Для sub-second latency (fraud detection, dynamic pricing) нужны stream processors — Flink, Spark Structured Streaming, Materialize. dbt для этого не подходит.",{"type":32,"tag":33,"props":2976,"children":2977},{},[2978],{"type":37,"value":2979},"Поддержка Python моделей в dbt (v1.3+) ограничена. Вы можете манипулировать pandas dataframe'ами, но тяжелый ML training dbt'де не делается. Типичный паттерн: feature engineering в dbt, model training в Vertex AI, inference в BigQuery ML. Python модель dbt:",{"type":32,"tag":85,"props":2981,"children":2983},{"className":2511,"code":2982,"language":2513,"meta":16,"style":16},"def model(dbt, session):\n    df = dbt.ref('stg_orders').to_pandas()\n    df['log_amount'] = np.log1p(df['order_amount'])\n    return df\n",[2984],{"type":32,"tag":52,"props":2985,"children":2986},{"__ignoreMap":16},[2987,3006,3033,3070],{"type":32,"tag":95,"props":2988,"children":2989},{"class":97,"line":98},[2990,2995,3001],{"type":32,"tag":95,"props":2991,"children":2992},{"style":432},[2993],{"type":37,"value":2994},"def",{"type":32,"tag":95,"props":2996,"children":2998},{"style":2997},"--shiki-default:#B392F0",[2999],{"type":37,"value":3000}," model",{"type":32,"tag":95,"props":3002,"children":3003},{"style":108},[3004],{"type":37,"value":3005},"(dbt, session):\n",{"type":32,"tag":95,"props":3007,"children":3008},{"class":97,"line":120},[3009,3014,3018,3023,3028],{"type":32,"tag":95,"props":3010,"children":3011},{"style":108},[3012],{"type":37,"value":3013},"    df ",{"type":32,"tag":95,"props":3015,"children":3016},{"style":432},[3017],{"type":37,"value":839},{"type":32,"tag":95,"props":3019,"children":3020},{"style":108},[3021],{"type":37,"value":3022}," dbt.ref(",{"type":32,"tag":95,"props":3024,"children":3025},{"style":152},[3026],{"type":37,"value":3027},"'stg_orders'",{"type":32,"tag":95,"props":3029,"children":3030},{"style":108},[3031],{"type":37,"value":3032},").to_pandas()\n",{"type":32,"tag":95,"props":3034,"children":3035},{"class":97,"line":134},[3036,3041,3046,3051,3055,3060,3065],{"type":32,"tag":95,"props":3037,"children":3038},{"style":108},[3039],{"type":37,"value":3040},"    df[",{"type":32,"tag":95,"props":3042,"children":3043},{"style":152},[3044],{"type":37,"value":3045},"'log_amount'",{"type":32,"tag":95,"props":3047,"children":3048},{"style":108},[3049],{"type":37,"value":3050},"] ",{"type":32,"tag":95,"props":3052,"children":3053},{"style":432},[3054],{"type":37,"value":839},{"type":32,"tag":95,"props":3056,"children":3057},{"style":108},[3058],{"type":37,"value":3059}," np.log1p(df[",{"type":32,"tag":95,"props":3061,"children":3062},{"style":152},[3063],{"type":37,"value":3064},"'order_amount'",{"type":32,"tag":95,"props":3066,"children":3067},{"style":108},[3068],{"type":37,"value":3069},"])\n",{"type":32,"tag":95,"props":3071,"children":3072},{"class":97,"line":158},[3073,3078],{"type":32,"tag":95,"props":3074,"children":3075},{"style":432},[3076],{"type":37,"value":3077},"    return",{"type":32,"tag":95,"props":3079,"children":3080},{"style":108},[3081],{"type":37,"value":3082}," df\n",{"type":32,"tag":3084,"props":3085,"children":3086},"style",{},[3087],{"type":37,"value":3088},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":16,"searchDepth":134,"depth":134,"links":3090},[3091,3092,3093,3094,3095,3096,3097],{"id":42,"depth":120,"text":45},{"id":402,"depth":120,"text":405},{"id":1104,"depth":120,"text":1107},{"id":1522,"depth":120,"text":1525},{"id":1897,"depth":120,"text":1900},{"id":2500,"depth":120,"text":2503},{"id":2961,"depth":120,"text":2964},"markdown","content:ru:data:dbt-bigquery-sovremenniy-marketing-data-stack.md","content","ru\u002Fdata\u002Fdbt-bigquery-sovremenniy-marketing-data-stack.md","ru\u002Fdata\u002Fdbt-bigquery-sovremenniy-marketing-data-stack","md",1782050758084]