استراتيجية التخزين: Valkey مقابل JSON مقابل NumPy
يشرح هذا المقال سبب استخدامنا لتقنيات تخزين مختلفة لأنواع مختلفة من البيانات في خطة عمل SEO وخدمة البحث.
المشكلة: لا يناسب الحل الواحد جميع الاحتياجات
البيانات المختلفة لها أنماط وصول مختلفة:
-
التضمينات (Embeddings) (5K × 384 رقم عائم): تحتاج إلى عمليات متجهية سريعة (تشابه جيب التمام)
-
تعيينات العبارات (أكثر من 2500 عبارة): تحتاج إلى تحرير بشري، التحكم بالإصدارات
-
ذاكرة التخزين المؤقت للاستعلامات (استعلامات حية): تحتاج إلى عمليات بحث سريعة من نوع مفتاح-قيمة، وانتهاء صلاحية TTL
-
بيانات المنتج (64 ألف منتج): تحتاج إلى وصول منظم، قواعد التوافق
استخدام نفس التخزين لكل هذه الأنواع سيكون غير فعال.
ثلاث تقنيات تخزين
1. مصفوفات NumPy: العمليات المتجهية
حالة الاستخدام: التضمينات (المنتجات، الاستعلامات، العبارات)
لماذا NumPy:
-
رياضيات متجهية سريعة: مكتبات C/Fortran مُحسَّنة لعمليات المصفوفات
-
ملفات معينة للذاكرة (Memory-mapped): تحميل مصفوفات كبيرة دون نسخها إلى ذاكرة الوصول العشوائي (RAM)
-
عمليات الدُفعات: معالجة آلاف المتجهات في أجزاء من الثانية
-
تنسيق قياسي: متوافق مع مكتبات تعلم الآلة (scikit-learn, TensorFlow)
تنسيق الملف: ملفات ثنائية .npy
التحميل:
import numpy as np
# معينة للذاكرة (لا تحمل الملف بأكمله إلى ذاكرة الوصول العشوائي)
embeddings = np.load('embeddings.npy', mmap_mode='r')
# حساب تشابه جيب التمام
from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity(query_embedding, embeddings)
الأداء: عمليات بحث ضخمة عن التشابه بسرعات مناسبة للاستدلال الفوري (real-time inference).
2. ملفات JSON: البيانات القابلة للتحرير البشري
حالة الاستخدام: التكوين، التعيينات، البيانات الوصفية (Metadata)
لماذا JSON:
-
قابلة للقراءة البشرية: سهلة الفحص والتشخيص
-
التحكم بالإصدارات: يعرض Git diff بالضبط ما تغير
-
التحرير اليدوي: يمكن إصلاح الأخطاء دون الحاجة إلى كود
-
تنسيق عالمي: كل لغة برمجة يمكنها تحليل JSON
ما نخزنه:
-
تعيينات العبارة إلى المرشح (Filter): عبارات → قواعد التصفية
-
ميزات المنتج: منتجات → قواميس الميزات
-
البيانات الوصفية للاستعلام: استعلامات → نقرات، ظهورات، مصادر
-
تكوين خط العمل: معاملات الخطوة، العتبات
تنسيق الملف: ملفات نصية .json
التحميل:
import json
with open('phrase_mappings.json') as f:
mappings = json.load(f)
# الوصول إلى البيانات
filters = mappings['mini pc'] # ['form_factor:mini', 'category:pc']
3. Valkey (Redis): ذاكرة تخزين مؤقت سريعة من نوع مفتاح-قيمة
حالة الاستخدام: البحث المباشر، الإكمال التلقائي، الاستعلامات الشائعة
لماذا Valkey:
-
في الذاكرة: زمن انتقال ميكروثانية لعمليات البحث
-
RediSearch: بحث تشابه متجهي مع فهارس
-
انتهاء صلاحية TTL: إبطال ذاكرة التخزين المؤقت تلقائيًا
-
النشر/الاشتراك (Pub/sub): تحديثات فورية عبر الخوادم
-
الثبات (Persistence): لقطات قرص اختيارية للمتانة
ما نخزنه:
-
ذاكرة التخزين المؤقت لتضمينات الاستعلام: الاستعلامات الحديثة → تضمينات
-
الاستعلامات الشائعة: أفضل 1000 استعلام حسب حركة المرور
-
فهرس الإكمال التلقائي: البادئة → اقتراحات الاستعلام
-
ذاكرة التخزين المؤقت لاستخراج المرشحات: الاستعلام → المرشحات المستخرجة
-
ذاكرة التخزين المؤقت للبحث ذي الصلة: الاستعلام → استعلامات ذات صلة
هياكل البيانات:
-
السلاسل النصية (Strings): مفتاح-قيمة بسيط (استعلام → تضمين)
-
المجموعات المرتبة (Sorted sets): بيانات مصنفة (استعلامات شائعة حسب النتيجة)
-
فهارس RediSearch: بحث تشابه متجهي
-
الجداول التجزئة (Hashes): بيانات منظمة (بيانات وصفية للاستعلام)
التحميل:
from app.shared.valkey_cache import get_valkey
valkey = get_valkey()
# ... (تفاصيل التنفيذ محذوفة)
مصفوفة القرار
متى تستخدم NumPy
المعايير:
-
البيانات رقمية (أرقام عائمة، أعداد صحيحة)
-
تحتاج إلى عمليات متجهية سريعة (ضرب نقطي، تشابه جيب التمام)
-
البيانات ثقيلة القراءة (نادرًا ما يتم تحديثها)
-
البيانات كبيرة (ملايين الأرقام)
-
معالجة دُفعية (معالجة العديد من العناصر دفعة واحدة)
أمثلة:
-
التضمينات (المنتجات، الاستعلامات، العبارات)
-
نواقل الميزات (Feature vectors)
-
مصفوفات التشابه
متى تستخدم JSON
المعايير:
-
البيانات منظمة (كائنات، مصفوفات)
-
تحتاج إلى قابلية القراءة البشرية
-
تحتاج إلى التحكم بالإصدارات (Git)
-
البيانات تتغير أحيانًا (تحرير يدوي)
-
البيانات صغيرة-متوسطة (<100 ميجابايت)
أمثلة:
-
ملفات التكوين
-
تعيينات العبارات
-
البيانات الوصفية للمنتج
-
معاملات خط العمل
متى تستخدم Valkey
المعايير:
-
تحتاج إلى عمليات بحث سريعة (ميكروثانية)
-
البيانات تتغير بشكل متكرر (استعلامات حية)
-
تحتاج إلى انتهاء صلاحية TTL (إبطال ذاكرة التخزين المؤقت)
-
تحتاج إلى نشر/اشتراك (تحديثات فورية)
-
تحتاج إلى بحث متجهي (RediSearch)
أمثلة:
-
ذاكرة التخزين المؤقت للاستعلام
-
الإكمال التلقائي
-
الاستعلامات الشائعة
-
بيانات الجلسة
-
تحديد معدل الطلبات (Rate limiting)
نهج هجين
نحن نجمع بين الثلاثة للحصول على أفضل أداء:
خط العمل (المعالجة خارج الخط)
NumPy: حساب التضمينات، مصفوفات التشابه
JSON: تخزين التعيينات، البيانات الوصفية، التكوين
Valkey: غير مستخدم (خط العمل يعمل خارج الخط)
خدمة البحث (استعلامات حية)
NumPy: تحميل التضمينات من القرص (معينة للذاكرة)
JSON: تحميل التعيينات من القرص (مخزنة مؤقتًا في الذاكرة)
Valkey: تخزين مؤقت للاستعلامات الحية، الإكمال التلقائي، الاستعلامات الشائعة
تدفق البيانات
graph LR
Pipeline[خط عمل SEO
خارج الخط]
subgraph Storage
NP[ملفات NumPy
embeddings.npy]
JS[ملفات JSON
mappings.json]
end
Search[خدمة البحث
مباشر]
VK[Valkey
ذاكرة تخزين مؤقت]
Pipeline --> NP
Pipeline --> JS
NP --> Search
JS --> Search
Search --> VK
VK --> Searchمقارنة الأداء
NumPy (معينة للذاكرة):
-
وقت التحميل: فوري (تعيين بدون نسخ إلى الذاكرة الظاهرية)
-
وقت البحث: قريب من الصفر (مؤشر وحدة المعالجة المركزية مباشرة إلى فهرس المصفوفة)
-
الذاكرة: ضئيلة (ذاكرة التخزين المؤقت للصفحات المدارة بواسطة نظام التشغيل، غير مقيمة في ذاكرة الوصول العشوائي للعملية)
JSON:
-
وقت التحميل: زمن انتقال مرتفع (تحليل تسلسلي وإنشاء كائنات)
-
وقت البحث: فعال (نفقات عامة قياسية لخريطة التجزئة)
-
الذاكرة: كبيرة (هيكل التسلسل بأكمله مقيم في الكومة)
Valkey:
-
وقت التحميل: ثابت (مقيم في خدمة الخلفية)
-
وقت البحث: متوسط (يشمل رحلة ذهاب وإياب عبر الشبكة وتسلسل البروتوكول)
-
الذاكرة: خارجية (معزولة داخل عملية قاعدة البيانات)
الفائز: NumPy للمعالجة الدُفعية عالية الإنتاجية، Valkey للوصول الموزع للمفتاح الواحد
بحث التشابه المتجهي
NumPy (cosine_similarity):
-
عمليات الدُفعات: سريعة (مُحسَّنة عبر الجبر الخطي المتجهي/SIMD)
-
قابلة للتوزيع: عالية (تتوسع عبر جميع نوى وحدة المعالجة المركزية المتاحة)
-
الذاكرة: خطية (تتوسع مباشرة مع أبعاد التضمين)
Valkey (RediSearch):
-
سرعة البحث: متفوقة (تستخدم فهرسة HNSW/Vector المتخصصة)
-
قابلة للتوزيع: محدودة (مقيدة بنموذج خيوط المحرك)
-
الذاكرة: مكثفة (تتطلب تضمينات أولية بالإضافة إلى بيانات وصفية للفهرسة)
الفائز: Valkey للبحث المباشر دون الإدراك الحسي، NumPy للمعالجة التحليلية الثقيلة خارج الخط
بحث التكوين
JSON:
-
وقت التحميل: متغير (يتناسب مع تعقيد التكوين)
-
وقت البحث: سريع (وصول قياسي للقاموس)
-
وقت التحرير: سلس (تعديل نصي قابل للقراءة البشرية)
Valkey:
-
وقت التحميل: فوري (نشط عند الاتصال)
-
وقت البحث: مقيد بالشبكة (يعتمد على النفقات العامة للطلب)
-
وقت التحرير: برمجي (يتطلب أوامر CLI أو SET من العميل)
الفائز: JSON للتكوينات الثابتة، Valkey للحالة المشتركة الديناميكية
المراجع
التقنيات
-
NumPy - مكتبة حساب المصفوفات
-
JSON - تنسيق تبادل البيانات
-
Valkey - مخزن بيانات في الذاكرة (فرع من Redis)
-
RediSearch - وحدة بحث متجهي
المفاهيم التقنية
-
ملف معين للذاكرة (Memory-mapped file) - ويكيبيديا
-
قاعدة بيانات مفتاح-قيمة - ويكيبيديا
-
قاعدة بيانات متجهية - ويكيبيديا
مقالات ذات صلة
-
نظرة عامة على خط عمل SEO - هيكل خط العمل الكامل
-
هيكل خدمة البحث - بحث مباشر باستخدام Valkey
-
هيكل متعدد الخوادم - التخزين لكل خادم
-
المعالجة التدريجية - استراتيجية التخزين المؤقت
الملخص
نستخدم ثلاث تقنيات تخزين مُحسَّنة لحالات استخدام مختلفة:
NumPy (التضمينات):
-
عمليات متجهية سريعة (تشابه جيب التمام)
-
معينة للذاكرة
-
معالجة دُفعية
-
تنسيق قياسي لتعلم الآلة
JSON (التكوين):
-
قابلة للقراءة البشرية (سهلة التشخيص)
-
التحكم بالإصدارات (Git diffs)
-
تحرير يدوي (لا حاجة للكود)
-
تنسيق عالمي
Valkey (ذاكرة التخزين المؤقت المباشرة):
-
عمليات بحث سريعة (ميكروثانية)
-
بحث متجهي (RediSearch)
-
انتهاء صلاحية TTL (إبطال تلقائي)
-
نشر/اشتراك (تحديثات فورية)
النهج الهجين: استخدم الأداة المناسبة لكل مهمة، واجمعها للحصول على أفضل أداء.