دليل Validatar

سكربتات استيراد البيانات الوصفية — قوالب Python

Metadata Ingestion Scripts Python Templates

شرح لكيفية استخدام قوالب Python في اكتشاف البيانات الوصفية عبر سكربت واحد يعيد إطارات بيانات pandas بدلاً من استعلامات SQL منفصلة.

لوحة المتابعة

نظرة عامة

تستخدم قوالب مصادر البيانات القائمة على Python نهجًا مختلفًا جوهريًا عن نظيراتها المبنية على SQL في استيراد البيانات الوصفية. فبدلاً من استعلامات SQL منفصلة لكل مستوى من مستويات البيانات الوصفية، يستخدم قالب Python سكربتًا واحدًا يتصل ببرمجية بمصدر البيانات ويُعيد حتى ثلاثة إطارات بيانات pandas — واحد لكل من المخططات (schemas) والجداول (tables) والأعمدة (columns).

يتيح هذا النهج لـ Validatar اكتشاف البيانات الوصفية من مصادر لا تملك واجهة SQL، مثل REST APIs وأنظمة الملفات والتخزين السحابي والمنصات المخصصة وأي شيء آخر يمكن الوصول إليه عبر مكتبة Python.

تتناول هذه المقالة استيراد البيانات الوصفية لقوالب فئة Script. أما القوالب المبنية على SQL، فراجع مقالة Metadata Ingestion Scripts — SQL Templates.

تبويب Metadata Ingestion — قوالب Python

افتح قالب Python وانتقل إلى تبويب Metadata Ingestion. على عكس قوالب SQL التي تعرض تبويبات منفصلة لمستويات المخطط والجدول والعمود، تعرض قوالب Python محرر سكربت واحد فقط.

شكل 1: تبويب Metadata Ingestion — قوالب Python

كيف يعمل الاستيراد عبر Python

سكربت الاستيراد هو سكربت Python ينفذه Validatar عبر بيئة تشغيل Python المدمجة فيه. يقوم السكربت بما يلي:

  1. 1الوصول إلى معاملات القالب (مفاتيح API، مسارات الملفات، معلومات الاتصال) من سياق التنفيذ
  2. 2الاتصال بمصدر البيانات الخارجي باستخدام مكتبات Python المناسبة
  3. 3اكتشاف بنية البيانات الوصفية
  4. 4إعادة حتى ثلاثة إطارات بيانات pandas بأسماء وبنى أعمدة محددة

توفر بيئة تشغيل Python الخاصة بـ Validatar مكتبات pandas وrequests وغيرها من المكتبات الشائعة. يعمل السكربت في بيئة مُدارة مع إمكانية الوصول إلى المعاملات المعرّفة في تبويب Defaults الخاص بالقالب.

بنية إطار البيانات المتوقعة

ينبغي أن يُنتج السكربت إطارات بيانات بالأسماء والأعمدة المحددة التالية. ليست الإطارات الثلاثة كلها مطلوبة — أعد فقط الإطارات ذات الصلة بمصدر بياناتك.

إطار بيانات المخطط (Schema DataFrame)

اسم إطار البيانات: schemas

ColumnRequiredDescription
schema_nameYesاسم المخطط أو التجميع المنطقي

إطار بيانات الجدول (Table DataFrame)

اسم إطار البيانات: tables

ColumnRequiredDescription
schema_nameYesالمخطط الذي ينتمي إليه هذا الجدول
table_nameYesاسم الجدول أو المجموعة أو نقطة النهاية
table_typeNoتصنيف النوع (مثل TABLE أو VIEW أو ENDPOINT)

إطار بيانات العمود (Column DataFrame)

اسم إطار البيانات: columns

ColumnRequiredDescription
schema_nameYesالمخطط
table_nameYesالجدول
column_nameYesاسم العمود أو الحقل
data_typeYesنوع البيانات (يجب أن يطابق تعيينًا في تبويب Data Types)
ordinal_positionNoترتيب الحقل
is_nullableNoهل يسمح الحقل بالقيم الفارغة (YES / NO)

الوصول إلى المعاملات ضمن السكربتات

تكون معاملات القالب المعرّفة في تبويب Defaults متاحة ضمن سياق تنفيذ السكربت. وهذا ما يتيح للسكربت الحصول على بيانات الاعتماد وعناوين URL وقيم الإعداد الأخرى دون ترميزها مباشرة في الكود.

# Parameters are available through the execution context
# The exact access pattern depends on the parameter reference
# keys
# defined on the template's Defaults tab

import pandas as pd
import requests

# Access parameters
base_url = parameters['api_base_url']
api_key = parameters['api_key']
ملاحظة

يتم فك تشفير المعاملات السرية (مثل مفاتيح API) وقت التشغيل وتكون متاحة كنص واضح داخل السكربت. ينفذ السكربت في بيئة آمنة ومُدارة — لكن يجب الحرص على عدم تسجيل أو طباعة القيم الحساسة.

مثال: سكربت استيراد لواجهة REST API

يوضح هذا المثال سكربت استيراد كاملًا لواجهة REST API تستخدم Swagger/OpenAPI لوصف نقاط النهاية الخاصة بها:

import pandas as pd
import requests
import json

# Get parameters from template configuration
base_url = parameters['api_base_url']
api_key = parameters['api_key']

# Fetch the API schema (e.g., from a Swagger endpoint)
headers = {'Authorization': f'Bearer {api_key}'}
response = requests.get(f'{base_url}/swagger/v1/swagger.json',
    headers=headers)

spec = response.json()

# Build schema DataFrame
# For an API, "schemas" might represent API versions or resource groups
schema_records = []
for tag in spec.get('tags', []):
    schema_records.append({'schema_name': tag['name']})

schemas = pd.DataFrame(schema_records)

# Build table DataFrame
# Each API endpoint becomes a "table"
table_records = []
for path, methods in spec.get('paths', {}).items():
    for method, details in methods.items():
        tags = details.get('tags', ['default'])
        table_records.append({
            'schema_name': tags[0],
            'table_name': f'{method.upper()} {path}',
            'table_type': 'ENDPOINT'
        })

tables = pd.DataFrame(table_records)

# Build column DataFrame
# Response schema properties become "columns"
column_records = []
for path, methods in spec.get('paths', {}).items():
    for method, details in methods.items():
        tags = details.get('tags', ['default'])
        # Extract response schema properties
        responses = details.get('responses', {})
        success_response = responses.get('200', responses.get('201', {}))
        schema_ref = success_response.get('schema', {})

        if 'properties' in schema_ref:
            for i, (prop_name, prop_info) in enumerate(schema_ref['properties'].items()):
                column_records.append({
                    'schema_name': tags[0],
                    'table_name': f'{method.upper()} {path}',
                    'column_name': prop_name,
                    'data_type': prop_info.get('type', 'string'),
                    'ordinal_position': i + 1,
                    'is_nullable': 'YES'
                })

columns = pd.DataFrame(column_records)

مثال: سكربت استيراد لنظام ملفات

يكتشف هذا المثال البيانات الوصفية من مجلد يحتوي على ملفات CSV:

import pandas as pd
import os
import csv

# Get parameters
directory_path = parameters['directory_path']
file_pattern = parameters.get('file_pattern', '*.csv')

# Schema = the root directory
schemas = pd.DataFrame([{'schema_name': os.path.basename(directory_path)}])

# Each file is a "table"
table_records = []
column_records = []

for filename in os.listdir(directory_path):
    if filename.endswith('.csv'):
        filepath = os.path.join(directory_path, filename)
        table_name = os.path.splitext(filename)[0]

        table_records.append({
            'schema_name': os.path.basename(directory_path),
            'table_name': table_name,
            'table_type': 'FILE'
        })

        # Read header row to discover columns
        with open(filepath, 'r') as f:
            reader = csv.reader(f)
            headers = next(reader)
            for i, header in enumerate(headers):
                column_records.append({
                    'schema_name': os.path.basename(directory_path),
                    'table_name': table_name,
                    'column_name': header,
                    'data_type': 'string',   # CSV columns are string by default
                    'ordinal_position': i + 1,
                    'is_nullable': 'YES'
                })

tables = pd.DataFrame(table_records)
columns = pd.DataFrame(column_records)

كيف تعمل الإعدادات الافتراضية والتجاوزات

ينطبق نموذج الوراثة نفسه المستخدم مع قوالب SQL:

  1. 1يحدد القالب سكربت الاستيراد الافتراضي
  2. 2ترث مصادر البيانات التي تستخدم هذا القالب الإعداد الافتراضي
  3. 3يمكن لمصادر البيانات الفردية تجاوز السكربت بنسخة مخصصة في صفحة Schema Metadata

تُخزَّن التجاوزات على مستوى مصدر البيانات ولا تؤثر على القالب أو مصادر البيانات الأخرى.

نصائح لكتابة سكربتات استيراد Python

معالجة الأخطاء بسلاسة

يتصل سكربتك بأنظمة خارجية قد تكون غير متاحة أو محدودة المعدل أو تعيد استجابات غير متوقعة. استخدم كتل try/except وأعد رسائل خطأ ذات معنى:

try:
    response = requests.get(url, headers=headers, timeout=30)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    raise Exception(f"Failed to connect to API: {str(e)}")

احترام حدود معدل الطلبات

عند الاستيراد من واجهات API، احرص على مراعاة حدود معدل الطلبات (rate limits). أضف فترات تأخير مناسبة بين الطلبات إذا تطلب ذلك. عادةً ما يعمل استيراد البيانات الوصفية بشكل غير متكرر (يوميًا أو عند الطلب)، لذا فإن ثوانٍ قليلة من التأخير لكل طلب أمر مقبول.

اتساق أنواع البيانات

يجب أن تطابق قيم data_type في إطار بيانات الأعمدة التعيينات الموجودة في تبويب Data Types الخاص بالقالب. بالنسبة لمصادر API، قم بتعيين أنواع JSON (string، integer، number، boolean، array، object) إلى المدخلات المقابلة في إعداد Data Types.

إعادة إطارات بيانات فارغة، وليس None

إذا لم يكن لمصدر بياناتك مفهوم للمخططات (مثل واجهة API ذات نقطة نهاية واحدة)، فما زال يتعين عليك إعادة إطار بيانات schemas يحتوي على صف واحد على الأقل. استخدم اسم تجميع منطقي مثل اسم واجهة API أو اسم مصدر البيانات.

الاختبار التدريجي

عند تطوير سكربت استيراد جديد:

  1. 1ابدأ بإطار بيانات المخطط فقط وتحقق من استيراده بشكل صحيح
  2. 2أضف إطار بيانات الجدول وأعد الاختبار
  3. 3أضف إطار بيانات العمود أخيرًا
  4. 4تحقق من دليل البيانات (data catalog) بعد كل عملية استيراد للتأكد من النتائج

كيف يندرج هذا ضمن الصورة الأكبر

سكربتات استيراد Python هي ما يجعل وعد Validatar بـ"الاتصال بأي بيانات، في أي مكان" حقيقة واقعة. فبينما تغطي قوالب SQL قواعد البيانات التقليدية، تمتد قوالب Python بهذا الوصول ليشمل واجهات API والملفات والتخزين السحابي وأي مصدر بيانات آخر تتوفر له مكتبة Python.

بمجرد استيراد البيانات الوصفية — سواء أتت من سكربتات SQL أو Python — تكون التجربة اللاحقة متطابقة: التنميط (profiling)، توصيات الاختبار، تجسيد اختبارات القالب، والماكرو تعمل جميعها بالطريقة نفسها. طريقة الاستيراد تكون شفافة بالنسبة للمستخدمين الذين يعملون مع مصدر البيانات.

لمعرفة إعداد التنميط الخاص بـ Python، راجع مقالة Profiling Configuration — Python Templates. وللاطلاع على الصورة الكاملة من البداية للنهاية، راجع مقالة Data Source Templates: The Complete Picture.