سكالا وباي سبارك في البيانات الضخمة عملياً: الكود والأوامر التي تهم حقاً

سكالا باي سبارك بيغ داتا: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات ملموسة، مقتطفات من دورة مكونة من 47 درسًا.

سكالا وباي سبارك في البيانات الضخمة عملياً: الكود والأوامر التي تهم حقاً

لا توجد نظرية لا تنتهي هنا: نفتح الطرفية ونمارس. إليك الأساسيات لـ Scala PySpark Big Data، مستخرجة مباشرة من دورة كاملة تضم 47 درسًا — مع كود حقيقي يمكنك نسخه ولصقه الآن.

tl;dr
  • مقدمة في نماذج البرمجة
  • تثبيت بيئة البيانات الضخمة
  • اكتشاف البيانات الضخمة وSpark
  • أساسيات Scala
  • Scala المتقدم لـ Spark
~$ cat ./parcours.md # Scala PySpark Big Data — 12 فصول
01
مقدمة إلى نماذج البرمجة
→ النموذج الأمري والإجرائي→ النموذج الموجه للكائنات+ 2 دروس أخرى
02
تثبيت بيئة البيانات الضخمة
→ تثبيت Java JDK و Scala→ تثبيت Apache Spark و PySpark+ 2 دروس أخرى
03
اكتشاف البيانات الضخمة و Spark
→ تاريخ وتحديات البيانات الضخمة→ منظومة Apache Spark+ 1 دروس أخرى
04
أساسيات Scala
→ الصيغة الأساسية وأنواع البيانات→ الدوال والشروط والحلقات+ 2 دروس أخرى
05
Scala المتقدم لـ Spark
→ الفئات والكائنات و case classes→ مطابقة الأنماط والخيارات+ 4 دروس أخرى
06
الأسس النظرية لـ Spark RDD DataFrame Dataset
→ البنية الداخلية لـ Spark→ RDD vs DataFrame vs Dataset+ 1 دروس أخرى
07
RDD مجموعات البيانات الموزعة المرنة
→ ما هو RDD ؟→ التحويلات والإجراءات على الـ RDD+ 1 دروس أخرى
08
DataFrames و Spark SQL
→ ما هو DataFrame ؟→ العمليات والتحويلات على الـ DataFrames+ 2 دروس أخرى
🏁
المشروع النهائي (+ 4 فصول في الطريق)
→ تعود بمشروع ملموس وقابل للعرض

تمارين عملية كاملة على Spark

NOTEالهدف — تطبيق كل المفاهيم التي تمت دراستها في الدورة من خلال تمارين عملية في spark-shell (Scala) وPySpark. هذه الوحدة عبارة عن مختبر عملي موجه: تكتب الأوامر واحدًا تلو الآخر وتراقب النتائج.
WARNINGلا تقلق — صُمم هذا التمرين ليُتبع خطوة بخطوة. كل أمر مشروح. لا تحتاج إلى فهم كل شيء فورًا: الهدف هو التعامل ورؤية النتائج. سيأتي الفهم مع الممارسة.

الأهداف التعليمية

TIPفي نهاية هذه الوحدة — ستكون قادرًا على إتقان هذه المهارات الأساسية.
NOTEالمتطلبات المسبقة — لمتابعة هذا التمرين، يجب أن تكون قد:
  • ثبت Spark (انظر الفصل 01)
  • وصول إلى spark-shell من الطرفية
  • مجلد عمل (مثال: C:/Users/user01/Desktop/SPARK/)

الجزء 0 – إتقان spark-shell (REPL)

NOTEما هو spark-shell؟spark-shell هو REPL (Read-Eval-Print Loop): طرفية تفاعلية تكتب فيها أمر Scala، فيُنفذه Spark فورًا ويعرض النتيجة. إنه الأداة المثالية للتعلم واختبار أوامر Spark بسرعة، دون الحاجة إلى إنشاء مشروع كامل.
TIPالمتغيرات المنشأة تلقائيًا — عند تشغيل spark-shell، ينشئ Spark تلقائيًا متغيرين لك:
  • spark: كائن SparkSession (نقطة الدخول الرئيسية لـ Spark)
  • sc: كائن SparkContext (يُستخدم لإنشاء RDD)
لا تحتاج إلى إنشائهما بنفسك. إنهما جاهزان للاستخدام. بالإضافة إلى ذلك، import spark.implicits._ مستورد تلقائيًا (مما يتيح استخدام .toDF()).

0.1 – تشغيل spark-shell

bash
# Windows (PowerShell) :
spark-shell

# macOS / Linux :
./bin/spark-shell
# أو إذا كان Spark في PATH:
spark-shell
NOTESpark Web UI — عند بدء spark-shell، ينشئ Spark تلقائيًا واجهة ويب يمكن الوصول إليها على العنوان http://localhost:4040. إذا كان المنفذ 4040 مشغولاً، يحاول Spark 4041، 4042، إلخ. تتيح لك هذه الواجهة رؤية المهام والمراحل والعمليات الجارية.

0.2 – الاختبار الأول: إنشاء DataFrame

output
// Tapez ces commandes une par une dans le spark-shell :

scala> import spark.implicits._
// déjà importé automatiquement, mais utile si vous créez votre propre SparkSession

scala> val data = Seq(("Java", "20000"), ("Python", "100000"), ("Scala", "3000"))
// data: Seq[(String, String)] = List((Java,20000), (Python,100000), (Scala,3000))

scala> val df = data.toDF()
// df: org.apache.spark.sql.DataFrame = [_1: string, _2: string]

scala> df.show()
// +------+------+
// |    _1|    _2|
// +------+------+
// |  Java| 20000|
// |Python|100000|
// | Scala|  3000|
// +------+------+
TIPتسمية الأعمدة — تُسمى الأعمدة _1 و_2 افتراضيًا. لإعطائها أسماء حقيقية، استخدم .toDF("langage", "offres") :
output
scala> val df = data.toDF("langage", "offres")
scala> df.show()
// +-------+------+
// |langage|offres|
// +-------+------+
// |   Java| 20000|
// | Python|100000|
// |  Scala|  3000|
// +-------+------+

0.3 – الأوامر الخاصة بـ spark-shell

WARNINGمهم جدًا — يمتلك spark-shell أوامر خاصة تبدأ بـ : (نقطتين). هذه الأوامر ليست Scala، بل خاصة بالـ REPL. تعلمها، ستوفر عليك الكثير من الوقت!
output
// Afficher l'aide complète (liste de toutes les commandes spéciales)
scala> :help
الأمرالوصفمثال
:help يعرض قائمة بجميع الأوامر المتاحة :help أو :he
:paste وضع «لصق»: يتيح لصق عدة أسطر من الكود دفعة واحدة. أنهِ بـ Ctrl+D. :paste
:load <fichier> يحمّل وينفذ ملف .scala سطرًا سطرًا :load hello.scala
:load -v <fichier> يحمّل ملفًا في الوضع verbose (يعرض كل سطر منفذ) :load -v hello.scala
:quit الخروج من spark-shell بشكل نظيف :quit أو :q
:history يعرض سجل الأوامر المكتوبة :history أو :history 20
:h? <mot> البحث عن كلمة في السجل :h? toDF
:require <jar> إضافة ملف JAR إلى classpath أثناء الجلسة :require /chemin/vers/mon.jar
:type <expr> يعرض نوع تعبير دون تنفيذه :type 1 + 2Int
:imports يعرض جميع الاستيرادات النشطة في الجلسة :imports
:implicits يعرض الـ implicits المتاحة :implicits -v
:reset يعيد تهيئة الـ REPL (يمسح جميع المتغيرات) :reset
:replay يعيد التهيئة ويعيد تشغيل جميع الأوامر السابقة :replay
:save <fichier> يحفظ الجلسة في ملف .scala :save ma_session.scala
:sh <cmd> ينفذ أمر shell (Unix/macOS فقط) :sh ls -la
:silent تفعيل/تعطيل العرض التلقائي للنتائج :silent
:javap <class> يفكك فئة Java / Scala :javap scala.Int
NOTEلماذا :paste؟ — في spark-shell، إذا لصقت كودًا متعدد الأسطر مباشرة، يحاول الـ REPL تنفيذ كل سطر على حدة، مما يسبب أخطاء. وضع :paste يتيح لصق كتلة كاملة من الكود وتنفيذها ككل.
output
// Étape 1 : tapez :paste et appuyez sur Entrée
scala> :paste
// Entering paste mode (ctrl-D to finish)

// Étape 2 : collez votre code multi-lignes
val noms = Seq("Alice", "Bob", "Charlie")
val rdd = sc.parallelize(noms)
val majuscules = rdd.map(_.toUpperCase)
majuscules.collect()

// Étape 3 : appuyez sur Ctrl+D pour exécuter
// Exiting paste mode, now interpreting.

// noms: Seq[String] = List(Alice, Bob, Charlie)
// rdd: org.apache.spark.rdd.RDD[String] = ...
// majuscules: org.apache.spark.rdd.RDD[String] = ...
// res0: Array[String] = Array(ALICE, BOB, CHARLIE)
WARNINGCtrl+D، وليس Ctrl+C! — لإنهاء وضع :paste, اضغط Ctrl+D. إذا ضغطت Ctrl+C، تلغي الكود الملصق.
NOTEحالة الاستخدام — لديك ملف .scala يحتوي على دوال أو معالجات تريد تنفيذها في spark-shell. بدلاً من نسخ كل شيء، استخدم :load.

الخطوة 1 – إنشاء ملف Scala:

bash
# Windows (PowerShell) :
@"
println("Bonjour depuis le fichier Scala !")
val animaux = Seq("chat", "chien", "oiseau")
val rdd = sc.parallelize(animaux)
println("Nombre d'animaux : " + rdd.count())
rdd.collect().foreach(println)
"@ | Out-File -Encoding utf8 "C:\Users\user01\Desktop\SPARK\hello.scala"

# macOS / Linux :
cat > ~/Desktop/SPARK/hello.scala <<'EOF'
println("Bonjour depuis le fichier Scala !")
val animaux = Seq("chat", "chien", "oiseau")
val rdd = sc.parallelize(animaux)
println("Nombre d'animaux : " + rdd.count())
rdd.collect().foreach(println)
EOF

تطبيق عملي على Spark SQL — AAPL وIncome

NOTEالهدف: تطبيق Spark SQL على مجموعتي بيانات حقيقيتين — بيانات أسهم Apple (AAPL.csv) وبيانات الدخل (income.csv) — باستخدام case class وRDD وDataFrame ودوال التجميع في Spark SQL.
TIPالمتطلبات المسبقة: إكمال الجزء 5 (مشروع Maven IntelliJ). Spark مثبت أو الوصول إلى بيئة Spark (Databricks، IntelliJ مع Spark، أو spark-shell).

جدول المحتويات

0. عرض البيانات وتنزيلها

0.1 – ملف AAPL.csv (بيانات أسهم Apple)

NOTEيحتوي الملف AAPL.csv على سجل أسعار سهم Apple (NASDAQ : AAPL). كل سطر يمثل يوم تداول.
العمودالنوعالوصفمثال
dtStringتاريخ المعاملة1984-09-07
openpriceDoubleسعر الافتتاح لليوم25.50
highpriceDoubleأعلى سعر لليوم26.10
lowpriceDoubleأدنى سعر لليوم24.80
closepriceDoubleسعر الإغلاق لليوم25.90
volumeDoubleعدد الأسهم المتداولة1234567.0
adjclosepriceDoubleسعر الإغلاق المعدل (توزيعات الأرباح، الانقسامات)25.85
NOTE كيفية تنزيل AAPL.csv — 3 طرق
الطريقة 1 — wget (موصى بها، Windows/macOS/Linux)
نزّل الملف الخام مباشرة من GitHub :
bash
wget https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/AAPL.csv
NOTEفي Windows PowerShell، استخدم الاسم المستعار Invoke-WebRequest إذا لم يكن wget متاحًا:
bash
# PowerShell — télécharger AAPL.csv dans le dossier courant
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/AAPL.csv" -OutFile "AAPL.csv"
NOTEالطريقة 2 — git clone (استنساخ المستودع كاملاً)
استنسخ المستودع كاملاً واحصل على جميع ملفات البيانات:
bash
# Cloner le dépôt inskillflow/data
git clone https://github.com/inskillflow/data.git

# Le fichier AAPL.csv sera dans :
#   data/AAPL.csv
TIPالطريقة 3 — واجهة GitHub (بدون طرفية)
  1. افتح https://github.com/inskillflow/data/blob/main/AAPL.csv
  2. انقر على زر « Raw » في أعلى يمين الملف
  3. اضغط Ctrl+S (أو Cmd+S على Mac) لحفظ الصفحة باسم AAPL.csv
رابط مباشر للملف الخام:
https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/AAPL.csv
NOTEوضع الملف بعد التنزيل: ضع AAPL.csv في مجلد يمكن الوصول إليه، ثم عدّل المسار في الكود:
  • Windows : C:\Users\VotreNom\Desktop\Spark\AAPL.csv
  • Linux / macOS : /home/utilisateur/data/AAPL.csv
  • Spark Shell (مسار نسبي) : ./AAPL.csv

0.2 – ملف Income.csv (بيانات الدخل)

العمودالنوعالوصف
idDoubleمعرف فريد
workclassStringفئة الوظيفة (Private, Self-emp, Gov...)
educationStringمستوى التعليم
maritalstatusStringالحالة الزوجية
occupationStringالمهنة
relationshipStringالعلاقة العائلية
raceStringالأصل العرقي
genderStringالجنس
nativecountryStringبلد المنشأ
incomeStringشريحة الدخل (<=50K أو >50K)
ageDoubleعمر الفرد
fnlwgtDoubleوزن الترجيح الإحصائي
educationalnumDoubleعدد سنوات التعليم
capitalgainDoubleمكاسب رأس المال
capitallossDoubleخسائر رأس المال
hoursperweekDoubleساعات العمل أسبوعيًا
NOTE كيفية تنزيل Income.csv — 3 طرق
الطريقة 1 — wget
bash
wget https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/Income.csv
NOTEفي Windows PowerShell :
bash
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/Income.csv" -OutFile "Income.csv"
NOTEالطريقة 2 — git clone (استنساخ الملفين معًا)
bash
# Si vous avez déjà cloné le dépôt pour AAPL.csv, Income.csv est déjà présent
# Sinon :
git clone https://github.com/inskillflow/data.git
# Le fichier Income.csv sera dans :  data/Income.csv

مطابقة الأنماط وOptions

NOTEالهدف — إتقان مطابقة الأنماط، أقوى أداة في Scala للمقارنة والترتيب وتفكيك البيانات. اكتشاف النوع Option[T] الذي يلغي NullPointerException، والتعمق أكثر مع Either وfor-comprehensions.
WARNINGلا تقلق — مطابقة الأنماط هي ببساطة معادل switch/case في Java أو match في Python 3.10+، لكن أقوى بكثير. إذا كنت تعرف بالفعل if/elif/else في Python، ستفهم بسهولة. تضيف Scala إمكانية التحقق من الأنواع، واستخراج البيانات من الكائنات، ووضع شروط — كل ذلك في صيغة واضحة ومختصرة.

الأهداف التعليمية

TIPفي نهاية هذه الوحدة — ستكون قادرًا على إتقان هذه المهارات الأساسية.

1. تشبيه الفرز البريدي

تخيل مركز فرز بريدي. تصل كل رسالة على سير متحرك. ينظر الموظف إلى العنوان ويرسل الرسالة إلى الصندوق الصحيح: باريس يسارًا، ليون يمينًا، مرسيليا مباشرة. إذا لم يطابق العنوان أي شيء معروف، تذهب الرسالة إلى صندوق «أخرى».

تعمل مطابقة الأنماط تمامًا مثل هذا الفرز البريدي: نفحص قيمة، نقارنها بعدة أنماط، وننفذ الكود المرتبط بأول نمط يطابق.

TIPلماذا أفضل من if/else — مطابقة الأنماط أكثر قابلية للقراءة، وأكثر أمانًا (يتحقق المترجم من تغطية جميع الحالات مع sealed trait) وأقوى بكثير، لأنها تستطيع تفكيك كائنات معقدة، واستخراج القيم، والجمع بين النوع + القيمة + الشرط في case واحد.

2. صيغة match/case

تعبير match يأخذ قيمة ويقارنها بسلسلة من عبارات case. تُنفذ أول عبارة مطابقة. على عكس switch في Java، لا يوجد break لكتابته — يتوقف Scala تلقائيًا عند أول حالة مطابقة.

NOTEالمفهوم الرئيسي — في Scala، match هو تعبير، وليس تعليمة. هذا يعني أنه يُرجع دائمًا قيمة. يمكنك كتابة val x = valeur match { ... }.

مثال 1: أيام الأسبوع

output
val jour = "Mercredi"

val typeJour = jour match {
  case "Lundi" | "Mardi" | "Mercredi" | "Jeudi" | "Vendredi" =>
    "Jour ouvré"
  case "Samedi" | "Dimanche" =>
    "Week-end"
  case _ =>
    "Jour inconnu"  // _ = la boîte "Autres" du tri postal
}

println(typeJour)  // "Jour ouvré"
NOTEالرمز الجامع _ — الرمز _ (الشرطة السفلية) يطابق «كل ما تبقى». يجب وضعه دائمًا في النهاية، لأنه يلتقط كل شيء. بدونه، إذا لم يطابق أي case، يرفع Scala استثناء MatchError أثناء التنفيذ.

مثال 2: تحويل درجة إلى تقدير

output
val note = 15

val mention = note match {
  case 20                 => "Parfait"
  case 16 | 17 | 18 | 19 => "Très bien"
  case 14 | 15            => "Bien"
  case 12 | 13            => "Assez bien"
  case 10 | 11            => "Passable"
  case _                  => "Insuffisant"
}

println(mention)  // "Bien"

في Java أو Python، يكون switch أو match تعليمة: يفعل شيئًا لكنه لا يُرجع قيمة مباشرة. في Scala، match هو تعبير: يُرجع دائمًا قيمة.

ما يغيره عمليًا:

output
// Scala : match est une expression, on peut l'assigner directement
val categorie = age match {
  case a if a < 18  => "Mineur"
  case a if a < 65  => "Adulte"
  case _            => "Senior"
}

// On peut aussi l'utiliser comme argument d'une fonction
println(age match {
  case a if a < 18 => "Mineur"
  case _           => "Adulte"
})

// Ou dans une interpolation de string
val message = s"Statut : ${age match {
  case a if a < 18 => "Mineur"
  case _           => "Adulte"
}}"
output
// Java : le switch (avant Java 14) ne retourne pas de valeur
// Il fallait écrire :
String categorie;
switch (age) {
  case ...: categorie = "Mineur"; break;
  default:  categorie = "Adulte";
}
// Java 14+ a ajouté les switch expressions pour combler ce manque
TIPقاعدة عملية — بما أن match يُرجع قيمة، يتحقق المترجم من أن جميع الفروع تُرجع نفس النوع. إذا أرجع case String وآخر Int، يستنتج Scala النوع المشترك (Any). غالبًا ما يكون ذلك علامة على خطأ في التصميم.
output
# Python 3.10+ structural pattern matching
jour = "Mercredi"
match jour:
    case "Lundi" | "Mardi" | "Mercredi" | "Jeudi" | "Vendredi":
        type_jour = "Jour ouvre"
    case "Samedi" | "Dimanche":
        type_jour = "Week-end"
    case _:
        type_jour = "Jour inconnu"

# Difference : en Python, match est une instruction (pas d'assignation directe)
# En Scala : val x = valeur match { ... }  <-- expression qui retourne une valeur
# En Python : vous devez assigner dans chaque branche manuellement
output
# Python < 3.10 : pas de match/case, on utilise if/elif/else
jour = "Mercredi"

if jour in ("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi"):
    type_jour = "Jour ouvre"
elif jour in ("Samedi", "Dimanche"):
    type_jour = "Week-end"
else:
    type_jour = "Jour inconnu"
va-plus-loin

يغطي هذا المقال المقتطفات الأكثر فائدة — الدورة الكاملة Scala PySpark Big Data (13 فصلاً، 47 درسًا، تمارين محلولة ومشروع نهائي) تأخذك إلى النهاية.

./acceder-au-cours-complet cours gratuit : Maîtriser Claude Code

الأسئلة الشائعة

كم من الوقت لتعلم Scala PySpark Big Data؟
مع تقدم منظم (13 فصلاً، 47 درسًا قصيرًا وعمليًا)، يمكن الوصول إلى مستوى تشغيلي في بضعة أسابيع بمعدل 30 إلى 60 دقيقة يوميًا. المهم هو تطبيق كل مفهوم فورًا.
هل هناك متطلبات مسبقة؟
تكفي أساسيات في الحوسبة. إذا كنت تعرف استخدام الطرفية وقراءة كود بسيط، فأنت جاهز.
من أين نبدأ عمليًا؟
أعد إنتاج أوامر هذا المقال، ثم تابع الدورة الكاملة Scala PySpark Big Data: تربط الـ 47 درسًا بالترتيب، مع تمارين ومشروع نهائي.

📬 هل تريد تلقي هذا النوع من الأدلة كل أسبوع؟ اشترك مجانًا — كود حقيقي، بدون كلام فارغ.