You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

20 KiB

دستورالعمل جامع نرمال‌سازی جستجو برای متون عربی و اسلامی

(Comprehensive Arabic & Persian Search Normalization Specification)


۱. مقدمه و بیان مسئله (Executive Summary & Problem Statement)

در پایگاه‌های داده و سامانه‌های متنی اسلامی و حدیثی، جستجوی متنی با چالش‌های بنیادین زبان‌شناختی و فنی مواجه است:

  1. گوناگونی رسم‌الخط و کدگذاری یونیکد (Unicode Homoglyphs): نویسه‌هایی مانند الف همزه‌دار (أ، إ)، الف ممدوده (آ)، الف وصل (ٱ) و الف ساده (ا) دارای کدهای یونیکد کاملاً متفاوتی هستند.
  2. اعراب و اعجام (Harakat / Tashkeel): متون احادیث و اسناد دینی معمولاً با حرکت‌گذاری کامل (مانند إِنَّمَا الأَعْمَالُ) در پایگاه داده ذخیره شده‌اند، در حالی که کاربران جستجوهای خود را بدون اعراب (انما الاعمال یا انما) تایپ می‌کنند. در مقایسه‌های متنی پیش‌فرض دیتابیس (LIKE یا ILIKE و icontains)، وجود اعراب در میان حروف کلمه باعث می‌شود کلمه کاربر تطبیق داده نشود و نتیجه «هیچ رکوردی یافت نشد» برگردد.
  3. تداخل کاراکترهای فارسی و عربی: در کیبوردهای کاربران (موبایل و دسکتاپ)، حروفی چون «ی» و «ي»، «ک» و «ك»، «ه» و «ة» مدام جابه‌جا می‌شوند.
  4. علائم قرآنی و وقوف: نمادهایی مانند «الف خنجری» (ٰ مانند رَحْمٰنِ)، علائم وقف و نمادهای تعظیم اگر نرمال نشوند، جستجو را مسدود می‌کنند.

هدف: هر متنی که کاربر با هر شکلی از کیبورد (با اعراب، بدون اعراب، با همزه یا بدون همزه، فارسی یا عربی) جستجو کرد، سیستم باید دقیقاً مفهوم آن را درک کرده و تمامی رکوردهای منطبق را بدون وابستگی به شکل ظاهری نگارش پیدا کند.


۲. دسته‌بندی جامع کاراکترها و حالات نرمال‌سازی (Normalization Taxonomy)

۲.۱. خانواده الف‌ها و همزه‌ها (Alef & Hamza Variants)

الف در رسم‌الخط عربی دارای حالت‌های متعددی است که در جستجو باید همگی یکپارچه شوند:

نویسه اصلی نام یونیکد کد یونیکد هدف نرمال‌سازی مثال جستجو مثال در دیتابیس
أ Arabic Letter Alef With Hamza Above U+0623 ا (U+0627) أنما انما / إِنَّمَا
إ Arabic Letter Alef With Hamza Below U+0625 ا (U+0627) إسناد اسناد
آ Arabic Letter Alef With Madda Above U+0622 ا (U+0627) آثار اثار
ٱ Arabic Letter Alef Wasla U+0671 ا (U+0627) ٱمرؤ امرؤ
ا Arabic Letter Alef (Bare) U+0627 ا (U+0627) اعمال أعمال
ٴ Arabic Letter High Hamza U+0674 حذف یا ا — —

حالات دیگر همزه‌ها (Other Hamza Forms):

  • همزه روی واو (ؤ - U+0624): در جستجوی آسان‌گیر (Lenient)، همزه روی واو به و (U+0648) نرمال می‌شود تا کاربر با سرچ «مومن» بتواند «مؤمن» را پیدا کند یا بالعکس («مسؤول» / «مسئول»).
  • همزه روی یاء / نبره (ئ - U+0626): به ی / ي تبدیل می‌شود تا کلماتی چون «قائل»، «قایل»، «هیئة»، «هيئة» هم‌ارز شوند.
  • همزه تنها روی خط (ء - U+0621): حذف یا تبدیل به فاصله در صورت نیاز.

۲.۲. خانواده یاء و الف مقصوره (Yeh & Alef Maksura)

یکی از پرتکرارترین خطاها در جستجوی عربی و فارسی مربوط به حرف «ی» است:

نویسه اصلی نام کد یونیکد رفتار نرمال‌سازی مثال
ي یاء عربی دو نقطه U+064A تبدیل به نویسه واحد مبنا (مثلاً ی یا ي) علي / علی
ى الف مقصوره عربی (بی‌نقطه) U+0649 تبدیل به ی یا ا بر اساس سیاست پروژه موسی / موسي / موسى
ی یای فارسی بدون نقطه U+06CC تبدیل به نویسه واحد مبنا حدیث / حديث
ئ یاء با همزه U+0626 تبدیل به نویسه واحد مبنا بئر / بیر

نکته تخصصی در متون دینی: الف مقصوره (ى در انتهای کلماتی چون «حتى»، «إلى»، «موسى») در کیبورد کاربران گاهی با ی، گاهی با ي و حتی گاهی به اشتباه با ا («حتا») نوشته می‌شود. نرمال‌سازی [ي ى ی ئ] به یک نویسه پایدار، پوشش جستجو را به ۱۰۰٪ می‌رساند.


۲.۳. کاف عربی و فارسی (Kaf Normalization)

  • ك (کاف عربی با نشان همزه/کاف کوچک: U+0643)
  • ک (کاف فارسی سرکش‌دار: U+06A9)
  • قاعده: تبدیل هر دو به یک فرم استاندارد (مثلاً ك برای متون عربی یا ک).

۲.۴. تاء مربوطه و هاء (Teh Marbuta & Heh)

  • ة (تاء مربوطه: U+0629)
  • ه (هاء: U+0647)
  • ۀ (هاء با همزه: U+06C0)
  • تحلیل رفتاری: کاربران در تایپ سریع اسامی یا اصطلاحات اغلب تاء مربوطه را با هاء جابه‌جا می‌زنند:
    • «معاویه» ↔ «معاوية»
    • «فاطمه» ↔ «فاطمة»
    • «صحابه» ↔ «صحابة»
    • «رواة» ↔ «رواه»
  • قاعده سرچ نرمال: برای جستجوی متنی، ة به ه تبدیل می‌شود تا تفاوت نگارشی کاربر باعث حذف رکورد نشود.

۲.۵. حرکات، اعراب و تنوین‌ها (Tashkeel / Harakat / Diacritics) - حیاتی‌ترین بخش

تمام حرکات زیر باید از متن ورودی و از نسخه ایندکس‌شده جستجو کاملاً حذف شوند:

نام حرکت علامت کد یونیکد اثر در جستجوی خام دیتابیس
فتحه (Fatha) َ U+064E مانع تطابق متن ساده می‌شود
ضمه (Damma) ُ U+064F مانع تطابق متن ساده می‌شود
کسره (Kasra) ِ U+0650 مانع تطابق متن ساده می‌شود
تنوین نصب (Fathatan) ً U+064B مانع تطابق
تنوین رفع (Dammatan) ٌ U+064C مانع تطابق
تنوین جر (Kasratan) ٍ U+064D مانع تطابق
سکون (Sukun) ْ U+0652 مانع تطابق
تشدید (Shadda) ّ U+0651 مانع تطابق کلمات دارای تشدید
الف خنجری (Dagger Alef) ٰ U+0670 بسیار خطرناک: در «رَحْمٰنِ»، «إِلٰهَ»، «هٰذَا»، «إِسْمٰعِيل» اگر حذف نشود، سرچ «رحمن» هرگز «رحمٰن» را پیدا نمی‌کند!
مده (Maddah) ٓ U+0653 مانع تطابق
همزه فوقانی اعرابی ٔ U+0654 مانع تطابق
همزه تحتانی اعرابی ٕ U+0655 مانع تطابق

۲.۶. کشیدگی، تطویل و نشانه‌های نامرئی (Tatweel & Invisible Characters)

  • تطویل / کشیده (ـ - U+0640): برای تنظیم طول خطوط در متون کهن یا زیبایی متنی به کار می‌رود (مثل صـــــراط یا رســــول). این کاراکتر باید به کلی حذف شود.
  • نیم‌فاصله (Zero-Width Non-Joiner - U+200C): در متون فارسی و اسامی ترکیبی وجود دارد؛ باید به فاصله عادی یا حذف کامل تبدیل شود.
  • اتصال‌دهنده مجازی (ZWJ - U+200D): باید حذف شود.
  • نشانگرهای جهت یونیکد (LRM U+200E و RLM U+200F): باید کاملاً حذف شوند.

۲.۷. نشانه‌ها و نمادهای وقوف قرآنی و مذهبی (Quranic Symbols & Waqf Marks)

در متون روایی و قرآنی نمادهای ویژه‌ای در یونیکد ذخیره می‌شوند که باید در لایه سرچ پالایش گردند:

  • علائم وقف قرآنی: ۖ (U+06D6), ۗ (U+06D7), ۘ (U+06D8), ۙ (U+06D9), ۚ (U+06DA), ۛ (U+06DB), ۜ (U+06DC), ۝ (U+06DD), ۞ (U+06DE), ۟ (U+06DF), ۠ (U+06E0), ۡ (U+06E1), ۢ (U+06E2), ۣ (U+06E3), ۤ (U+06E4).
  • نمادهای لیگچر مذهبی: ﷺ (U+FDFA), ﷻ (U+FDFB), ﷽ (U+FDFD), ؑ (U+0611).
  • پرانتزها و براکت‌های قرآنی و نقل‌قول: ﴿، ﴾، «، »، [، ]، (، ).

۲.۸. ارقام و اعداد (Digits)

  • ارقام عربی-مشرقی: [٠, ١, ٢, ٣, ٤, ٥, ٦, ٧, ٨, ٩]
  • ارقام فارسی: [۰, ۱, ۲, ۳, ۴, ۵, ۶, ۷, ۸, ۹]
  • ارقام استاندارد لاتین: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • قاعده: تبدیل تمام ارقام به ارقام استاندارد (0-9) تا سرچ شماره حدیث یا جلد و صفحه فارغ از نوع کیبورد عدد را پیدا کند.

۳. ماتریس مقایسه‌ای سناریوهای سرچ (Search Scenario Matrix)

ورودی کاربر در سرچ متن در دیتابیس وضعیت جستجوی فعلی (خام) وضعیت پس از نرمال‌سازی
انما أنما الأعمال بالنيات ❌ No result (تفاوت ا و أ) ✅ منطبق و پیدا می‌شود
انما إِنَّمَا الأَعْمَالُ بِالنِّيَّاتِ ❌ No result (وجود کسره، تشدید، فتحه) ✅ منطبق و پیدا می‌شود
أبو هريرة ابو هريره ❌ No result (تفاوت أ/ا و ة/ه) ✅ منطبق و پیدا می‌شود
صحیح بخاری صَحِيحُ الْبُخَارِيِّ ❌ No result (تفاوت اعراب، ی/ي) ✅ منطبق و پیدا می‌شود
رحمن الرَّحْمٰنِ الرَّحِيمِ ❌ No result (وجود الف خنجری ٰ) ✅ منطبق و پیدا می‌شود
مومن إِنَّمَا الْمُؤْمِنُونَ إِخْوَةٌ ❌ No result (تفاوت و با ؤ) ✅ منطبق و پیدا می‌شود
صراط صــــراط الذين ❌ No result (وجود کشیده ـ) ✅ منطبق و پیدا می‌شود
حدیث ۱۱۰ حديث 110 یا حديث ١١٠ ❌ No result (تفاوت ارقام) ✅ منطبق و پیدا می‌شود

۴. گزینه‌ها و معماری پیاده‌سازی فنی در Django و PostgreSQL

برای اعمال این نرمال‌سازی در سیستم، سه رویکرد معماری وجود دارد:

🟢 گزینه اول: الگوی ستون جستجوی نرمال‌شده (Normalized Shadow Column / Search Column) — [رویکرد پیشنهادی و استاندارد]

در این الگو، متن اصلی برای نمایش دست‌نخورده باقی می‌ماند (تا اعراب و زیبایی اصیل آن در UI حفظ شود)، اما یک ستون متنی نرمال‌شده در کنار آن ایجاد و ایندکس‌گذاری می‌شود:

  1. در مدل‌ها (Hadis، HadisCategory، Transmitter و ...):
    • افزودن فیلد normalized_text = models.TextField(blank=True, db_index=True) یا استفاده از django.contrib.postgres.search.SearchVector.
    • در متد save() مدل، متن اصلی از تابع نرمال‌ساز عبور کرده و فیلد نرمال‌شده به صورت خودکار پر می‌شود.
    • ایجاد یک اسکریپت ساده migration برای پر کردن یک‌باره مقادیر رکوردهای موجود.
  2. در لایه Queryset / View:
    • عبارت سرچ کاربر (search_query) توسط همان تابع پایتون نرمال‌سازی می‌شود: normalized_q = normalize_text(search_query).
    • جستجو روی ستون normalized_text__icontains=normalized_q انجام می‌شود.
  3. مزایا:
    • فوق‌العاده سریع (High Performance): دیتابیس مستقیماً روی ستون ایندکس‌شده کوئری می‌زند بدون اینکه در هر ریکوئست تابع یا رجکس سنگین روی میلیون‌ها کاراکتر اجرا شود.
    • سادگی و پایداری: سازگاری کامل با معماری فعلی Django بدون نیاز به نصب اکستنشن‌های پیچیده C در دیتابیس سرور.
    • دقت ۱۰۰٪: تضمین می‌کند که منطق سمت پایتون در هر دو طرف ذخیره و جستجو دقیقاً یکی است.

🟡 گزینه دوم: تابع پایگاه داده در سطح PostgreSQL (Database-Level Stored Function & Functional Index)

  1. ایجاد یک تابع PL/pgSQL در PostgreSQL (مثلاً fn_normalize_arabic(text)).
  2. ساخت ایندکس تابعی:
    CREATE INDEX idx_hadis_normalized_text ON hadis_hadis (fn_normalize_arabic(text));
    
  3. در جنگو با استفاده از Func یا Raw SQL:
    queryset.filter(Q(normalized_text_func__icontains=normalize_text(query)))
    
  4. مزایا: عدم نیاز به ذخیره دیتای مضاعف در ستون جداگانه.
  5. معایب: وابستگی شدید به دیتابیس، سختی مایگریشن در محیط‌های توسعه و تست SQLite/Docker، و پیچیدگی نگهداری لاجیک در SQL.

🔴 گزینه سوم: استفاده از Regex در زمان کوئری (Query-time Regex)

  1. تبدیل هر حرف از کلمه سرچ به یک گروه رجکس؛ مثلاً تبدیل انما به: [اأإآٱ][ًٌٍَُِّْٰ]*ن[ًٌٍَُِّْٰ]*م[ًٌٍَُِّْٰ]*[اأإآٱ]
  2. ارسال به دیتابیس با text__iregex=pattern.
  3. معایب:
    • بسیار کند: دیتابیس نمی‌تواند از هیچ ایندکسی استفاده کند (Full Table Scan با Regex Engine).
    • با افزایش تعداد احادیث و اسناد، پاسخ سرور از چند میلی‌ثانیه به چند ثانیه افزایش می‌یابد و بار سرور را به شدت بالا می‌برد.

۵. کد مرجع پایتون برای تابع نرمال‌سازی (Python Reference Implementation)

این تابع کامل‌ترین و بهینه‌ترین پیاده‌سازی منطبق با استاندارد Unicode Consortium برای متون عربی و فارسی است:

import re
import unicodedata

# 1. حرکات، اعراب، تنوین‌ها، تشدید، سکون و الف خنجری
# شامل بازه U+064B تا U+065F و الف مقصوره بالایی U+0670
ARABIC_DIACRITICS_REGEX = re.compile(r'[\u064B-\u065F\u0670\u06D6-\u06ED]')

# 2. کاراکتر کشیدگی / تطویل
TATWEEL_REGEX = re.compile(r'\u0640')

# 3. جدول نگاشت الف‌ها و کاراکترهای چندشکلی
ARABIC_NORMALIZATION_MAP = str.maketrans({
    # انواع الف به الف ساده
    'أ': 'ا',
    'إ': 'ا',
    'آ': 'ا',
    'ٱ': 'ا',
    
    # انواع یاء و الف مقصوره به یای استاندارد
    'ي': 'ی',
    'ى': 'ی',
    'ئ': 'ی',
    
    # کاف عربی به کاف یکسان
    'ك': 'ک',
    
    # تاء مربوطه و هاء
    'ة': 'ه',
    'ۀ': 'ه',
    
    # واو همزه‌دار
    'ؤ': 'و',
    
    # ارقام عربی مشرقی و فارسی به ارقام استاندارد
    '٠': '0', '١': '1', '٢': '2', '٣': '3', '٤': '4',
    '٥': '5', '٦': '6', '٧': '7', '٨': '8', '٩': '9',
    '۰': '0', '۱': '1', '۲': '2', '۳': '3', '۴': '4',
    '۵': '5', '۶': '6', '۷': '7', '۸': '8', '۹': '9',
})

# 4. کاراکترهای کنترلی و نامرئی (Zero-width spaces, LRM, RLM)
ZERO_WIDTH_REGEX = re.compile(r'[\u200B-\u200F\u202A-\u202E\uFEFF]')

def normalize_for_search(text: str) -> str:
    """
    متن ورودی را بر اساس قواعد استاندارد جستجوی متون عربی و اسلامی نرمال‌سازی می‌کند:
    1. حذف کاراکترهای کنترلی پنهان و نیم‌فاصله‌های نامتعارف
    2. حذف کامل تمام اعراب‌ها، حرکات، تشدید، تنوین‌ها و الف خنجری (Tashkeel)
    3. حذف علامت کشیدگی (تطویل / کشیده)
    4. یکسان‌سازی الف‌ها (أ، إ، آ، ٱ -> ا)
    5. یکسان‌سازی یاء و الف مقصوره (ي، ى، ئ -> ی)
    6. یکسان‌سازی کاف (ك -> ک)
    7. یکسان‌سازی تاء مربوطه (ة -> ه)
    8. یکسان‌سازی واو همزه‌دار (ؤ -> و)
    9. تبدیل ارقام عربی و فارسی به ارقام استاندارد
    10. یکپارچه‌سازی فاصله‌های خالی چندگانه
    """
    if not text or not isinstance(text, str):
        return ""

    # ۱. نرمال‌سازی فرم یونیکد (NFKC)
    text = unicodedata.normalize('NFKC', text)

    # ۲. حذف کاراکترهای نامرئی
    text = ZERO_WIDTH_REGEX.sub('', text)

    # ۳. حذف حرکات و اعراب
    text = ARABIC_DIACRITICS_REGEX.sub('', text)

    # ۴. حذف تطویل
    text = TATWEEL_REGEX.sub('', text)

    # ۵. نگاشت الف‌ها و کاراکترهای هم‌ارز
    text = text.translate(ARABIC_NORMALIZATION_MAP)

    # ۶. حذف فاصله‌های اضافی مکرر
    text = re.sub(r'\s+', ' ', text).strip()

    return text

  1. فاز ۱ — بررسی و تأیید نهایی:
    • تأیید قوانین نرمال‌سازی فوق توسط کارفرما و تیم فنی (به‌ویژه در خصوص تبدیل ة به ه و ؤ به و).
  2. فاز ۲ — اضافه کردن ماژول Utility:
    • افزودن فایل backend/utils/text_normalizer.py شامل تابع normalize_for_search.
  3. فاز ۳ — پیاده‌سازی پایگاه داده:
    • اضافه کردن فیلدهای search_text یا normalized_text در مدل‌های کلیدی (Hadis، HadisCategory، Transmitter، HadisCorrection، ReferenceBook).
    • تنظیم پر شدن خودکار در save().
    • اجرای یک Management Command برای نرمال‌سازی داده‌های قبلی.
  4. فاز ۴ — به‌روزرسانی Queryset های جستجو:
    • اصلاح متدهای apply_search_filter در Viewها تا ورودی کاربر را پیش از جستجو نرمال کند.
  5. فاز ۵ — تست و اعتبارسنجی:
    • نوشتن تست‌های خودکار (Unit Tests) برای کلمات چالش‌برانگیز مثل «أنما»، «إِنَّمَا»، «الرَّحْمٰنِ»، «أبو هريرة»، «مسؤول» و اطمینان از نتیجه مثبت در تمامی حالات.