Storytelling with Data
132 subscribers
9 photos
2 links
Download Telegram
SPARK malumotlarini qayta ishlash asosan operatsiyalarin DAG (Directed Acyclic Graph) yaratish haqida.

Spark dasturlarida asosan dag yaratamiz.
Transformations and Actions

Transformations bitta dataframe ni boshqasiga ozgartirish uchun ishlatiladi va asl dataframe ozgarmaydi.
example: where() transformatsiyasi bunda u kirish df da ishlaydi va chiqish df yaratadi.
birinchi df ozgarishsiz qoladi.
shuning uchun spark da df ozgarishsiz qoladi.


endi Transformations ozi ham ikkiga bolinadi:
1.Narrow dependency transformation(Tor boglikdagi transformatsiya)
2.Wide dependency transformation(keng boglikdagi transformatsiya)


1.Narrow dependency transformation ->Agarda biz transformatsiyani alohida bolak yani partition ustida bajarilsa va natijaga tasir qilmasa bu Narrow dependency transformation hisoblanadi.
example: where() transformatsiyasi tor boglikdagi transformatsiya hisoblanadi.


2.Wide dependency transformation -> Agar transformatsiya boshqa bolaklardan malumotlarni talab qilsa, bu keng boglikdagi transformatsiya hisoblanadi.
example: groupBy() transformatsiyasi.

endi deylik hozir group nega bogliq mustaqil deb oyladingiz men ham birinchi marta shunaqa oylaganman 😁😁

keling misol koramiz:

Ikki df ni bolaklarga boldik va biz groupBy() transformatsiyasini qolladik va ichidagi yozuvlar sonini aniqladik.Spark nima qiladi har bir alohida bolakga groupBy() qiladi va yangi df yaratishi mumkin.

Ammo natijalar birlashganda nima boladi umumiylik yoqoladi va togri umumiy natija chiqmaydi.

Demak, groupBy() bolaklarning mustaqilligini buzadi.

shuning uchun ham groupBy() keng bogliqlikdagi transformatsiya hisoblanadi.
xop qanaqa qilamiz unda desak:


REPARTITIONING orqali tuzatish mumkin.

Yani barcha bolaklarni birlashtirib, malum guruhlarning barcha yozuvlarini bir xil bolakka joylashtiramiz.

Bu Jarayon esa Shuffle va sort operatsiyalari deyiladi.

keyin esa biz count() orqali sanab qoyamiz.boldi!
Please open Telegram to view this post
VIEW IN TELEGRAM
Endi Sparkning eng muhim jihatlaridan biri – kechiktirilgan baholashga (Lazy Evaluation) haqida gaplashamiz! 😲


Kechiktirilgan baholash – bu funksional dasturlash texnikasi.
Bu Spark dasturlari uchun nimani anglatadi?
Oddiy!
Dasturchilar ushbu transformatsiyalarni individual kod qatorlari sifatida ko‘radi,
ya’ni qadam-baqadam bajariladi deb o‘ylaydi.


Lekin Spark bunday ishlamaydi.
Nega?
Chunki biz DAG yaratmoqdamiz.

Barcha transformatsiyalar drayverga boradi,
drayver ularni optimallashtirib, bajarish rejasini yaratadi,
va ushbu reja bajaruvchilar tomonidan bajariladi.

Harakatlar (Actions) DAG’ni ishga tushiradi.

Masalan, show(), collect(), write(), read().

Barcha transformatsiyalar bajarilganidan keyin natijani olish uchun biz show() yoki collect() kabi harakatlarni bajarishimiz kerak.

Shuning uchun, transformatsiyalar kechiktirilgan (lazy),
ammo harakatlar darhol bajariladi.
Please open Telegram to view this post
VIEW IN TELEGRAM
df = df.repartition(n)

DataFrame n taga partitsiyaga ajraladi
Dataframe ga malumot yuklash bu ACTION.
va har bir spark action bir spark job ga masul bo'ladi.
har bir job kamida bitta stage ga ega bolishi kerak
va har bir stage kamida bitta task ga ega bolishi shart.

Har bir Stage ozining ichki operatsiyalarining DAG(Directeg Acyclic Graph) ni hosil qiladi.
RDD - Resilient Distributed Dataset
• RDD → Moslashuvchan, lekin murakkab va sekin
• DataFrame API→ Tezroq va optimallashtirilgan (Spark SQL bilan ishlaydi)
• Dataset API→ Tiplangan va samarali, lekin faqat Scala/Java uchun
Catalyst Optimizer – bu Apache Spark SQL Engine ning ichki optimizatsiya tizimi bo‘lib,
DataFrame API va Spark SQL da yozilgan kodni samarali bajarilishini taminlaydi

✔ Catalyst Optimizer – bu Spark SQL va DataFrame API kodlarini optimallashtirish uchun mo‘ljallangan
✔ Ma’lumotlarni tezroq va samaraliroq qayta ishlashga yordam beradi
✔ RDD lar Catalyst Optimizer bilan ishlamaydi, shuning uchun DataFrame API ishlatish yaxshiroq
✔ SQL so‘rovlarini va DataFrame transformatsiyalarini avtomatik optimallashtiradi
✔ Barcha Spark ilovalari Catalyst Optimizer orqali samarali ishlaydi
RDD – bu Resilient Distributed Dataset degan ma’noni anglatadi.

RDD – bu oddiygina ma’lumotlar to‘plami.
Bu malumotlarni saqlash va qayta ishlash uchun malum bir tuzilma.

RDD DataFrame ga o‘xshaydi,
chunki DataFrame ham RDD ustida qurilgan.


Biroq, RDD va DataFrame o‘rtasidagi asosiy farq:
1.RDD – oddiy obyektlar to‘plami (strukturaga ega emas)
2.DataFrame – qator/ustun tuzilmasi va sxemaga ega

qisqaroq qilib, RDD – bu Scala, Java yoki Python kolleksiyalariga juda o‘xshash.


Ammo RDD ichki jihatdan partitsiyalarga ajratiladi va parallel ishlash uchun executor yadro (core) lariga tarqatiladi.


RDD ning Asosiy Xususiyatlari:


Taqsimlangan (Distributed) ->
• RDD partitsiyalarga bo‘linadi
• Executor yadrolari orasida tarqatiladi
• Shu sababli, RDD parallel ishlaydi

Qayta tiklanadigan (Resilient) ->
• RDD lar xatolarga bardoshli
• Har bir RDD qayta tiklash uchun metama’lumotlarni saqlaydi
• Agar executor ishdan chiqsa, boshqa executor xuddi shu RDD partitsiyasini qayta yaratib, bajarishni davom ettiradi


RDD API larining Cheklovlari

1. RDD lar qolda boshqarilishi kerak
• Ma’lumotlar strukturasi yo‘q
• Qolda optimallashtirish kerak
• Ma’lumotlarni qo‘lda siqish va tezlashtirish kerak

2.Spark RDD’ning ichki tuzilishini tushunmaydi
• RDD faqatgina oddiy obyektlar jamlanmasi
• Catalyst Optimizer bu obyektlarning tuzilmasini bilmaydi
• Spark optimallashtirish imkoniyatlarini yo‘qotadi

3. DataFrame API lari RDD larni to‘liq almashtiradi
• DataFrame API lar avtomatik optimallashtirilgan
• SQL funksiyalari bilan ishlash mumkin
• RDD API’larga nisbatan ancha qulay
Hozirgi vaqtda, RDD API lar eskirgan va tavsiya etilmaydi
Data Pipeline larda malumotlarni tekshirish (validatsiya qilish) juda muhim bolib, u pipeline jarayonining turli bosqichlarida amalga oshiriladi.

data analyst lar uchun pipeline larda validatsiya odatda ma'lumotlarni olish (ingestion, extract-load) bosqichidan keyin va malumotlarni modellashtirish (transform) jarayonidan song amalga oshiriladi.
ML pipeline larida esa, yuklab olingan malumotlarni validatsiya qilish ayniqsa muhim. Bu bosqichda notogri yoki sifatsiz malumotlarni aniqlash va yoq qilish amalga oshiriladi.
Muhimi, malumot validatsiyasini ML modelning validatsiyasi bilan aralashtirmaslik kerak. Malumot validatsiyasi kiruvchi malumotlarning sifatini tekshirishga qaratilgan bolsa, ML model validatsiyasi esa modelning ishlash samaradorligini baholash jarayonidir.
import configparser
import pymysql
import csv
import boto3

# Config faylini oqish
parser = configparser.ConfigParser()
parser.read("pipeline.conf")

# MySQL ulanish malumotlarini olish
hostname = parser.get("mysql_config", "hostname")
port = parser.get("mysql_config", "port")
username = parser.get("mysql_config", "username")
dbname = parser.get("mysql_config", "database")
password = parser.get("mysql_config", "password")

# MySQL bazasiga ulanish
conn = pymysql.connect(
host=hostname,
user=username,
password=password,
db=dbname,
port=int(port)
)

if conn is None:
print("Error connecting to the MySQL database")
else:
print("MySQL connection established!")

# Orders jadvalidan malumotlarni olish va CSV faylga yozish
m_query = "SELECT * FROM Orders;"
local_filename = "order_extract.csv"
m_cursor = conn.cursor()
m_cursor.execute(m_query)
results = m_cursor.fetchall()

with open(local_filename, 'w') as fp:
csv_w = csv.writer(fp, delimiter='|')
csv_w.writerows(results)

fp.close()
m_cursor.close()
conn.close()

# S3 ga yuklash uchun AWS credentials malumotlarini olish
parser = configparser.ConfigParser()
parser.read("pipeline.conf")

access_key = parser.get("aws_boto_credentials", "access_key")
secret_key = parser.get("aws_boto_credentials", "secret_key")
bucket_name = parser.get("aws_boto_credentials", "bucket_name")

# S3 bilan ulanish
s3 = boto3.client(
's3',
aws_access_key_id=access_key,
aws_secret_access_key=secret_key
)

# CSV faylni S3 ga yuklash
s3_file = local_filename
s3.upload_file(local_filename, bucket_name, s3_file)
❤1
Bu kod MySQL malumotlar bazasidan "Orders" jadvalini toliq yuklab, uni CSV ga yozadi va songra Amazon S3 ga yuklaydi.
import configparser
import psycopg2

# Config faylini oqish
parser = configparser.ConfigParser()
parser.read("pipeline.conf")

# Redshift ulanish malumotlarini olish
dbname = parser.get("aws_creds", "database")
user = parser.get("aws_creds", "username")
password = parser.get("aws_creds", "password")
host = parser.get("aws_creds", "host")
port = parser.get("aws_creds", "port")

# Redshiftga ulanish
rs_conn = psycopg2.connect(
"dbname=" + dbname
+ " user=" + user
+ " password=" + password
+ " host=" + host
+ " port=" + port
)

# Orders jadvalidagi songgi yangilangan sanani olish
rs_sql = """SELECT COALESCE(MAX(LastUpdated), '1900-01-01') FROM Orders;"""

rs_cursor = rs_conn.cursor()
rs_cursor.execute(rs_sql)
result = rs_cursor.fetchone()

# Natijani olish
last_updated_warehouse = result[0]

# Kursorni yopish
rs_cursor.close()
👍1
Bu kod hozirgi yuklagan Orders jadvalidagi songi yangilanish sanasini olish uchun kerak. ETL (Extract, Transform, Load) jarayonida u juda muhim , kodning qanday ishlashini va nega kerakligini tushuntiramiz.xosh:

1. Delta Load (faqat yangi malumotlarni olish)
Agar biz har safar butun Orders jadvalini qayta yuklasak, bu kop vaqt va resurs talab qiladi. Shuning uchun biz faqat oxirgi marta yangilangan qatorlarni yuklash ni xohlaymiz.

Misol:
Agar last_updated_warehouse = '2024-02-10' bo‘lsa, biz 2024-02-10 sanasidan keyingi yangi buyurtmalarni yuklaymiz.

ETL kodimiz shunday yozilishi mumkin:

SELECT * FROM Orders WHERE LastUpdated > '2024-02-10';


Bu esa malumotlarni qayta yuklamaslik va tezlikga imkon beradi.


2. Malumotlarni sinxronizatsiya qilish
Agar biz malumotlarni boshqa tizimga yuklayotgan bo‘lsak (masalan, Redshift → Data Warehouse), biz songgi LastUpdated vaqtini tekshirib, faqat ozgargan malumotlarni yangilashimiz mumkin.
Bu har safar butun jadvalni qayta ishlashdan saqlaydi va tezroq ishlov berish imkonini beradi.


3. Malumotlar togri yuklanganini tekshirish
Agar ETL jarayonida xatolik yuz bersa, biz LastUpdated vaqtni tekshirib, songgi marta qaysi malumotlar yuklanganini bilib olamiz.
Bu qayta yuklash yoki debugging uchun foydali boladi.
Normalization – bu jadvallarni togri tashkil qilish va ortiqcha malumotlarni bolmasligini taminlash jarayoni. Maqsad – malumotlar bazasining samaradorligini oshirish va tahlil jarayonini tezlashtirish.
👍3
Xosh, keling Airflow da DAG larni yaratish turlari haqida va yollari haqida korib chiqamiz.
Biz bilgan dag =Dag() usuli

Agarda buni import qilmasak DAG yaratib olmaymiz.

'''
from airflow import DAG
'''

import qilganimizdan song
'''

dag = DAG(...)

'''

shunaqa tartibda yaratib organganmiz.

lekin bu usul kop code yozishga sabab boladi va ishlashida ham farqi bor keyinroq koramiz. bu haqida toliq.

Aytaylik Task yaratmoqchimiz. Buning uchun Operatorlarni chaqirishimiz kerak boladi.


from airflow.operators.python import PythonOperator




task_1 = PythonOperator(
task_id='task_1',
dag=dag, # DAG ga boglashimiz uchun shu parametr kerak har doim.
...
)

Lekin har bir yangi taskda dag=dag parametrini har safar 100 ta task yozsak 100 marta yozish kerak boladi.



task_2 = PythonOperator(
task_id='task_2',
dag=dag, # Buni yana yozish kerak
...
)

task_3 = PythonOperator(
task_id='task_3',
dag=dag, # Yana, yana
...
)



Biz shuni yozmasdan dag yaratishni organamiz 😁

Context Manager - with operator



with DAG(...) as dag:
task_1 = PythonOperator(task_id='task_1', ...)
task_2 = PythonOperator(task_id='task_2', ...)
task_3 = PythonOperator(task_id='task_3', ...)




Bu usul ancha qulay va code quyidagicha boladi
Bu usulda dag=dag ni qayta-qayta yozish shart emas

yana bir usul bor lekin



Uchinchi USulda biz

DAG dekoretorini korib chiqamiz:



from airflow.decorators import dag, task

@dag(...)
def my_dag():
@task
def task_1():
...

@task
def task_2():
...

task_1() >> task_2()

my_dag()





Bu usul with DAG(...) as dag: dan ham yaxshiroq, chunki Airflow keyinchalik dekorator usulini toliq qollab-quvvatlashi kutilmoqda.


Bundan tashqari, @task dekoratori ham mavjud bo‘lib, u PythonOperator ni almashtiradi.

DAG dekoratori (@dag) tavsiya qila olaman, chunki Airflow shu yonalishda rivojlanmoqda. Bundan tashqari, @task dekoratori orqali vazifalarni ham aniqlashtira oladi, bu esa kodni ancha clean code qiladi.

Ammo with DAG(...) usuli ham yaxshi, faqat eski dag=dag usulidan foydalanish tavsiya qilmayman lekin hamma usulni bilib qoygan yaxshi sababi interviewda sorab qolishadi
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Bugun Dag yaratgandagi parametrlar haqida korib chiqamiz va nega kerak degan savollarga javob olamiz!

“start_date” parametri bu dag qachondan boshlab ishga tushishini reja qigan bolamiz.
DateTime obyektiga tenglab belgilaymiz.

Buning uchun bizga pendulum kutubxonasidan DateTime obyektini import qilishimiz kerak boladi.


from pendulum import DateTime


xosh dag qachondan boshlab ishlashini reja qildik endi har qanchada yani 1 kunda yoki har soatda ishlasinmi degan savolga
bu “schedule” parametri orqali javob beramiz!

Masalan, biz bu yerda “schedule” ni “daily” (kunlik) deb belgilab, 2025-yil 1-yanvardan boshlab har kuni yarim tunda ishga tushishini aytaganmiz odatda ozi kechasi 12 am da ishga tushadi.
buni vaqtini aniq ayta olamiz.

bizga kerakli 3 chi parametr bu
catchup hisoblanadi.

Odatda, biz catchup ga false value beramiz chunki ozi default u true holatda boladi.

xop 2025- yil 1-yanvardan keyin bizni projectda xatolik tufayli muvaffaqiyatsiz ishga tushgan daglar bor. agarda catchup True bolsa dag default ularni boshidan yana 1- yanvardan boshlab run berishga try qiladi.


description bu keyingi parametr biz bu yerda
Dag ni yozganmiz va nimaga kerak ekanligini yozib qoya olamiz keyin esa biz airflow ui da kora olishlari uchun code oqib tushunish shart bolmay qoladi.

tags bu parametr bolsa
juda foydali hisoblanadi asosan jamoalar bolib ishlaganda Daglar orasida filtr qoyish uchun.
Biz tags ni qanday tanlashimiz ozimizga bogliqva uni UI da ularni filtrlay olamiz shuning uchun ular juda qulay hisoblanadi.

Keyingi parametr – bu default arguments.
default_args bu dictionary shaklida boladi.

Agar biz Dagdagi barcha tasklar uchun qayta urinib korishlar sonini(retries) belgilamoqchi bolsak, default args ni ishlatishimiz kerak.

masalan
har bir taskni oldiga alohida “retries = 1” deb yozmasdan default_args ga yozib qoyishimizni ozi yetarli boladi.


dagrun_timeout bu bizga agarda dag ni ishlash vaqt oraligi masalan hozirgi vaziyatda agarda dag 20 minut ichida yani boshlangandan 20 minut ichida yakunlamasa avtomatik bu failed boladi degani. bu juda kerakli hisoblanadi.


va oxirgisi max_consecutive_failed_dag_runs
masalan, qiymatini 2 deb belgiladik.

Bu parametr orqali biz, agar dagimiz ketma-ket ikki marta failed bajarilsa, Airflow Dagning keyingi ishga tushirilishini toxtatishi kerakligini belgilaymiz.

Bu juda kerakli, chunki bu Dagning kop marta failed ishga tushirilishini oldini oladi chunki dam olish kunlarida xatoliklar yuz bersa yoki biror sababga kora Dagni post qila olmagan bolsak, yoki juda tez-tez(hourly) ishlaydigan Dag bolsa
kop marta failed ishga tushirilish sonini kamaytiramiz.

bu yerda DAG yaratish uchun kerak bolgan asosiy parametrlarni korib chiqdik.
❤1👍1
backfill
bu mexanizm malumotlaringizni qayta toldirish uchun Dag ishga tushirilgan sanalarni qayta ishga tushirishimiz kerak bolsa yoki boshlanish sanasidan oldingi sanalar uchun dag ishlashi kerak bolganda ishlatamiz.

xosh bizning pipeline larda hammasi yaxshi va ishlab turibdi.
2024-yil 2-yanvardan emas 2024-yil 1-yanvardan ishga tushirishni xohlagan edik.shu vaziyda foydalansak boladi.

Backfilling Airflow tomonidan avtomatik ravishda bajariladigan mexanizm emas.
Uni qolda, terminalda yoki airflow ui orqali ishga tushirishimiz mumkin.
❤2🔥2💩2
CROSS- COMMUNICATION between Tasks in AIRFLOW
(AIRFLOW XCOMS)

xcom - bu tasklar orasida malumot almashish uchun ishlatiladigan mexanizm.
U quyidagi qismlardan iborat:
key (kalit nomi)
value (almashilayotgan ma’lumot)
task_id (ma’lumotni yuborgan task)
dag_id (task qaysi DAGga tegishli)
execution_date (qaysi data interval uchun bajarilgan)

XCOM qiymati odatda JSON formatga serialize qilinadi. Bu har qanday obyektlarni emas, faqat JSON bilan mos keladigan turlarni saqlay oladi.
PICKLE istalgan code uchun ishlaydi shu sabab xavfsiz emas.

1.XCOM PUSH qilish

bunda malumotlarni uzatish uchun uni push qilamiz yani bazaga yozamiz



from airflow import DAG
from airflow.decorators import task

with DAG(...) as dag:

@task()
def sender1():
# 'data' key ostida brand qiymatini yuborish
ti.xcom_push(key='data', value={'brand': 'APPLE'})




xuddi shu natijaga return_value orqali push



from airflow import DAG
from airflow.decorators import task

with DAG(...) as dag:

@task()
def sender2():
# 'return_value' keyi avtomatik tarzda ishlatiladi
return {'brand': 'Apple'}



2.Bazadan yuborilgan qiymatni olish




from airflow import DAG
from airflow.decorators import task

with DAG(...) as dag:

@task()
def receiver1():
# sender task'dan 'data' keyidagi qiymatni olish
ti.xcom_pull(task_ids='sender', key='data')





bizda hozir Standart yani default settings bilan XCOM yani:
• key='return_value' bo’ladi
• Aynan shu DAG run ichida
• Ayni bir DAG dan olinadi

lekin Moslashtirib olishimiz ham mumkin:
• Boshqa DAG’dan (dag_id ni korsatib)
• Bir nechta tasklardan (task_ids=['taskA', 'taskB'])
• Oldingi barcha DAG runlardan (include_prior_dates=True bilan)


Bogliqliklar (Dependencies)

XCOM lar implicit (bilvosita) bogliqliklar hosil qiladi.
Agar Task C, Task A yuborgan XCOM ni ishlatsa, ular orasida avtomatik bogliqlik hosil boladi.shuni
Ikki usulda yozish mumkin:

1.Graph strukturasi orqali

sender() >> receiver()


2.Argument orqali uzatish




receiver(sender())



XCOM Size Limitations (Hajm Cheklovlari )

XCOM qiymatlari bazada saqlanadi shuning uchun hajm cheklovlari mavjud:
SQLite: 2 GB
PostgreSQL: 1 GB
MySQL: 64 MB


demak biz XCOM qiymatlarni saqlashimiz togrimi ???
❤2💯1
Airflow 3.0 chiqarildi!
💋3