إعداد التنميط — قوالب Python
Profiling Configuration Python Templates
شرح كيفية إعداد التنميط لقوالب Python باستخدام سكربتات تعيد إطارات بيانات pandas بدلاً من تعريفات SQL منفصلة لكل مقياس.
نظرة عامة
تتبع قوالب مصادر البيانات القائمة على Python نهجًا مختلفًا في التنميط (profiling) عن نظيراتها المبنية على SQL. فبدلاً من تعريف تعريفات تنميط فردية بتعبيرات SQL التجميعية، تستخدم قوالب Python سكربتات تنميط — سكربتات Python كاملة تتصل بمصدر البيانات وتحسب المقاييس وتعيد النتائج كإطارات بيانات pandas.
يمنحك هذا النهج تحكمًا كاملًا في كيفية عمل التنميط لمصادر البيانات غير المبنية على SQL: يمكن تنميط واجهات API وأنظمة الملفات والتخزين السحابي والمنصات المخصصة جميعها باستخدام مكتبات Python نفسها المستخدمة في استيراد البيانات الوصفية.
تتناول هذه المقالة إعداد التنميط لقوالب فئة Script. أما القوالب المبنية على SQL، فراجع مقالة Profiling Configuration — SQL Templates.
تبويب Profiling — قوالب Python
افتح قالب Python وانتقل إلى تبويب Profiling. بدلًا من قائمة تعريفات التنميط، سترى سكربتات تنميط — سكربتات Python كاملة تحسب مقاييس التنميط.
كيف يختلف التنميط عبر Python عن التنميط عبر SQL
| Aspect | SQL Templates | Python Templates |
|---|---|---|
| وحدة الإعداد (Configuration unit) | تعريفات تنميط فردية (واحد لكل مقياس) | سكربتات تنميط (سكربت واحد يمكنه حساب عدة مقاييس) |
| التنفيذ (Execution) | تعبيرات SQL تُنفَّذ مقابل قاعدة البيانات | سكربتات Python تعمل ضمن بيئة تشغيل Python الخاصة بـ Validatar |
| التجميع (Batching) | يجمّع Validatar تلقائيًا عدة تنميطات في استعلامات فعّالة | يتحكم السكربت في كيفية حساب المقاييس وتجميعها |
| الوصول إلى البيانات (Data access) | SQL مباشر مقابل مصدر البيانات | عبر مكتبات Python (requests، pandas، عمليات إدخال/إخراج الملفات، إلخ) |
| المعاملات (Parameters) | لا ينطبق (يستخدم SQL عناصر نائبة للجدول/العمود) | معاملات القالب من تبويب Defaults متاحة |
| صيغة النتيجة (Result format) | مُعرّفة لكل تعريف تنميط | إطارات بيانات ببنية أعمدة متوقعة |
سكربتات التنميط
سكربت التنميط هو برنامج Python كامل يقوم بما يلي:
- 1الوصول إلى معاملات القالب لتفاصيل الاتصال
- 2الاتصال بمصدر البيانات
- 3قراءة أو استعلام البيانات لحساب المقاييس
- 4إعادة النتائج كإطار بيانات pandas ببنية محددة
بنية المخرجات المتوقعة
ينبغي أن تعيد سكربتات التنميط إطار بيانات بأعمدة تتوافق مع بنية نتائج التنميط في Validatar:
| Column | Required | Description |
|---|---|---|
| schema_name | Yes | المخطط الذي ينتمي إليه الكائن المُنمَّط |
| table_name | Yes | الجدول أو المجموعة التي يجري تنميطها |
| column_name | No | العمود (فارغ في التنميطات على مستوى الجدول) |
| profile_key | Yes | المفتاح المرجعي لتعريف التنميط (مثل record_count، null_count) |
| grouping_key | No | بالنسبة لتنميطات المصفوفات، بُعد التجميع |
| value | Yes | قيمة نتيجة التنميط (كسلسلة نصية) |
مثال: تنميط مصدر ملفات CSV
import pandas as pd
import os
# Access template parameters
directory_path = parameters['directory_path']
results = []
# Profile each CSV file (each file is a "table")
schema_name = os.path.basename(directory_path)
for filename in os.listdir(directory_path):
if not filename.endswith('.csv'):
continue
filepath = os.path.join(directory_path, filename)
table_name = os.path.splitext(filename)[0]
# Read the file
df = pd.read_csv(filepath)
# Table-level profiles
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': None,
'profile_key': 'record_count',
'grouping_key': None,
'value': str(len(df))
})
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': None,
'profile_key': 'column_count',
'grouping_key': None,
'value': str(len(df.columns))
})
# Column-level profiles
for col in df.columns:
# Null count
null_count = int(df[col].isnull().sum())
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': col,
'profile_key': 'null_count',
'grouping_key': None,
'value': str(null_count)
})
# Null percent
null_pct = round(null_count / len(df) * 100, 2) if len(df) > 0 else 0
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': col,
'profile_key': 'null_percent',
'grouping_key': None,
'value': str(null_pct)
})
# Distinct count
distinct_count = int(df[col].nunique())
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': col,
'profile_key': 'distinct_count',
'grouping_key': None,
'value': str(distinct_count)
})
# Min and max for numeric columns
if pd.api.types.is_numeric_dtype(df[col]):
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': col,
'profile_key': 'min',
'grouping_key': None,
'value': str(df[col].min())
})
results.append({
'schema_name': schema_name,
'table_name': table_name,
'column_name': col,
'profile_key': 'max',
'grouping_key': None,
'value': str(df[col].max())
})
profile_results = pd.DataFrame(results)مثال: تنميط مصدر REST API
import pandas as pd
import requests
# Access template parameters
base_url = parameters['api_base_url']
api_key = parameters['api_key']
headers = {'Authorization': f'Bearer {api_key}'}
results = []
# Get list of endpoints to profile
endpoints = [
{'schema': 'core', 'table': 'users', 'url': f'{base_url}/api/users'},
{'schema': 'core', 'table': 'orders', 'url': f'{base_url}/api/orders'},
]
for endpoint in endpoints:
try:
# Get record count via API (many APIs support count endpoints)
count_response = requests.get(
f"{endpoint['url']}/count",
headers=headers,
timeout=30
)
if count_response.ok:
count = count_response.json().get('count', 0)
results.append({
'schema_name': endpoint['schema'],
'table_name': endpoint['table'],
'column_name': None,
'profile_key': 'record_count',
'grouping_key': None,
'value': str(count)
})
# Get a sample to profile fields
sample_response = requests.get(
f"{endpoint['url']}?limit=1000",
headers=headers,
timeout=60
)
if sample_response.ok:
data = sample_response.json().get('data', [])
if data:
df = pd.DataFrame(data)
for col in df.columns:
null_count = int(df[col].isnull().sum())
results.append({
'schema_name': endpoint['schema'],
'table_name': endpoint['table'],
'column_name': col,
'profile_key': 'null_count',
'grouping_key': None,
'value': str(null_count)
})
distinct_count = int(df[col].nunique())
results.append({
'schema_name': endpoint['schema'],
'table_name': endpoint['table'],
'column_name': col,
'profile_key': 'distinct_count',
'grouping_key': None,
'value': str(distinct_count)
})
except requests.exceptions.RequestException:
continue # Skip endpoints that fail
profile_results = pd.DataFrame(results)كيف تتدفق سكربتات تنميط القالب إلى مصادر البيانات
تتبع العلاقة بين سكربتات تنميط القالب ومجموعات التنميط على مصدر البيانات نفس النمط المستخدم في قوالب SQL:
- 1يحدد القالب سكربتات التنميط (منطق التنميط المتاح)
- 2يملك مصدر البيانات مجموعات تنميط تحدد ما الذي يجب تنميطه ومتى
- 3تشير مجموعات التنميط إلى قدرات التنميط الخاصة بالقالب
- 4يستخدم التنفيذ سكربتات Python المحددة في القالب
تكون سكربتات التنميط في قوالب Python أقل تفصيلًا من تعريفات تنميط SQL. غالبًا ما يحسب سكربت واحد مقاييس عديدة دفعة واحدة، بينما تملك قوالب SQL تعريفًا واحدًا لكل مقياس. لذلك قد تقدم مجموعات التنميط على مصادر البيانات التي تستخدم قوالب Python خيارات تبديل فردية أقل.
نصائح لكتابة سكربتات التنميط
معالجة البيانات الناقصة بسلاسة
قد تعيد مصادر البيانات الخارجية بيانات غير مكتملة. تحقق دائمًا من القيم الفارغة والاستجابات الفارغة وأنواع البيانات غير المتوقعة قبل حساب المقاييس:
if len(df) > 0 and col in df.columns:
# Safe to calculate
null_pct = round(df[col].isnull().sum() / len(df) * 100, 2)استخدام مفاتيح تنميط متسقة
استخدم نفس مفاتيح التنميط المرجعية المستخدمة في تعريفات التنميط المبنية على SQL الجاهزة (record_count، null_count، distinct_count، إلخ). يضمن هذا عرضًا متسقًا في مستكشف البيانات (data explorer) وتوافقًا مع مجموعات بيانات الاختبار المستندة إلى التنميط.
احترام حدود معدل API
قد يتضمن التنميط عددًا كبيرًا من استدعاءات API، خاصة عند تنميط نقاط نهاية متعددة أو جلب بيانات عينة. طبِّق تحديدًا مناسبًا لمعدل الطلبات:
import time
for endpoint in endpoints:
# ... profile the endpoint ...
time.sleep(0.5) # Respect rate limitsإعادة جميع القيم كسلاسل نصية
ينبغي أن يحتوي عمود value في إطار بيانات نتائج التنميط دائمًا على قيم نصية. يتعامل Validatar مع تحويل الأنواع بناءً على صيغة تعريف التنميط. استخدم str() لتحويل جميع النتائج.
تحديد نطاق التنميط بشكل مناسب
بالنسبة لمصادر البيانات الكبيرة (عدد كبير من الملفات أو نقاط نهاية API)، ضع في اعتبارك تقييد التنميط إلى مجموعة فرعية يمكن إدارتها أو أخذ عينات من البيانات بدلًا من قراءة كل سجل. يمكن لمجموعات التنميط التحكم في الكائنات التي يجري تنميطها، لكن يجب أن يكون السكربت نفسه مرنًا أمام أحجام البيانات الكبيرة.
كيف يندرج هذا ضمن الصورة الأكبر
توسّع سكربتات تنميط Python قدرات التنميط في Validatar لتشمل أي مصدر بيانات يمكن لـ Python الوصول إليه. تُخزَّن نتائج التنميط الناتجة عنها وتُعرض بشكل مطابق لنتائج التنميط المبنية على SQL — يرى المستخدمون الذين يتصفحون مستكشف البيانات أو يضبطون درجات الثقة (trust scores) نفس المقاييس بغض النظر عما إذا كانت قد نتجت عن تعبير SQL تجميعي أو سكربت Python.
لمزيد من التفاصيل حول كيفية عمل مجموعات التنميط على مستوى مصدر البيانات، راجع مقالة Profile Sets. وللاطلاع على نظرة القالب الشاملة، راجع مقالة Data Source Templates: The Complete Picture.