← dovmem · بحث عربي ذكي · Arabic Search · English

ليش البحث العربي في SQLite ما يلقى الكلمة، وكيف تصلحه

5 أكتوبر 2026 · كل النتائج تحت مجرّبة فعليًا على SQLite 3.50.4

المشكلة في سطرين

عندك تطبيق ملاحظات أو رسائل يحفظ النصوص في SQLite، والمستخدم يكتب «مذكرة» في البحث. النص موجود قدامه بأكثر من شكل: «المُذَكِّرَة» و«للمذكرة» و«والمذكره». البحث العادي يرجّع له جزء منها بس، أو ما يرجّع شي.

جرّبنا هالأربع جمل في جدول SQLite:

  • لازم نكتب مذكرة تفاهم
  • راجعت المُذَكِّرَة أمس
  • أضفت للمذكرة ملاحظات
  • والمذكره ضاعت

١) LIKE: يفوّت التشكيل واختلاف الكتابة، ويمر على كل الصفوف

SELECT body FROM notes WHERE body LIKE '%مذكرة%';

النتيجة: «لازم نكتب مذكرة» و«أضفت للمذكرة» بس. فوّت «المُذَكِّرَة» لأن التشكيل حروف زيادة بين الحروف، وفوّت «والمذكره» لأن الهاء غير التاء المربوطة.

وفيه مشكلتين ثانيتين: LIKE '%علم%' يطابق داخل كلمات ما لها علاقة مثل «المعلم» و«العلمي». وEXPLAIN QUERY PLAN يقول SCAN، يعني يقرأ كل صف في الجدول مع كل بحث، فيبطأ كل ما كبرت البيانات.

٢) FTS5: سريع، لكنه يطابق الكلمة كاملة بس

CREATE VIRTUAL TABLE notes_fts USING fts5(body, tokenize='unicode61');
SELECT body FROM notes_fts WHERE notes_fts MATCH '"مذكرة"';

FTS5 يستخدم فهرس، فهو سريع حتى مع مئات الآلاف من الصفوف. لكنه يقسم النص لكلمات ويطابق الكلمة كما هي: النتيجة «لازم نكتب مذكرة» بس. «للمذكرة» عنده كلمة ثانية، و«المُذَكِّرَة» المشكّلة كلمة ثالثة.

وحتى البحث ببداية الكلمة ("مذكرة"*) ما يفيد، لأن السابقة في أول الكلمة مو في آخرها. وخيار remove_diacritics 2 في unicode61 ما يشيل التشكيل العربي: جرّبناه، و«المذكرة» ما لقت «المُذَكِّرَة».

الأسباب الثلاثة

السببمثالLIKEFTS5
التشكيل والتطويلمُذَكِّرَة، كتـــابيفوّتيفوّت
أكثر من كتابة للحرفأ إ آ ا، ة ه، ى ي، ؤ ويفوّتيفوّت
السوابق الملتصقةال، لل، بال، و، بيلقى، مع تطابقات غلطيفوّت

الحل الأول: وحّد النص (مجاني)

شيل التشكيل والتطويل، ووحّد «أ إ آ ٱ» إلى «ا»، و«ى ئ» إلى «ي»، و«ة» إلى «ه»، و«ؤ» إلى «و». وطبّقها على الطرفين: النص اللي تحفظه، والكلمة اللي يبحث عنها المستخدم.

pip install https://github.com/musaed300/arabic-search-lite/releases/download/v1.0.0/arabic_search_lite-1.0.0-py3-none-any.whl

from arabic_search_lite import normalize
normalize("المُذَكِّرَة")   # "المذكره"

احفظ نسخة موحّدة من النص في عمود ثاني، وابحث فيه بالكلمة بعد توحيدها. هالخطوة لحالها تصلّح أول سببين. هذي مكتبة arabic-search-lite المجانية برخصة MIT، لـPython وJavaScript.

بس السبب الثالث يظل: مع FTS5 «للمذكره» تبقى كلمة غير «مذكره»، ومع LIKE ترجع التطابقات الغلط والمرور على كل الصفوف.

الحل الثاني: FTS5 مع فصل السوابق

الفكرة: وقت الحفظ، كل كلمة عربية تنحفظ في الفهرس بشكلها الموحّد، ومعها شكلها بدون السابقة. «للمذكرة» تنحفظ كـ«للمذكره» و«مذكره». ووقت البحث، كل كلمة تتحول لبحث ببداية الكلمة على الشكلين. فالفهرس يرجّع الجمل الأربع، وبسرعة FTS5.

الصعوبة الحقيقية إن العربي ملتبس: الواو في «وصل» والفاء في «فكرة» والباء في «بيت» من أصل الكلمة، مو سوابق. لازم قواعد تحدد متى تفصل: مثلًا تخلي الجذع حرفين على الأقل بعد «ال»، وثلاثة بعد حرف مفرد مثل و وب. وحتى مع هالقواعد يبقى التباس قليل: البحث عن «كرة» ممكن يلقى «فكرة».

وفيه حدود لازم تعرفها: فصل السوابق ما يحلّل اللواحق (مذكرتي، مذكرات)، وما يستخرج الجذور («كتب» ما تلقى «مكتبة»)، وما يعرف مرادفات اللهجات («وش» ما تلقى «ماذا»).

جرّبها بنفسك

في صفحة «بحث عربي ذكي» تجربة مباشرة: تكتب أي كلمة عربية، وتشوف نفس الـ20 جملة في جدولين FTS5، العادي والمعدّل، جنب بعض.

«بحث عربي ذكي» مكتبة جاهزة تسوي الحل الثاني كامل: توحيد، وفصل سوابق بقواعد مجرّبة، وفهرس FTS5 واستعلاماته، ومقتطفات تلوّن الكلمة. بـSwift وPython وJavaScript بنفس النتيجة، بـ29$ مرة وحدة.


Why Arabic search in SQLite misses words, and how to fix it

October 5, 2026 · Every result below was run on SQLite 3.50.4

The problem

Your notes or chat app stores text in SQLite, and a user searches for «مذكرة» (memo). The word is there in several forms: «المُذَكِّرَة» with diacritics, «للمذكرة» with an attached prefix, «والمذكره» with a different final letter. Plain search returns only some of them, or none.

1) LIKE misses diacritics and spelling variants, and scans every row

SELECT body FROM notes WHERE body LIKE '%مذكرة%';

It found «مذكرة» and «للمذكرة», and missed «المُذَكِّرَة» (diacritics are extra characters) and «والمذكره» (ه is not ة). LIKE '%علم%' also matches inside unrelated words such as «المعلم», and EXPLAIN QUERY PLAN shows a full SCAN on every search.

2) FTS5 is fast but matches whole words only

CREATE VIRTUAL TABLE notes_fts USING fts5(body, tokenize='unicode61');
SELECT body FROM notes_fts WHERE notes_fts MATCH '"مذكرة"';

It returned only the exact word. To the tokenizer «للمذكرة» is another word. A prefix query ("مذكرة"*) does not help because Arabic prefixes come at the start of the word, and unicode61 with remove_diacritics 2 does not remove Arabic diacritics: we tried it.

Fix 1: normalize (free)

Remove diacritics and tatweel; turn أ إ آ ٱ into ا, ى ئ into ي, ة into ه and ؤ into و; apply it to the stored text and to the query. That fixes the first two causes. arabic-search-lite does exactly this, free under MIT, for Python and JavaScript.

Fix 2: FTS5 with prefix stems

At indexing time, store each Arabic word normalized and also without its attached prefix; at query time, search both forms as prefix queries. The hard part is ambiguity: و in «وصل» and ف in «فكرة» belong to the word, so you need stem-length rules, and a little ambiguity remains. It does not analyse suffixes, extract roots or know dialect synonyms.

Arabic Search is a ready library for this, in Swift, Python and JavaScript with identical results, for a one-time $29. Try it on any Arabic word: live demo.