{"id":488366,"date":"2026-07-23T17:50:51","date_gmt":"2026-07-23T17:50:51","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=488366"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=488366","title":{"rendered":"DE. \u041f\u0443\u0442\u044c \u0444\u0430\u0439\u043b\u0430 \u043f\u043e \u0441\u043b\u043e\u044f\u043c"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u043c\u0438\u0442\u0440\u0438\u0439, \u044f Data Engineer. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0447\u0443 \u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0439 BI-\u0432\u0438\u0442\u0440\u0438\u043d\u043e\u0439 \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0434\u0430\u0436\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043d\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u041f\u043e\u0433\u043d\u0430\u043b\u0438!<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0438\u0448\u044c \u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0434\u0430\u0448\u0431\u043e\u0440\u0434, \u043f\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0432\u0438\u0434\u0435\u043d. \u0415\u0441\u0442\u044c \u0434\u0430\u0442\u0430, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0438 \u0441\u0443\u043c\u043c\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0438. \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0441\u043b\u0430\u043b \u0444\u0430\u0439\u043b, \u0444\u0430\u0439\u043b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0433\u0440\u0430\u0444\u0438\u043a.<\/p>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 CSV \u0443\u0441\u043f\u0435\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0435\u0449\u0451 \u0434\u043e BI. \u0412 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0441\u0443\u043c\u043c\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043a\u0430\u043a <code>1299.90<\/code>, \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u0430\u043a <code>\"1 299,90\"<\/code>. \u0423 \u0437\u0430\u043a\u0430\u0437\u0430 \u043d\u0435\u0442 \u0434\u0430\u0442\u044b, \u043e\u0434\u0438\u043d <code>order_id<\/code> \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u0430 \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0438\u0439 \u0444\u0430\u0439\u043b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0435\u0442 \u0435\u0449\u0451 \u0440\u0430\u0437. \u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0443\u043c\u043c\u0430, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0438 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f, \u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0439.<\/p>\n<p>\u0422\u0430\u043a \u0432\u043e\u0442, \u0442\u0435\u043f\u0435\u0440\u044c \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443 &#8212; \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043c \u043e\u0434\u0438\u043d <code>orders.csv<\/code> \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435:<\/p>\n<pre><code>CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 Docker:<\/p>\n<ul>\n<li>\n<p>MinIO<\/p>\n<\/li>\n<li>\n<p>Postgres <\/p>\n<\/li>\n<li>\n<p>Airflow<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 11 \u0441\u0442\u0440\u043e\u043a (\u0442\u0443\u0442 \u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u043b\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u0438). <\/p>\n<p>\u0414\u043e CORE \u0434\u043e\u0445\u043e\u0434\u044f\u0442 7, \u0435\u0449\u0451 4 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 rejects \u0441 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439. \u0412\u0430\u043b\u043e\u0432\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0440\u0430\u0432\u043d\u0430 <code>4720.30<\/code>, \u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 <code>2200.30<\/code>.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0436\u0443, \u0433\u0434\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u044e\u0442 \u0441\u0443\u043c\u043c\u0443.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/118\/ddf\/8f8\/118ddf8f8628460faeb973b6aefe5847.png\" alt=\"\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI.\" title=\"\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI.\" width=\"1672\" height=\"941\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/118\/ddf\/8f8\/118ddf8f8628460faeb973b6aefe5847.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/118\/ddf\/8f8\/118ddf8f8628460faeb973b6aefe5847.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 <code>CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI<\/code>.<\/figcaption><\/div>\n<\/figure>\n<h3>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u0432\u0430\u0448\u0435\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430<\/h3>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u0443\u044e, \u0447\u0442\u043e \u043d\u0435 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 DWH \u0435\u0441\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e RAW, STG, CORE \u0438 MARTS. \u041d\u0430 \u043e\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 RAW \u043b\u0435\u0436\u0438\u0442 \u0432 S3, \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u044d\u0442\u043e \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 Postgres. STG \u0438 CORE \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442, \u0430 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u0443 \u0432\u0441\u0435\u0445 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443, \u043d\u043e \u0441\u043c\u044b\u0441\u043b \u043f\u043b\u044e\u0441 \u043c\u0438\u043d\u0443\u0441 \u043e\u0434\u0438\u043d.<\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043e\u0434\u043d\u0443 \u0438\u0437 \u0447\u0430\u0441\u0442\u044b\u0445 \u0441\u0445\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>RAW \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438;<\/p>\n<\/li>\n<li>\n<p>STG \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u043c\u0443 \u0432\u0438\u0434\u0443;<\/p>\n<\/li>\n<li>\n<p>CORE \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430;<\/p>\n<\/li>\n<li>\n<p>MARTS \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f;<\/p>\n<\/li>\n<li>\n<p>BI \u0447\u0438\u0442\u0430\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0432\u0438\u0442\u0440\u0438\u043d\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0441 \u043f\u043e\u043b\u0435\u043c \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438 \u0433\u0434\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c.<\/p>\n<h3>\u0427\u0442\u043e \u043b\u0435\u0436\u0438\u0442 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c CSV<\/h3>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0432\u0437\u044f\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0444\u0430\u0439\u043b \u0438 \u0442\u0430\u043a\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438:<\/p>\n<pre><code>order_id,customer_id,order_date,status,amount1001,C001,2026-07-18,paid,1299.901002,C002,2026-07-18,paid,\"1 299,90\"1003,C003,,paid,750.001004,C004,2026-07-19,created,500.001005,C005,2026-07-19,refunded,800.001006,C006,2026-07-20,paid,not_a_number1007,C007,2026-07-20,paid,100.001007,C007,2026-07-20,paid,100.001008,C008,2026-07-20,cancelled,420.001009,C009,20.07.2026,paid,\"300,50\"1010,C010,2026-07-21,paid,-50.00<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0437\u0434\u0435\u0441\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u044b \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435:<\/p>\n<ul>\n<li>\n<p>\u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0434\u0430\u0442\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0441\u0443\u043c\u043c\u044b;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0443\u0441\u0442\u0430\u044f \u0434\u0430\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u043a\u0441\u0442 \u0432\u043c\u0435\u0441\u0442\u043e \u0447\u0438\u0441\u043b\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 <code>order_id<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043f\u043e\u0434\u0445\u043e\u0434 \u00ab\u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u00bb \u0443\u0436\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \ud83d\ude42<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/70d\/4b9\/a77\/70d4b9a77b3bb7972f7c900955b3cdb5.png\" alt=\"orders.csv \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438\" title=\"orders.csv \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438\" width=\"582\" height=\"350\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/70d\/4b9\/a77\/70d4b9a77b3bb7972f7c900955b3cdb5.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/70d\/4b9\/a77\/70d4b9a77b3bb7972f7c900955b3cdb5.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><code>orders.csv<\/code> \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438<\/figcaption><\/div>\n<\/figure>\n<h3>RAW: \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 DAG \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 SHA-256 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0434\u0443\u0431\u043b\u0435\u0439 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u0434\u0432\u0443\u043c\u044f \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u0438\u043b\u0438, \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 \u0441 \u043f\u0440\u0435\u0436\u043d\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c.<\/p>\n<pre><code class=\"python\">file_bytes = source_file.read_bytes()file_sha256 = hashlib.sha256(file_bytes).hexdigest()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u0435\u0435\u0441\u0442\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a:<\/p>\n<pre><code class=\"sql\">select object_keyfrom raw.habr_file_registrywhere file_sha256 = %s;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0445\u0435\u0448\u0430 \u0435\u0449\u0451 \u043d\u0435\u0442, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 CSV \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 MinIO. <br \/>\u0412 \u043a\u043b\u044e\u0447 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u044f \u0442\u043e\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e SHA-256:<\/p>\n<pre><code>raw\/habr\/orders\/sha256=&lt;hash&gt;\/orders.csv<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 Postgres \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c:<\/p>\n<pre><code>file_name, file_sha256, object_key, source_row_count,valid_row_count, rejected_count, status, loaded_at<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0435\u0435\u0441\u0442\u0440 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>orders.csv | 11 | 7 | 4 | completed<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b: \u043a\u0430\u043a\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u0438\u0448\u0451\u043b, \u043a\u043e\u0433\u0434\u0430 \u0435\u0433\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432 \u043d\u0451\u043c \u0431\u044b\u043b\u043e \u0441\u0442\u0440\u043e\u043a \u0438 \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b.<\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6f6\/4e0\/c01\/6f64e0c016dc04cb150864c5b2ed2626.png\" alt=\"\u041e\u0431\u044a\u0435\u043a\u0442 orders.csv \u0432 MinIO Console, \u0431\u0430\u043a\u0435\u0442 raw, \u043f\u0443\u0442\u044c\" title=\"\u041e\u0431\u044a\u0435\u043a\u0442 orders.csv \u0432 MinIO Console, \u0431\u0430\u043a\u0435\u0442 raw, \u043f\u0443\u0442\u044c\" width=\"1537\" height=\"277\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/6f6\/4e0\/c01\/6f64e0c016dc04cb150864c5b2ed2626.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6f6\/4e0\/c01\/6f64e0c016dc04cb150864c5b2ed2626.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041e\u0431\u044a\u0435\u043a\u0442 <code>orders.csv<\/code> \u0432 MinIO Console, \u0431\u0430\u043a\u0435\u0442 <code>raw<\/code>, \u043f\u0443\u0442\u044c<\/figcaption><\/div>\n<\/figure>\n<h3>STG: \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0440\u044f\u0434\u043e\u043a<\/h3>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0447\u0438\u0442\u0430\u0435\u0442 \u0444\u0430\u0439\u043b \u0443\u0436\u0435 \u0438\u0437 RAW-\u0431\u0430\u043a\u0435\u0442\u0430. \u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b.<\/p>\n<p>\u0421 \u0434\u0430\u0442\u0430\u043c\u0438 \u0432\u0441\u0451 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u044b \u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430:<\/p>\n<pre><code class=\"python\">def parse_date(value: str):    for pattern in (\"%Y-%m-%d\", \"%d.%m.%Y\"):        try:            return datetime.strptime(value.strip(), pattern).date()        except ValueError:            continue    raise ValueError(\"invalid_order_date\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421 \u0441\u0443\u043c\u043c\u0430\u043c\u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435. \u041f\u0440\u043e\u0431\u0435\u043b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u043c \u0442\u044b\u0441\u044f\u0447, \u0430 \u0437\u0430\u043f\u044f\u0442\u0430\u044f \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u044b\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u043c. \u041f\u043e\u0441\u043b\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <code>Decimal<\/code>, \u0430 \u043d\u0435 \u0432 <code>float<\/code>:<\/p>\n<pre><code class=\"python\">def parse_amount(value: str) -&gt; Decimal:    normalized = value.strip().replace(\" \", \"\")    if \",\" in normalized:        normalized = normalized.replace(\",\", \".\")    amount = Decimal(normalized).quantize(Decimal(\"0.01\"))    if amount &lt;= 0:        raise ValueError(\"non_positive_amount\")    return amount<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u043f\u043e\u043b\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0441\u043b\u0443\u0447\u0430\u0439, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0447\u0438\u0441\u043b\u0435 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u0447\u043a\u0430 \u0438 \u0437\u0430\u043f\u044f\u0442\u0430\u044f.<\/p>\n<p>\u041e\u0448\u0438\u0431\u043e\u0447\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u044f \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u044e. \u041e\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 <code>stg.habr_orders_rejects<\/code> \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0441\u0442\u0440\u043e\u043a\u0438, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c JSON \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u043e\u0442\u043a\u0430\u0437\u0430.<\/p>\n<p>\u041f\u043e \u043d\u0430\u0448\u0435\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0435\u0442\u044b\u0440\u0435 rejects:<\/p>\n<pre><code>4  | invalid_order_date         | order_id=10037  | invalid_amount             | order_id=10069  | duplicate_order_id_in_file | order_id=100712 | non_positive_amount        | order_id=1010<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u0431\u0430\u043b\u0430\u043d\u0441:<\/p>\n<pre><code>11 \u0441\u0442\u0440\u043e\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 = 7 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 + 4 \u043e\u0442\u043a\u043b\u043e\u043d\u0451\u043d\u043d\u044b\u0445<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0441\u0435 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0438\u0434\u043d\u044b \u0441 \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c\u0438 \u0431\u0440\u0430\u043a\u0430.<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e \u0434\u0443\u0431\u043b\u044c. <code>DISTINCT<\/code> \u0443\u0431\u0440\u0430\u043b \u0431\u044b \u0432\u0442\u043e\u0440\u0443\u044e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u043d\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0443\u0431\u043b\u044f \u043f\u043e\u0442\u0435\u0440\u044f\u043b\u0430\u0441\u044c \u0431\u044b. \u0417\u0434\u0435\u0441\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 <code>order_id<\/code> \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432 rejects. \u0412\u043e\u043e\u0431\u0449\u0435 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0430\u043a\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439, \u0442\u043e \u0435\u0441\u0442\u044c \u043e\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/502\/e7d\/795\/502e7d7952c199e270a784c017bce2bf.png\" alt=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a stg.habr_orders_rejects\" title=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a stg.habr_orders_rejects\" width=\"620\" height=\"137\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/502\/e7d\/795\/502e7d7952c199e270a784c017bce2bf.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/502\/e7d\/795\/502e7d7952c199e270a784c017bce2bf.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a <code>stg.habr_orders_rejects<\/code><\/figcaption><\/div>\n<\/figure>\n<div class=\"floating-image\">\n<p>\u041f\u043e\u0441\u043b\u0435 STG \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438: \u0434\u0430\u0442\u0430 \u0441\u0442\u0430\u043b\u0430 \u0434\u0430\u0442\u043e\u0439, \u0441\u0443\u043c\u043c\u0430 \u0447\u0438\u0441\u043b\u043e\u043c, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u044b, \u0434\u0443\u0431\u043b\u0438 \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u044b.<\/p>\n<\/div>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u0441\u0443\u043c\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u0430 \u0435\u0449\u0451 \u043d\u0435 \u0440\u0430\u0432\u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0435. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430:<\/p>\n<pre><code class=\"sql\">case    when order_status = 'paid' then amount    when order_status = 'refunded' then -amount    else 0end as net_revenue<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a:<\/p>\n<pre><code>paid      -&gt; \u0441\u0443\u043c\u043c\u0430 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u044b\u0440\u0443\u0447\u043a\u0443refunded  -&gt; \u0441\u0443\u043c\u043c\u0430 \u0432\u044b\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044fcreated   -&gt; \u0437\u0430\u043a\u0430\u0437 \u0435\u0449\u0451 \u043d\u0435 \u043e\u043f\u043b\u0430\u0447\u0435\u043d, \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 \u043d\u0443\u043b\u044ecancelled -&gt; \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0439 \u0437\u0430\u043a\u0430\u0437 \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u044b\u0440\u0443\u0447\u043a\u0443<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 CORE \u044f \u0445\u0440\u0430\u043d\u044e \u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0441\u0443\u043c\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u0430, \u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u0443\u044e \u0432\u044b\u0440\u0443\u0447\u043a\u0443:<\/p>\n<pre><code>order_id | status    | gross_amount | net_revenue1001     | paid      | 1299.90      | 1299.901004     | created   | 500.00       | 0.001005     | refunded  | 800.00       | -800.001008     | cancelled | 420.00       | 0.00<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0443\u043c\u043c\u0430 \u0438\u0437 CSV \u0438 \u0441\u0443\u043c\u043c\u0430 \u043d\u0430 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0435 \u043c\u043e\u0433\u0443\u0442 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c. \u042d\u0442\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0448\u0438\u0431\u043a\u0430. \u0418\u043d\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c. \u0427\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0443\u0442 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u043e\u0439 (\u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0432\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0435!).<\/p>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cec\/673\/342\/cec67334278fbc4f30be43fc772d3164.png\" alt=\"\u0422\u0430\u0431\u043b\u0438\u0446\u0430 core.habr_orders: gross_amount, net_revenue \u0438 business_rule.\" title=\"\u0422\u0430\u0431\u043b\u0438\u0446\u0430 core.habr_orders: gross_amount, net_revenue \u0438 business_rule.\" width=\"777\" height=\"210\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/cec\/673\/342\/cec67334278fbc4f30be43fc772d3164.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cec\/673\/342\/cec67334278fbc4f30be43fc772d3164.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 <code>core.habr_orders<\/code>: <code>gross_amount<\/code>, <code>net_revenue<\/code> \u0438 <code>business_rule<\/code>.<\/figcaption><\/div>\n<\/figure>\n<h3>MARTS: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435<\/h3>\n<p>\u0412\u0438\u0442\u0440\u0438\u043d\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441: \u043a\u0430\u043a\u0430\u044f \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u0431\u044b\u043b\u0430 \u043f\u043e \u0434\u043d\u044f\u043c. \u0415\u0451 \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u043e\u0439 \u0444\u0440\u0430\u0437\u043e\u0439:<\/p>\n<blockquote>\n<p>\u041e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d\u043e\u043c\u0443 \u0434\u043d\u044e \u0437\u0430\u043a\u0430\u0437\u0430.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u044f \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"sql\">select    order_date,    count(*) as orders_count,    count(*) filter (where order_status = 'paid') as paid_orders,    count(*) filter (where order_status = 'refunded') as refunded_orders,    sum(gross_amount) as gross_amount,    sum(net_revenue) as net_revenuefrom core.habr_ordersgroup by order_date;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<pre><code>order_date  | orders | gross_amount | net_revenue2026-07-18  | 2      | 2599.80      | 2599.802026-07-19  | 2      | 1300.00      | -800.002026-07-20  | 3      | 820.50       | 400.50<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e:<\/p>\n<pre><code>gross_amount = 4720.30net_revenue  = 2200.30<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c, \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u043c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u044b\u043c \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438. \u0415\u0441\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0432\u0438\u0442\u0440\u0438\u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043b\u043e\u043d\u043a\u0443 <code>amount<\/code>, \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0441\u044f\u0446 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0430 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442.<\/p>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0437\u0434\u0435\u0441\u044c \u0447\u0430\u0441\u0442\u043e \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0449\u0451 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: JOIN \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u0438\u043b\u0438 \u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439 \u0440\u0430\u0437\u043c\u043d\u043e\u0436\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0434 <code>SUM<\/code> \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u0435\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043a\u0430\u0440\u0434\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f (\u043a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e JOIN \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c).<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f9f\/e16\/dbb\/f9fe16dbbbc7dfb553715ac12de0c420.png\" alt=\"\u0413\u0440\u0430\u0444\u0438\u043a \u0432 Metabase\" title=\"\u0413\u0440\u0430\u0444\u0438\u043a \u0432 Metabase\" width=\"1887\" height=\"812\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/f9f\/e16\/dbb\/f9fe16dbbbc7dfb553715ac12de0c420.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f9f\/e16\/dbb\/f9fe16dbbbc7dfb553715ac12de0c420.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0413\u0440\u0430\u0444\u0438\u043a \u0432 Metabase<\/figcaption><\/div>\n<\/figure>\n<h3>Airflow: \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0448\u0430\u0433\u043e\u0432 \u0438 \u043c\u0435\u0441\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0438<\/h3>\n<p>DAG \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0448\u0435\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447:<\/p>\n<pre><code>prepare_lab  -&gt; store_file_in_raw  -&gt; clean_to_stg  -&gt; apply_business_rules_to_core  -&gt; build_daily_mart  -&gt; check_pipeline<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Airflow \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0448\u0430\u0433\u0438 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u0438 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435.<\/p>\n<p>\u0422\u0430\u043a\u043e\u0439 \u0433\u0440\u0430\u0444 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0435\u0449\u0451 \u0438 \u0434\u043b\u044f \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438:<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043d\u0435 \u043f\u043e\u043f\u0430\u043b \u0432 MinIO, \u0441\u043c\u043e\u0442\u0440\u0438\u043c <code>store_file_in_raw<\/code>. <\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0443\u0448\u043b\u0438 \u0432 rejects, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c <code>clean_to_stg<\/code>. <\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 CORE \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f, \u0430 \u0441\u0443\u043c\u043c\u0430 \u0432\u0438\u0442\u0440\u0438\u043d\u044b \u0440\u0430\u0437\u043e\u0448\u043b\u0430\u0441\u044c, \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 <code>apply_business_rules_to_core<\/code>, <code>build_daily_mart<\/code> \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"bordered full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/488\/c56\/c3c\/488c56c3c217f935dfe0b6d29df5c14e.png\" alt=\"\u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 DAG\" title=\"\u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 DAG\" width=\"1418\" height=\"270\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/488\/c56\/c3c\/488c56c3c217f935dfe0b6d29df5c14e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/488\/c56\/c3c\/488c56c3c217f935dfe0b6d29df5c14e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 DAG<\/figcaption><\/div>\n<\/figure>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e DAG<\/h3>\n<p>\u0417\u0435\u043b\u0451\u043d\u044b\u0439 DAG \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438\u0441\u044c. \u041d\u043e \u043c\u044b \u0436\u0435 \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0432\u043d\u043e \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432\u0441\u0435 \u043e\u0442\u0431\u0435\u0436\u0430\u043b\u043e \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u043f\u0438\u0442\u044c \u043a\u043e\u0444\u0435.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0448\u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a:<\/p>\n<pre><code>raw_row_balance                    11 = 11no_duplicate_order_ids_in_stg       0 = 0no_null_required_fields_in_stg      0 = 0stg_to_core_row_count               7 = 7core_to_mart_net_revenue      2200.30 = 2200.30sample_expected_net_revenue   2200.30 = 2200.30<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043f\u0435\u0440\u0435\u0447\u043d\u0435\u043c \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0412 \u043b\u043e\u0433\u0430\u0445 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f actual, expected \u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0441 \u0436\u0451\u0441\u0442\u043a\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u043e\u0439 \u044f \u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u043b \u0441\u0432\u0435\u0440\u043a\u043e\u0439 \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u043e\u043c \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c. \u0417\u0434\u0435\u0441\u044c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u0442\u0430\u0441\u0435\u0442 \u0438\u0433\u0440\u0443\u0448\u0435\u0447\u043d\u044b\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u043d\u0430\u0435\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/333\/ea5\/2a0\/333ea52a0eff24c71c28f8e8a43bd57d.png\" alt=\"\u041b\u043e\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 check_pipeline \u0441 \u0448\u0435\u0441\u0442\u044c\u044e passed=True\" title=\"\u041b\u043e\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 check_pipeline \u0441 \u0448\u0435\u0441\u0442\u044c\u044e passed=True\" width=\"1341\" height=\"230\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/333\/ea5\/2a0\/333ea52a0eff24c71c28f8e8a43bd57d.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/333\/ea5\/2a0\/333ea52a0eff24c71c28f8e8a43bd57d.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041b\u043e\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 <code>check_pipeline<\/code> \u0441 \u0448\u0435\u0441\u0442\u044c\u044e <code>passed=True<\/code><\/figcaption><\/div>\n<\/figure>\n<h3>\u0427\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442, \u0435\u0441\u043b\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0448\u043b\u0451\u0442 \u0442\u043e\u0442 \u0436\u0435 \u0444\u0430\u0439\u043b \u0432\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0437<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e DAG \u0435\u0449\u0451 \u0440\u0430\u0437, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 <code>orders.csv<\/code>.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 <code>prepare_lab<\/code> \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, \u0430 <code>store_file_in_raw<\/code> \u043d\u0430\u0445\u043e\u0434\u0438\u0442 SHA-256 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <code>skipped<\/code>. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u043e\u0436\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f. \u0412 RAW \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043f\u0438\u044f, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e.<\/p>\n<p>\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0440\u0435\u0448\u0435\u043d\u0438\u0438. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435.<\/p>\n<p>\u0422\u0430\u043a\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0437\u0430\u0449\u0438\u0442\u0430 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430. \u0412 production \u0435\u0449\u0451 \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438: \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043f\u0435\u0440\u0435\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c, \u043a\u0430\u043a \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u0438 \u043a\u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0430\u0432\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043d\u0435 \u043b\u043e\u043c\u0430\u0435\u0442 \u043d\u0430\u043c \u0446\u0438\u0444\u0440\u044b \u0438 \u0432\u044b\u0440\u0443\u0447\u043a\u0443.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/60c\/b98\/d6c\/60cb98d6cbfc7466a9b95e838d6903d2.png\" alt=\"\u0412\u0442\u043e\u0440\u043e\u0439 DAG-run: store_file_in_raw \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043a\u0430\u043a skipped.\" title=\"\u0412\u0442\u043e\u0440\u043e\u0439 DAG-run: store_file_in_raw \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043a\u0430\u043a skipped.\" width=\"1407\" height=\"230\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/60c\/b98\/d6c\/60cb98d6cbfc7466a9b95e838d6903d2.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/60c\/b98\/d6c\/60cb98d6cbfc7466a9b95e838d6903d2.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0412\u0442\u043e\u0440\u043e\u0439 DAG-run: <code>store_file_in_raw<\/code> \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043a\u0430\u043a <code>skipped<\/code>.<\/figcaption><\/div>\n<\/figure>\n<h3>\u0427\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432 \u0441\u0432\u043e\u0451\u043c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0435<\/h3>\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u044b\u043b\u043e \u0432\u0441\u0435\u0433\u043e 11 \u0441\u0442\u0440\u043e\u043a, \u043d\u043e \u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0442\u0435 \u0436\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u0441\u043e\u0432\u043f\u0430\u043b\u043e \u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0432 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0435 \u0441 \u0441\u0443\u043c\u043c\u043e\u0439 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 \u0438 \u043e\u0442\u043a\u043b\u043e\u043d\u0451\u043d\u043d\u044b\u0445;<\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u0442\u044c \u043b\u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e reject;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430 \u043a\u0430\u043a\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u0442\u0438\u043f\u044b \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043e\u0432\u043b\u0438\u044f\u043b\u0438 \u043d\u0430 \u0438\u0442\u043e\u0433\u043e\u0432\u0443\u044e \u0441\u0443\u043c\u043c\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043b\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0443\u0431\u043b\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0432\u0442\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0451\u0432 \u0438 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f (\u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e) &#8212; \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 MinIO \u0438 Airflow, \u0432 \u0434\u0440\u0443\u0433\u043e\u043c S3 \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u043f\u0430\u0439\u043f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u043b \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c, \u043e\u0442\u043a\u0443\u0434\u0430 \u0432\u0437\u044f\u043b\u0430\u0441\u044c \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043a\u0443\u0434\u0430 \u043f\u0440\u043e\u043f\u0430\u043b\u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0446\u0438\u0444\u0440\u0430 \u0432 BI \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043a\u0430\u043a \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0432 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445. \u041a\u0443\u0434\u0430 \u0432\u044b \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0435 \u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434, \u043a\u0430\u043a \u0441\u0432\u0435\u0440\u044f\u0435\u0442\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0438 \u0434\u0435\u043d\u044c\u0433\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u043e\u044f\u043c\u0438 \u0438 \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0444\u0430\u0439\u043b\u0430? \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445. \u0415\u0441\u043b\u0438 \u0442\u0435\u043c\u0430 \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0438\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a Spark jobs \u0447\u0435\u0440\u0435\u0437 Airflow.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u044f \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c, \u0437\u0430\u0445\u043e\u0434\u0438\u0442\u0435 \u0432 \u043c\u043e\u0439 \u0431\u043b\u043e\u0433 <a href=\"https:\/\/t.me\/kuzmin_dmitry91\" rel=\"noopener noreferrer nofollow\">https:\/\/t.me\/kuzmin_dmitry91<\/a>.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1062446\/\">https:\/\/habr.com\/ru\/articles\/1062446\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u043c\u0438\u0442\u0440\u0438\u0439, \u044f Data Engineer. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0447\u0443 \u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0439 BI-\u0432\u0438\u0442\u0440\u0438\u043d\u043e\u0439 \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0434\u0430\u0436\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043d\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u041f\u043e\u0433\u043d\u0430\u043b\u0438!\u041a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0438\u0448\u044c \u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0434\u0430\u0448\u0431\u043e\u0440\u0434, \u043f\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0432\u0438\u0434\u0435\u043d. \u0415\u0441\u0442\u044c \u0434\u0430\u0442\u0430, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0438 \u0441\u0443\u043c\u043c\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0438. \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0441\u043b\u0430\u043b \u0444\u0430\u0439\u043b, \u0444\u0430\u0439\u043b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0433\u0440\u0430\u0444\u0438\u043a.\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 CSV \u0443\u0441\u043f\u0435\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0435\u0449\u0451 \u0434\u043e BI. \u0412 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0441\u0443\u043c\u043c\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043a\u0430\u043a 1299.90, \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u0430\u043a &#171;1 299,90&#187;. \u0423 \u0437\u0430\u043a\u0430\u0437\u0430 \u043d\u0435\u0442 \u0434\u0430\u0442\u044b, \u043e\u0434\u0438\u043d order_id \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u0430 \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0438\u0439 \u0444\u0430\u0439\u043b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0435\u0442 \u0435\u0449\u0451 \u0440\u0430\u0437. \u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0443\u043c\u043c\u0430, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0438 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f, \u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0439.\u0422\u0430\u043a \u0432\u043e\u0442, \u0442\u0435\u043f\u0435\u0440\u044c \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443 &#8212; \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043c \u043e\u0434\u0438\u043d orders.csv \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435:CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI\u0414\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 Docker:MinIOPostgres Airflow\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 11 \u0441\u0442\u0440\u043e\u043a (\u0442\u0443\u0442 \u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u043b\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u0438). \u0414\u043e CORE \u0434\u043e\u0445\u043e\u0434\u044f\u0442 7, \u0435\u0449\u0451 4 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 rejects \u0441 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439. \u0412\u0430\u043b\u043e\u0432\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0440\u0430\u0432\u043d\u0430 4720.30, \u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 2200.30.\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0436\u0443, \u0433\u0434\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u044e\u0442 \u0441\u0443\u043c\u043c\u0443.\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 CSV -&gt; RAW -&gt; STG -&gt; CORE -&gt; MARTS -&gt; BI.\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u0432\u0430\u0448\u0435\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\u0421\u0440\u0430\u0437\u0443 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u0443\u044e, \u0447\u0442\u043e \u043d\u0435 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 DWH \u0435\u0441\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e RAW, STG, CORE \u0438 MARTS. \u041d\u0430 \u043e\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 RAW \u043b\u0435\u0436\u0438\u0442 \u0432 S3, \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u044d\u0442\u043e \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 Postgres. STG \u0438 CORE \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442, \u0430 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u0443 \u0432\u0441\u0435\u0445 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443, \u043d\u043e \u0441\u043c\u044b\u0441\u043b \u043f\u043b\u044e\u0441 \u043c\u0438\u043d\u0443\u0441 \u043e\u0434\u0438\u043d.\u0417\u0434\u0435\u0441\u044c \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043e\u0434\u043d\u0443 \u0438\u0437 \u0447\u0430\u0441\u0442\u044b\u0445 \u0441\u0445\u0435\u043c:RAW \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438;STG \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u043c\u0443 \u0432\u0438\u0434\u0443;CORE \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430;MARTS \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f;BI \u0447\u0438\u0442\u0430\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0432\u0438\u0442\u0440\u0438\u043d\u0443.\u0422\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0441 \u043f\u043e\u043b\u0435\u043c \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438 \u0433\u0434\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c.\u0427\u0442\u043e \u043b\u0435\u0436\u0438\u0442 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c CSV\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0432\u0437\u044f\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0444\u0430\u0439\u043b \u0438 \u0442\u0430\u043a\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438:order_id,customer_id,order_date,status,amount1001,C001,2026-07-18,paid,1299.901002,C002,2026-07-18,paid,&#187;1 299,90&#8243;1003,C003,,paid,750.001004,C004,2026-07-19,created,500.001005,C005,2026-07-19,refunded,800.001006,C006,2026-07-20,paid,not_a_number1007,C007,2026-07-20,paid,100.001007,C007,2026-07-20,paid,100.001008,C008,2026-07-20,cancelled,420.001009,C009,20.07.2026,paid,&#187;300,50&#8243;1010,C010,2026-07-21,paid,-50.00\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0437\u0434\u0435\u0441\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u044b \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435:\u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0434\u0430\u0442\u044b;\u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0441\u0443\u043c\u043c\u044b;\u043f\u0443\u0441\u0442\u0430\u044f \u0434\u0430\u0442\u0430;\u0442\u0435\u043a\u0441\u0442 \u0432\u043c\u0435\u0441\u0442\u043e \u0447\u0438\u0441\u043b\u0430;\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 order_id;\u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430;\u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0443.\u0412 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043f\u043e\u0434\u0445\u043e\u0434 \u00ab\u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u00bb \u0443\u0436\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 :)orders.csv \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438RAW: \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 DAG \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 SHA-256 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0434\u0443\u0431\u043b\u0435\u0439 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u0434\u0432\u0443\u043c\u044f \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u0438\u043b\u0438, \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 \u0441 \u043f\u0440\u0435\u0436\u043d\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c.file_bytes = source_file.read_bytes()file_sha256 = hashlib.sha256(file_bytes).hexdigest()\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u0435\u0435\u0441\u0442\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a:select object_keyfrom raw.habr_file_registrywhere file_sha256 = %s;\u0415\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0445\u0435\u0448\u0430 \u0435\u0449\u0451 \u043d\u0435\u0442, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 CSV \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 MinIO. \u0412 \u043a\u043b\u044e\u0447 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u044f \u0442\u043e\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e SHA-256:raw\/habr\/orders\/sha256=&lt;hash&gt;\/orders.csv\u0412 Postgres \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c:file_name, file_sha256, object_key, source_row_count,valid_row_count, rejected_count, status, loaded_at\u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0435\u0435\u0441\u0442\u0440 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:orders.csv | 11 | 7 | 4 | completed\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b: \u043a\u0430\u043a\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u0438\u0448\u0451\u043b, \u043a\u043e\u0433\u0434\u0430 \u0435\u0433\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432 \u043d\u0451\u043c \u0431\u044b\u043b\u043e \u0441\u0442\u0440\u043e\u043a \u0438 \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b.\u041e\u0431\u044a\u0435\u043a\u0442 orders.csv \u0432 MinIO Console, \u0431\u0430\u043a\u0435\u0442 raw, \u043f\u0443\u0442\u044cSTG: \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0440\u044f\u0434\u043e\u043a\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0447\u0438\u0442\u0430\u0435\u0442 \u0444\u0430\u0439\u043b \u0443\u0436\u0435 \u0438\u0437 RAW-\u0431\u0430\u043a\u0435\u0442\u0430. \u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b.\u0421 \u0434\u0430\u0442\u0430\u043c\u0438 \u0432\u0441\u0451 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u044b \u0434\u0432\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0430:def parse_date(value: str):    for pattern in (&#171;%Y-%m-%d&#187;, &#171;%d.%m.%Y&#187;):        try:            return datetime.strptime(value.strip(), pattern).date()        except ValueError:            continue    raise ValueError(&#171;invalid_order_date&#187;)\u0421 \u0441\u0443\u043c\u043c\u0430\u043c\u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435. \u041f\u0440\u043e\u0431\u0435\u043b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u043c \u0442\u044b\u0441\u044f\u0447, \u0430 \u0437\u0430\u043f\u044f\u0442\u0430\u044f \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u044b\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u043c. \u041f\u043e\u0441\u043b\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 Decimal, \u0430 \u043d\u0435 \u0432 float:def parse_amount(value: str) -&gt; Decimal:    normalized = value.strip().replace(&#187; &#171;, &#171;&#187;)    if &#171;,&#187; in normalized:        normalized = normalized.replace(&#171;,&#187;, &#171;.&#187;)    amount = Decimal(normalized).quantize(Decimal(&#171;0.01&#187;))    if amount &lt;= 0:        raise ValueError(&#171;non_positive_amount&#187;)    return amount\u0412 \u043f\u043e\u043b\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0441\u043b\u0443\u0447\u0430\u0439, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0447\u0438\u0441\u043b\u0435 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u0447\u043a\u0430 \u0438 \u0437\u0430\u043f\u044f\u0442\u0430\u044f.\u041e\u0448\u0438\u0431\u043e\u0447\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u044f \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u044e. \u041e\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 stg.habr_orders_rejects \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0441\u0442\u0440\u043e\u043a\u0438, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c JSON \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u043e\u0442\u043a\u0430\u0437\u0430.\u041f\u043e \u043d\u0430\u0448\u0435\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0435\u0442\u044b\u0440\u0435 rejects:4  | invalid_order_date         | order_id=10037  | invalid_amount             | order_id=10069  | duplicate_order_id_in_file | order_id=100712 | non_positive_amount        | order_id=1010\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u0431\u0430\u043b\u0430\u043d\u0441:11 \u0441\u0442\u0440\u043e\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 = 7 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 + 4 \u043e\u0442\u043a\u043b\u043e\u043d\u0451\u043d\u043d\u044b\u0445\u0412\u0441\u0435 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0438\u0434\u043d\u044b \u0441 \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c\u0438 \u0431\u0440\u0430\u043a\u0430.\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e \u0434\u0443\u0431\u043b\u044c. DISTINCT \u0443\u0431\u0440\u0430\u043b \u0431\u044b \u0432\u0442\u043e\u0440\u0443\u044e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u043d\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0443\u0431\u043b\u044f \u043f\u043e\u0442\u0435\u0440\u044f\u043b\u0430\u0441\u044c \u0431\u044b. \u0417\u0434\u0435\u0441\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 order_id \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432 rejects. \u0412\u043e\u043e\u0431\u0449\u0435 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0430\u043a\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439, \u0442\u043e \u0435\u0441\u0442\u044c \u043e\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a stg.habr_orders_rejects\u041f\u043e\u0441\u043b\u0435 STG \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438: \u0434\u0430\u0442\u0430 \u0441\u0442\u0430\u043b\u0430 \u0434\u0430\u0442\u043e\u0439, \u0441\u0443\u043c\u043c\u0430 \u0447\u0438\u0441\u043b\u043e\u043c, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u044b, \u0434\u0443\u0431\u043b\u0438 \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u044b.\u041e\u0434\u043d\u0430\u043a\u043e, \u0441\u0443\u043c\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u0430 \u0435\u0449\u0451 \u043d\u0435 \u0440\u0430\u0432\u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0435. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430:case    when order_status = &#8216;paid&#8217; then amount    when order_status = &#8216;refunded&#8217; then -amount    else 0end as net_revenue\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a:paid      -&gt; \u0441\u0443\u043c\u043c\u0430 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u044b\u0440\u0443\u0447\u043a\u0443refunded  -&gt; \u0441\u0443\u043c\u043c\u0430 \u0432\u044b\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044fcreated   -&gt; \u0437\u0430\u043a\u0430\u0437 \u0435\u0449\u0451 \u043d\u0435 \u043e\u043f\u043b\u0430\u0447\u0435\u043d, \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 \u043d\u0443\u043b\u044ecancelled -&gt; \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0439 \u0437\u0430\u043a\u0430\u0437 \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u044b\u0440\u0443\u0447\u043a\u0443\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 CORE \u044f \u0445\u0440\u0430\u043d\u044e \u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0441\u0443\u043c\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u0430, \u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u0443\u044e \u0432\u044b\u0440\u0443\u0447\u043a\u0443:order_id | status    | gross_amount | net_revenue1001     | paid      | 1299.90      | 1299.901004     | created   | 500.00       | 0.001005     | refunded  | 800.00       | -800.001008     | cancelled | 420.00       | 0.00\u0422\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0443\u043c\u043c\u0430 \u0438\u0437 CSV \u0438 \u0441\u0443\u043c\u043c\u0430 \u043d\u0430 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0435 \u043c\u043e\u0433\u0443\u0442 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c. \u042d\u0442\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0448\u0438\u0431\u043a\u0430. \u0418\u043d\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c. \u0427\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0443\u0442 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u043e\u0439 (\u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0432\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0435!).\u0422\u0430\u0431\u043b\u0438\u0446\u0430 core.habr_orders: gross_amount, net_revenue \u0438 business_rule.MARTS: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435\u0412\u0438\u0442\u0440\u0438\u043d\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441: \u043a\u0430\u043a\u0430\u044f \u0432\u044b\u0440\u0443\u0447\u043a\u0430 \u0431\u044b\u043b\u0430 \u043f\u043e \u0434\u043d\u044f\u043c. \u0415\u0451 \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u043e\u0439 \u0444\u0440\u0430\u0437\u043e\u0439:\u041e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d\u043e\u043c\u0443 \u0434\u043d\u044e \u0437\u0430\u043a\u0430\u0437\u0430.\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u044f \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e:select    order_date,    count(*) as orders_count,    count(*) filter (where order_status = &#8216;paid&#8217;) as paid_orders,    count(*) filter (where order_status = &#8216;refunded&#8217;) as refunded_orders,    sum(gross_amount) as gross_amount,    sum(net_revenue) as net_revenuefrom core.habr_ordersgroup by order_date;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:order_date  | orders | gross_amount | net_revenue2026-07-18  | 2      | 2599.80      | 2599.802026-07-19  | 2      | 1300.00      | -800.002026-07-20  | 3      | 820.50       | 400.50\u0418\u0442\u043e\u0433\u043e:gross_amount = 4720.30net_revenue  = 2200.30\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c, \u043e\u0442\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u043c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u044b\u043c \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438. \u0415\u0441\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0432\u0438\u0442\u0440\u0438\u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043b\u043e\u043d\u043a\u0443 amount, \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0441\u044f\u0446 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0430 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442.\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0437\u0434\u0435\u0441\u044c \u0447\u0430\u0441\u0442\u043e \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0449\u0451 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: JOIN \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u0438\u043b\u0438 \u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439 \u0440\u0430\u0437\u043c\u043d\u043e\u0436\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0434 SUM \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u0435\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043a\u0430\u0440\u0434\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f (\u043a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e JOIN \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c).\u0413\u0440\u0430\u0444\u0438\u043a \u0432 MetabaseAirflow: \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0448\u0430\u0433\u043e\u0432 \u0438 \u043c\u0435\u0441\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0438DAG \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0448\u0435\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447:prepare_lab  -&gt; store_file_in_raw  -&gt; clean_to_stg  -&gt; apply_business_rules_to_core  -&gt; build_daily_mart  -&gt; check_pipelineAirflow \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0448\u0430\u0433\u0438 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u0438 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435.\u0422\u0430\u043a\u043e\u0439 \u0433\u0440\u0430\u0444 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0435\u0449\u0451 \u0438 \u0434\u043b\u044f \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438:\u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043d\u0435 \u043f\u043e\u043f\u0430\u043b \u0432 MinIO, \u0441\u043c\u043e\u0442\u0440\u0438\u043c store_file_in_raw. \u0415\u0441\u043b\u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0443\u0448\u043b\u0438 \u0432 rejects, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c clean_to_stg. \u0415\u0441\u043b\u0438 CORE \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f, \u0430 \u0441\u0443\u043c\u043c\u0430 \u0432\u0438\u0442\u0440\u0438\u043d\u044b \u0440\u0430\u0437\u043e\u0448\u043b\u0430\u0441\u044c, \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 apply_business_rules_to_core, build_daily_mart \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c\u0438.\u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 DAG\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e DAG\u0417\u0435\u043b\u0451\u043d\u044b\u0439 DAG \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438\u0441\u044c. \u041d\u043e \u043c\u044b \u0436\u0435 \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0432\u043d\u043e \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432\u0441\u0435 \u043e\u0442\u0431\u0435\u0436\u0430\u043b\u043e \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u043f\u0438\u0442\u044c \u043a\u043e\u0444\u0435.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0448\u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a:raw_row_balance                    11 = 11no_duplicate_order_ids_in_stg       0 = 0no_null_required_fields_in_stg      0 = 0stg_to_core_row_count               7 = 7core_to_mart_net_revenue      2200.30 = 2200.30sample_expected_net_revenue   2200.30 = 2200.30\u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043f\u0435\u0440\u0435\u0447\u043d\u0435\u043c \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0412 \u043b\u043e\u0433\u0430\u0445 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f actual, expected \u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435.\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0441 \u0436\u0451\u0441\u0442\u043a\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u043e\u0439 \u044f \u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u043b \u0441\u0432\u0435\u0440\u043a\u043e\u0439 \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u043e\u043c \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c. \u0417\u0434\u0435\u0441\u044c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u0442\u0430\u0441\u0435\u0442 \u0438\u0433\u0440\u0443\u0448\u0435\u0447\u043d\u044b\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u043d\u0430\u0435\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442.\u041b\u043e\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 check_pipeline \u0441 \u0448\u0435\u0441\u0442\u044c\u044e passed=True\u0427\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442, \u0435\u0441\u043b\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u0440\u0438\u0448\u043b\u0451\u0442 \u0442\u043e\u0442 \u0436\u0435 \u0444\u0430\u0439\u043b \u0432\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0437\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e DAG \u0435\u0449\u0451 \u0440\u0430\u0437, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 orders.csv.\u0417\u0430\u0434\u0430\u0447\u0430 prepare_lab \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, \u0430 store_file_in_raw \u043d\u0430\u0445\u043e\u0434\u0438\u0442 SHA-256 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 skipped. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u043e\u0436\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f. \u0412 RAW \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043f\u0438\u044f, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-488366","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/488366","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=488366"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/488366\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=488366"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=488366"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=488366"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}