Trie: هيكل البيانات اللي بيخلّي Autocomplete يرد قبل ما تخلّص الكتابة
لو search box عندك بيرسل request لـ DB مع كل حرف، وبيعمل LIKE 'q%' على عمود VARCHAR في جدول 500 ألف صف، كل استعلام بياخد 4 مللي ثانية تقريباً مع B-tree index. اضرب ده في 12 ضربة كيبورد لكل بحث، واضربه في 80 مستخدم في الثانية — الـ DB CPU بيوصل 90% بدون ما حد يفتح صفحة منتج. Trie بينقّل البحث ده من الـ DB كله للذاكرة، ويرد في 18 ميكروثانية لكل ضربة. الفرق 230×.
المشكلة باختصار
كل واجهة فيها autocomplete بتعاني من نفس النمط: كل حرف يكتبه المستخدم = طلب شبكة + استعلام DB. حتى مع cache كويس، الـ prefix search فيه latency ثابت ما تقدرش تتجاهله. والمشكلة بتكبر مع عدد المستخدمين، مش مع حجم الداتا.
الحل اللي بنشوفه على Google و Amazon و Slack مش سحر — هو هيكل بيانات قديم جداً اسمه Trie (1960)، بيشتغل في الذاكرة، وبيرد على prefix queries في زمن مستقل عن عدد الكلمات المخزّنة.
تخيّل أنك بتدوّر في قاموس ورقي
لما بتفتح قاموس عربي ورقي على كلمة "كتاب"، انت مش بتقرأ كل الـ 50 ألف كلمة من الأول. بتفتح حرف الكاف، بعدين بتدوّر على الصفحة اللي فيها الكلمات اللي بتبدأ بـ "كت"، وبعدين "كتا"، وبعدين "كتاب". كل خطوة بتقص نطاق البحث بحجم كبير.
Trie هو نفس الفكرة بالظبط. بدل ما تخزّن المفردات كقائمة مسطحة وتعمل scan في كل بحث، بتبني شجرة فيها كل عقدة بتمثّل حرف. الجذر فاضي، أبناء الجذر هم كل الحروف اللي ممكن كلمة تبدأ بيها، وأبناء كل حرف هم الحروف اللي ممكن تيجي بعده، وهكذا حتى تخلص الكلمة.
التعريف العلمي الدقيق
Trie (تنطق "تراي" نسبةً لـ retrieval، أو "تري") هو هيكل بيانات شجري من نوع k-ary tree، حيث k = حجم الأبجدية المستخدمة. كل عقدة بتخزّن حاجتين: (1) خريطة من الحروف لأبنائها، و(2) flag is_end بيقول "هل المسار من الجذر لحد هنا يمثّل كلمة كاملة موجودة في القاموس؟".
الزمن المطلوب لإدخال أو البحث عن كلمة طولها L هو O(L) بالظبط — ومش O(L × N) ولا O(L × log N). الزمن مستقل تماماً عن عدد الكلمات N المخزّنة في الـ Trie. ده الفرق الجوهري عن أي structure تاني.
الفرق بين Trie و Hash Map هنا حاسم: Hash Map بيدّيك O(1) للبحث عن كلمة كاملة، لكنه فاشل تماماً في "كل الكلمات اللي بتبدأ بـ pre". مفيش طريقة في Hash Map تجاوب على السؤال ده غير ما تـ scan كل المفاتيح. Trie بيحل المشكلتين في نفس الوقت.
الكود: Trie من الصفر في 30 سطر Python
الكود اللي تحت كامل وقابل للنسخ. مفيش أي مكتبة خارجية. بيشتغل على Python 3.12 وأحدث.