لست خبيرًا تقنيًا، ولكني كنت أبحث في هذه المشكلة لأنني أريد التأكد من عدم تفويت أي استعلامات بحث في منتدى ثنائي اللغة بالفارسية والعربية. نظرًا لأن Discourse يستخدم PostgreSQL، فإن التطبيع يصبح ضروريًا: قد يبحث المستخدم باستخدام أحرف فارسية، بينما يتم تخزين نفس الكلمة باستخدام أحرف عربية - أو العكس. بدون تطبيع مناسب، ستفشل عملية البحث.
بناءً على ما تعلمته، فإن استخدام تطبيع Unicode NFKC هو نقطة انطلاق قوية - فهو يتعامل مع العديد من حالات التوافق مثل الروابط، وأشكال العرض، والأرقام العربية/الفارسية.
ومع ذلك، بالنسبة للنص الفارسي والعربي، لا يكفي NFKC وحده. فهو لا يقوم بتطبيع العديد من المتغيرات الحرفية الهامة المتكافئة بصريًا ودلاليًا ولكنها تختلف على المستوى الثنائي.
أدناه، أقدم الإجراءات والرؤى التي توصلت إليها من خلال بحثي واستكشافي.
रणनी استراتيجية التصميم الشاملة
- طبق تطبيع Unicode NFKC أولاً للتعامل مع الروابط، وأشكال العرض، وتوحيد الأرقام.
- ثم طبق تعيينات الأحرف المخصصة بترتيب محدد (على سبيل المثال، تطبيع متغيرات الهمزة قبل الياء العربية).
- فصل سياسات التطبيع للتخزين مقابل البحث:
- استخدم ملف تعريف محافظ للتخزين القياسي (احتفظ بـ ZWNJ، وتجنب التحولات الدلالية).
- استخدم ملف تعريف متساهل للبحث (تجاهل ZWNJ، ووحد متغيرات الهمزة، وطبع الأرقام).
- يجب أن تكون جميع التعيينات قابلة للتكوين عبر جدول تعيين مركزي في قاعدة البيانات أو تجزئة Ruby في التطبيق.
ملفات تعريف التطبيع
محافظ (للتخزين)
- تحويل أدنى
- طبق NFKC
- طبع الكاف/الياء العربية إلى ما يعادلها بالفارسية
- إزالة علامات التشكيل
- احتفظ بـ ZWNJ
- التخزين كـ
original_text+normalized_conservative
متساهل (للبحث)
- مطابقة قوية
- طبق جميع قواعد المحافظ
- إزالة/تجاهل ZWNJ
- طبع متغيرات الهمزة إلى الأحرف الأساسية
- تحويل جميع الأرقام إلى ASCII
- اختياريًا توحيد التاء المربوطة → الهاء
- يستخدم لمعالجة استعلامات البحث مسبقًا
جدول تعيين شامل
| المصدر | الهدف | يونيكود | ملاحظات |
|---|---|---|---|
ك |
ک |
U+0643 → U+06A9 | الكاف العربية → الكاف الفارسية |
ي |
ی |
U+064A → U+06CC | الياء العربية → الياء الفارسية |
ى |
ی |
U+0649 → U+06CC | متغير الياء النهائي |
أ، إ، ٱ |
ا |
مختلف → U+0627 | أشكال الهمزة → الألف |
ؤ |
و |
U+0624 → U+0648 | الهمزة على الواو |
ئ |
ی |
U+0626 → U+06CC | الهمزة على الياء |
ء |
— | U+0621 | إزالة أو الاحتفاظ (قابل للتكوين) |
ة |
ه |
U+0629 → U+0647 | التاء المربوطة → الهاء (اختياري) |
ۀ |
هٔ |
U+06C0 ↔ U+0647+U+0654 | تطبيع الشكل المركب |
ڭ |
گ |
U+06AD → U+06AF | المتغيرات الإقليمية |
|
— | U+200C | ZWNJ: الاحتفاظ في المحافظ، الإزالة في المتساهل |
٤، ۴ |
4 |
U+0664، U+06F4 → ASCII | تطبيع الأرقام |
| علامات التشكيل | — | U+064B–U+0652 | إزالة جميع الحركات |
| ZWJ | — | U+200D | إزالة الروابط غير المرئية |
| مسافات متعددة | مسافة واحدة | — | تطبيع المسافات |
مقتطف تعيين سريع (لـ SQL أو Ruby)
ك → ک
ي → ی
ى → ی
أ → ا
إ → ا
ؤ → و
ئ → ی
ة → ه
ۀ → هٔ
ٱ → ا
٤, ۴ → 4
ZWNJ (U+200C) → (تمت إزالته في المتساهل)
الحركات (U+064B..U+0652) → تمت إزالتها
ZWJ (U+200D) → تمت إزالته
التنفيذ في PostgreSQL
- إنشاء جدول
text_normalization_map - استخدام
regexp_replaceأو سلاسلTRANSLATEلتحسين الأداء - اختياريًا، التنفيذ في PL/Python أو PL/v8 لدعم Unicode
- تطبيع كل من المحتوى المخزن والاستعلامات الواردة باستخدام نفس المنطق
استراتيجية الفهرسة
- تخزين
normalized_conservativeللفهرسة القياسية - تطبيع الاستعلامات باستخدام
normalize_persian_arabic(query, 'permissive') - إذا كنت تستخدم البحث المتساهل، فيجب أن يتطابق الفهرس مع نفس الملف الشخصي
- اختياريًا، تخزين كلا الإصدارين للمقارنة المتبادلة
مثال تجزئة Ruby (لـ Discourse)
NORMALIZATION_MAP = {
"ك" => "ک",
"ي" => "ی",
"ى" => "ی",
"أ" => "ا",
"إ" => "ا",
"ٱ" => "ا",
"ؤ" => "و",
"ئ" => "ی",
"ة" => "ه",
"ۀ" => "هٔ",
"۴" => "4",
"٤" => "4",
"\u200C" => "", # ZWNJ
"\u200D" => "", # ZWJ
}
ملاحظات الأداء والعملية
- طبق NFKC في طبقة التطبيق (على سبيل المثال، Ruby
unicode_normalize(:nfkc)) - استخدم فهارس منفصلة لملفات التعريف المحافظة مقابل المتساهلة
- تجنب التعيينات الإجبارية للأحرف الحساسة دلاليًا (مثل الهمزة، التاء المربوطة) ما لم يتم تكوينها صراحةً
- قم بإجراء اختبارات A/B على بيانات المنتدى الفعلية لقياس معدل الإصابات والإيجابيات الخاطئة
- وثق كل تعيين مع الأساس المنطقي والأمثلة
- حدد اختبارات الوحدة في كل من Ruby و SQL لكل تعيين
التوصية النهائية
- استخدم Unicode NFKC كأساس
- قم بتوسيعه باستخدام طبقة تعيين مخصصة
- حافظ على ملفات تعريف مزدوجة للتخزين والبحث
- نفذ التطبيع في كل من طبقات التطبيق وقاعدة البيانات
- وثق واختبر كل تعيين
- أنشئ فهارس مناسبة (
GIN + to_tsvector) على الأعمدة المطبعة