ذكاء محلي أولاً: هندسة Vector Search مباشرة في Expo باستخدام SQLite VSS
توقف عن إرسال كل استعلام إلى الـ Cloud. أتعمق هنا في كيفية دمج SQLite VSS داخل بيئة Expo لتحقيق Vector Similarity Search في أقل من 10 مللي ثانية محلياً على الجهاز.

ما وراء شريط البحث: هندسة On-Device Vector Search باستخدام Expo و SQLite VSS
لفترة طويلة، كانت المعمارية المتبعة للبحث المدعوم بالـ AI متوقعة: التقاط استعلام المستخدم، إرساله إلى السيرفر، توليد Embedding عبر OpenAI، ثم الاستعلام من Pinecone أو Weaviate، وأخيراً إعادة النتائج. هذه الطريقة تعمل، لكنها بطيئة (Latent)، مكلفة، وتمثل كابوساً للخصوصية عندما يتعلق الأمر ببيانات المستخدم الحساسة.
مؤخراً، قررت كسر هذه الحلقة. أردت معرفة ما إذا كان بإمكاني جلب Vector Similarity Search عالي الأداء مباشرة إلى تطبيق Expo. هدفي؟ عمليات بحث محلية في أقل من 10 مللي ثانية وبدون تكاليف نقل بيانات (Egress costs).
إليك كيف هندست حلاً باستخدام SQLite VSS ونظام ملفات Expo الحديث.
تحول الهيكلية (The Architecture Shift)
نقل الـ Vector Search إلى الـ Edge (هاتف المستخدم) يتطلب ثلاثة أشياء:
- Storage: قاعدة بيانات محلية تفهم الـ Vectors.
- Indexing: طريقة لإجراء عمليات بحث K-Nearest Neighbor (KNN) دون فحص خطي لكل قاعدة البيانات.
- Embeddings: طريقة لتحويل النص إلى أرقام محلياً (باستخدام
transformers.jsأو مكتبات مشابهة).
بينما تعتبر expo-sqlite هي المعيار الصناعي للبيانات المحلية، إلا أنها لا تدعم الـ Vector types بشكل افتراضي. هنا يأتي دور sqlite-vss — وهي إضافة مبنية على Faiss.
الاختراق التقني: إدخال VSS إلى Expo
تطبيق Expo Go القياسي لا يتضمن إضافة sqlite-vss. ولجعل هذا الأمر يعمل، كان علي الانتقال إلى عالم Development Builds.
العقبة التقنية هي أن sqlite-vss عبارة عن إضافة مكتوبة بلغة C++. باستخدام expo-sqlite/next (الـ API الجديد عالي الأداء)، يمكننا نظرياً تحميل الإضافات، لكن العمل الثقيل يحدث في إعدادات الـ Native build.
1. إعداد الـ Virtual Table
بمجرد ربط الإضافة، يحدث السحر من خلال الـ Virtual Tables. على عكس جداول SQL القياسية، جداول vss0 محسنة لمصفوفات الأرقام العشرية عالية الأبعاد (High-dimensional floating-point arrays).
2. إدراج البيانات
عندما يقوم المستخدم بحفظ ملاحظة، أقوم بتوليد الـ Embedding على الـ Main thread (أو Web worker) وإدراجه في كلا الجدولين. يتوقع جدول vss_notes مصفوفة JSON من الأرقام.
الاستعلام: Semantic Search في أقل من 10 مللي ثانية
هنا يظهر ثمار المجهود الهندسي. بدلاً من استخدام LIKE %query% التقليدية، نقوم بإجراء بحث عن التشابه. توفر SQLite VSS دالة vss_search وهي فعالة للغاية.
في تجاربي على جهاز iPhone 14، استغرق الاستعلام في مجموعة بيانات تضم 1,000 مستند حوالي 6 مللي ثانية. هذا أسرع مما يمكن لأي API round-trip أن تحلم به.
التغلب على قيود الذاكرة (Memory Constraint)
شيء واحد تعلمته بالطريقة الصعبة: الـ Embeddings ثقيلة.
إذا كان لديك 10,000 صف مع Vectors بـ 1536 بعداً (بأسلوب OpenAI)، فسوف يتضخم ملف SQLite بشكل كبير. للحفاظ على سرعة التطبيق، اخترت نماذج بـ 384 بعداً (مثل bge-small-en). إنها توفر توازناً مثالياً بين الدقة الدلالية (Semantic accuracy) واستهلاك الذاكرة على الجهاز.
لماذا يهمنا هذا الأمر؟
كمهندسين محترفين، غالباً ما نتجه تلقائياً لحلول الـ Cloud لأنها "أسهل" في التنفيذ. لكن الهندسة الموجهة للجهاز أفضل للمستخدم. من خلال الاحتفاظ بالـ Vectors في sqlite-vss:
- Offline first: يعمل البحث في تطبيقك في الأنفاق أو على الطائرة.
- Zero Latency: تبدو تحديثات واجهة المستخدم فورية.
- Privacy: أفكار المستخدم الخاصة (ملاحظاته، مذكراته، أو بياناته) لا تغادر السيليكون الموجود في جيبه أبداً.
كلمات أخيرة
الفجوة بين ما يمكن أن يفعله الـ Backend وما يمكن أن يفعله الهاتف المحمول تتقلص. إذا كنت تبني تطبيق Expo في عام 2024، فلا تكتفِ ببناء شريط بحث عادي — بل ابنِ محرك ذكاء محلي (Local intelligence engine).
أقوم حالياً بالتجربة مع طرق الـ Quantization لتناسب مجموعات Vectors أكبر في ذاكرة الهاتف. إذا كنت قد تعاملت مع الـ Local indexing، سأكون سعيداً بسماع نهجك في التعليقات.