سكالا وباي سبارك في البيانات الضخمة عملياً: الكود والأوامر التي تهم حقاً
سكالا باي سبارك بيغ داتا: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات ملموسة، مقتطفات من دورة مكونة من 47 درسًا.
لا توجد نظرية لا تنتهي هنا: نفتح الطرفية ونمارس. إليك الأساسيات لـ Scala PySpark Big Data، مستخرجة مباشرة من دورة كاملة تضم 47 درسًا — مع كود حقيقي يمكنك نسخه ولصقه الآن.
- مقدمة في نماذج البرمجة
- تثبيت بيئة البيانات الضخمة
- اكتشاف البيانات الضخمة وSpark
- أساسيات Scala
- Scala المتقدم لـ Spark
تمارين عملية كاملة على Spark
spark-shell (Scala) وPySpark. هذه الوحدة عبارة عن مختبر عملي موجه: تكتب الأوامر واحدًا تلو الآخر وتراقب النتائج.الأهداف التعليمية
- ثبت Spark (انظر الفصل 01)
- وصول إلى
spark-shellمن الطرفية - مجلد عمل (مثال:
C:/Users/user01/Desktop/SPARK/)
الجزء 0 – إتقان spark-shell (REPL)
spark-shell هو REPL (Read-Eval-Print Loop): طرفية تفاعلية تكتب فيها أمر Scala، فيُنفذه Spark فورًا ويعرض النتيجة. إنه الأداة المثالية للتعلم واختبار أوامر Spark بسرعة، دون الحاجة إلى إنشاء مشروع كامل.spark-shell، ينشئ Spark تلقائيًا متغيرين لك:
spark: كائن SparkSession (نقطة الدخول الرئيسية لـ Spark)sc: كائن SparkContext (يُستخدم لإنشاء RDD)
import spark.implicits._ مستورد تلقائيًا (مما يتيح استخدام .toDF()).0.1 – تشغيل spark-shell
# Windows (PowerShell) : spark-shell # macOS / Linux : ./bin/spark-shell # أو إذا كان Spark في PATH: spark-shell
http://localhost:4040. إذا كان المنفذ 4040 مشغولاً، يحاول Spark 4041، 4042، إلخ. تتيح لك هذه الواجهة رؤية المهام والمراحل والعمليات الجارية.0.2 – الاختبار الأول: إنشاء DataFrame
// 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|
// +------+------+_1 و_2 افتراضيًا. لإعطائها أسماء حقيقية، استخدم .toDF("langage", "offres") :scala> val df = data.toDF("langage", "offres")
scala> df.show()
// +-------+------+
// |langage|offres|
// +-------+------+
// | Java| 20000|
// | Python|100000|
// | Scala| 3000|
// +-------+------+0.3 – الأوامر الخاصة بـ spark-shell
: (نقطتين). هذه الأوامر ليست Scala، بل خاصة بالـ REPL. تعلمها، ستوفر عليك الكثير من الوقت!// 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 + 2 → Int |
: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 |
:paste؟ — في spark-shell، إذا لصقت كودًا متعدد الأسطر مباشرة، يحاول الـ REPL تنفيذ كل سطر على حدة، مما يسبب أخطاء. وضع :paste يتيح لصق كتلة كاملة من الكود وتنفيذها ككل.// É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):paste, اضغط Ctrl+D. إذا ضغطت Ctrl+C، تلغي الكود الملصق..scala يحتوي على دوال أو معالجات تريد تنفيذها في spark-shell. بدلاً من نسخ كل شيء، استخدم :load.الخطوة 1 – إنشاء ملف Scala:
# 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
AAPL.csv) وبيانات الدخل (income.csv) — باستخدام case class وRDD وDataFrame ودوال التجميع في Spark SQL.جدول المحتويات
0. عرض البيانات وتنزيلها
0.1 – ملف AAPL.csv (بيانات أسهم Apple)
AAPL.csv على سجل أسعار سهم Apple (NASDAQ : AAPL). كل سطر يمثل يوم تداول.| العمود | النوع | الوصف | مثال |
|---|---|---|---|
dt | String | تاريخ المعاملة | 1984-09-07 |
openprice | Double | سعر الافتتاح لليوم | 25.50 |
highprice | Double | أعلى سعر لليوم | 26.10 |
lowprice | Double | أدنى سعر لليوم | 24.80 |
closeprice | Double | سعر الإغلاق لليوم | 25.90 |
volume | Double | عدد الأسهم المتداولة | 1234567.0 |
adjcloseprice | Double | سعر الإغلاق المعدل (توزيعات الأرباح، الانقسامات) | 25.85 |
AAPL.csv — 3 طرق
الطريقة 1 —
wget (موصى بها، Windows/macOS/Linux)نزّل الملف الخام مباشرة من GitHub :
wget https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/AAPL.csv
Invoke-WebRequest إذا لم يكن wget متاحًا:# 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"
git clone (استنساخ المستودع كاملاً)استنسخ المستودع كاملاً واحصل على جميع ملفات البيانات:
# Cloner le dépôt inskillflow/data git clone https://github.com/inskillflow/data.git # Le fichier AAPL.csv sera dans : # data/AAPL.csv
- افتح https://github.com/inskillflow/data/blob/main/AAPL.csv
- انقر على زر « Raw » في أعلى يمين الملف
- اضغط Ctrl+S (أو Cmd+S على Mac) لحفظ الصفحة باسم
AAPL.csv
https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/AAPL.csv
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 (بيانات الدخل)
| العمود | النوع | الوصف |
|---|---|---|
id | Double | معرف فريد |
workclass | String | فئة الوظيفة (Private, Self-emp, Gov...) |
education | String | مستوى التعليم |
maritalstatus | String | الحالة الزوجية |
occupation | String | المهنة |
relationship | String | العلاقة العائلية |
race | String | الأصل العرقي |
gender | String | الجنس |
nativecountry | String | بلد المنشأ |
income | String | شريحة الدخل (<=50K أو >50K) |
age | Double | عمر الفرد |
fnlwgt | Double | وزن الترجيح الإحصائي |
educationalnum | Double | عدد سنوات التعليم |
capitalgain | Double | مكاسب رأس المال |
capitalloss | Double | خسائر رأس المال |
hoursperweek | Double | ساعات العمل أسبوعيًا |
Income.csv — 3 طرق
الطريقة 1 —
wgetwget https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/Income.csv
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/inskillflow/data/refs/heads/main/Income.csv" -OutFile "Income.csv"
git clone (استنساخ الملفين معًا)# 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
Option[T] الذي يلغي NullPointerException، والتعمق أكثر مع Either وfor-comprehensions.switch/case في Java أو match في Python 3.10+، لكن أقوى بكثير. إذا كنت تعرف بالفعل if/elif/else في Python، ستفهم بسهولة. تضيف Scala إمكانية التحقق من الأنواع، واستخراج البيانات من الكائنات، ووضع شروط — كل ذلك في صيغة واضحة ومختصرة.الأهداف التعليمية
1. تشبيه الفرز البريدي
تخيل مركز فرز بريدي. تصل كل رسالة على سير متحرك. ينظر الموظف إلى العنوان ويرسل الرسالة إلى الصندوق الصحيح: باريس يسارًا، ليون يمينًا، مرسيليا مباشرة. إذا لم يطابق العنوان أي شيء معروف، تذهب الرسالة إلى صندوق «أخرى».
تعمل مطابقة الأنماط تمامًا مثل هذا الفرز البريدي: نفحص قيمة، نقارنها بعدة أنماط، وننفذ الكود المرتبط بأول نمط يطابق.
if/else — مطابقة الأنماط أكثر قابلية للقراءة، وأكثر أمانًا (يتحقق المترجم من تغطية جميع الحالات مع sealed trait) وأقوى بكثير، لأنها تستطيع تفكيك كائنات معقدة، واستخراج القيم، والجمع بين النوع + القيمة + الشرط في case واحد.2. صيغة match/case
تعبير match يأخذ قيمة ويقارنها بسلسلة من عبارات case. تُنفذ أول عبارة مطابقة. على عكس switch في Java، لا يوجد break لكتابته — يتوقف Scala تلقائيًا عند أول حالة مطابقة.
match هو تعبير، وليس تعليمة. هذا يعني أنه يُرجع دائمًا قيمة. يمكنك كتابة val x = valeur match { ... }.مثال 1: أيام الأسبوع
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é"_ — الرمز _ (الشرطة السفلية) يطابق «كل ما تبقى». يجب وضعه دائمًا في النهاية، لأنه يلتقط كل شيء. بدونه، إذا لم يطابق أي case، يرفع Scala استثناء MatchError أثناء التنفيذ.مثال 2: تحويل درجة إلى تقدير
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 هو تعبير: يُرجع دائمًا قيمة.
ما يغيره عمليًا:
// 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"
}}"// 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 manquematch يُرجع قيمة، يتحقق المترجم من أن جميع الفروع تُرجع نفس النوع. إذا أرجع case String وآخر Int، يستنتج Scala النوع المشترك (Any). غالبًا ما يكون ذلك علامة على خطأ في التصميم.# 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# 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"يغطي هذا المقال المقتطفات الأكثر فائدة — الدورة الكاملة Scala PySpark Big Data (13 فصلاً، 47 درسًا، تمارين محلولة ومشروع نهائي) تأخذك إلى النهاية.
./acceder-au-cours-complet cours gratuit : Maîtriser Claude Codeالأسئلة الشائعة
كم من الوقت لتعلم Scala PySpark Big Data؟
هل هناك متطلبات مسبقة؟
من أين نبدأ عمليًا؟
📬 هل تريد تلقي هذا النوع من الأدلة كل أسبوع؟ اشترك مجانًا — كود حقيقي، بدون كلام فارغ.