في المشهد المتطور لهندسة البيانات، واجهت بنية بحيرة البيانات التقليدية عنق زجاجة حرج: عدم الدعم الأصلي لمعاملات ACID (الذرية، الاتساق، العزل، المتانة). بينما توفر بحيرات البيانات قابلية هائلة للتوسع وتخزين منخفض التكلفة، فإنها تواجه صعوبات في سلامة البيانات عندما يحاول عدة كتابات تعديل البيانات في وقت واحد. هنا يأتي دور Apache Hudi (Hadoop Upserts Deletes and Incrementals)، وهو إطار عمل مفتوح المصدر يحل هذه المشكلة من خلال تمكين تحديثات البيانات بكفاءة ومعالجة البيانات التزايدية مباشرة على أنظمة التخزين الموزعة مثل HDFS وS3 وADLS.
ما المشكلة التي يحلها Apache Hudi؟
تاريخياً، إذا أردت تحديث سجل في ملف Parquet أو ORC مخزن في بحيرة بيانات، كان عليك إعادة كتابة الملف بأكمله. هذه العملية مكلفة حسابياً وغير فعالة. يقدم Apache Hudi مفهوم "الدمج" (Upserts) (تحديث + إدراج) و"الحذف" على مستوى الملف. يدير هذه التغييرات من خلال الحفاظ على البيانات الوصفية واستخدام تنسيقات تخزين فعالة، مما يسمح بإجراء استعلامات في نقاط زمنية محددة والتكامل المستمر للبيانات.
من خلال تنفيذ مفتاح السجل ومسار القسم، يمكن لـ Hudi تحديد سجلات محددة ضمن مجموعات بيانات ضخمة، مما يضمن تحديث الملفات الضرورية فقط بدلاً من مجموعة البيانات بأكملها. هذهCapability أساسية لبناء بحيرات بيانات حديثة (Data Lakehouses).
مفاهيم البنية الأساسية
للاستفادة من Hudi بشكل فعال، يجب على المطورين فهم مكوناته الأساسية. يعتمد النظام على عدد قليل من المعلمات الرئيسية لإدارة استيعاب البيانات:
- مفتاح السجل (Record Key): معرف فريد لكل صف (على سبيل المثال، user_id).
- مسار القسم (Partition Path): بنية الدليل المستخدمة لتقسيم البيانات (على سبيل المثال، ds=2023-10-01).
- أنواع العمليات: يدعم Hudi عمليات INSERT وUPSERT وDELETE.
يدعم Hudi أنواعاً متعددة من الجداول، بما في ذلك Copy-On-Write (COW) وMerge-On-Read (MOR). جداول COW محسنة لأحمال العمل الثقيلة في القراءة، حيث يتم تطبيق التحديثات على الملفات الأساسية. جداول MOR، من ناحية أخرى، مصممة لأحمال العمل الثقيلة في الكتابة، حيث تحتفظ بالتغييرات الأخيرة في ملفات سجل منفصلة لتقليل زمن كتابة البيانات وتعظيم الإنتاجية.
التطبيق العملي مع Spark
دمج Apache Hudi سلس مع Apache Spark. فيما يلي مثال عملي حول كيفية تسجيل جدول Hudi وإجراء عملية دمج (Upsert) باستخدام PySpark. يوضح هذا المثال كيفية كتابة DataFrame كجدول Hudi، مع تحديد نوع الجدول كـ COW لأداء قراءة محسن.
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("HudiUpsertExample") \
.getOrCreate()
# بيانات نموذجية لاستيعابها
data = [
(1, "Alice", 30, "2023-10-01"),
(2, "Bob", 25, "2023-10-01"),
(3, "Charlie", 35, "2023-10-01")
]
df = spark.createDataFrame(data, ["id", "name", "age", "dt"])
# تحديد خصائص الجدول لـ Hudi
props = {
"hoodie.table.name": "hudi_test_table",
"hoodie.datasource.write.partitionpath.field": "dt",
"hoodie.datasource.write.recordkey.field": "id",
"hoodie.table.type": "COPY_ON_WRITE",
"hoodie.datasource.write.operation": "upsert"
}
# كتابة DataFrame إلى Hudi
df.write \
.format("hudi") \
.options(**props) \
.mode("overwrite") \
.save("s3://my-bucket/data/hudi_table")
السفر عبر الزمن والاستعلامات التزايدية
إحدى أقوى ميزات Hudi هي "السفر عبر الزمن" (Time Travel). لأن Hudi يلتزم بكل تغيير، يمكنك استعلام حالة بياناتك في أي نقطة زمنية سابقة. هذا لا يقدر بثمن لتصحيح مشكلات جودة البيانات أو تكرار الحالات التاريخية دون الحفاظ على لقطات تاريخية منفصلة. بالإضافة إلى ذلك، يمكّن Hudi الاستعلامات التزايدية، مما يسمح للعمليات اللاحقة باستلام التغييرات فقط منذ آخر استيعاب، مما يقلل بشكل كبير من تكاليف المعالجة.
الخاتمة
يُسدل Apache Hudi الفجوة بين بحيرات البيانات التقليدية والمتطلبات القوية للمعاملات في التحليلات الحديثة. من خلال توفير الدعم الأصلي للدمج (Upserts) والحذف والسفر عبر الزمن، فإنه يمكّن مهندسي البيانات من بناء بنية بحيرات بيانات (Data Lakehouses) موثوقة وقابلة للتوسع وفعالة من حيث التكلفة. بينما يقدم بعض التعقيد في التكوين والإدارة، فإن فوائد الامتثال لـ ACID على تخزين الكائنات الرخيص تجعله خياراً مقنعاً للمنظمات التي تتعامل مع مجموعات بيانات عالية الحجم ومتكررة التحديث.