هذه المقالة متعلقة بقواعد بيانات Microsoft
SQL Server وتناقش النقاط التالية:
-
دالة
SOUNDEX
-
دالة
DIFFERENCE
-
كتابة
استعلام يظهر النتائج المتشابهة مع كلمة ما في اللفظ
-
هل
تدعم دالة SOUNDEX
اللغة العربية؟ وما هي الحلول المتوفرة؟
-
هل
تعتبر دالة SOUNDEX
مثالية للتعرف على الكلمات المتشابهة؟
المتطلبات السابقة لقراءة هذه المقالة:
-
إلمام
بأساسيات قواعد بيانات Microsoft SQL Server
افرض
أن ماجد طلب من موظف استقبال الفندق معرفة رقم الغرفة التي يقطن فيها صديقه محمد
الأمين، قام الموظف بالبحث عن محمد بواسطة الاسم الأول فأدخل الاسم التالي Muhamed ، فظهرت للموظف نتائج البحث ومن ضمنها سجل
يحمل قيم الاسم الأول والاسم الأخير بالتتالي Mohammed Alameen ورقم غرفته 52 ، أخبر الموظف ماجد بأن صديقه
محمد يقطن في الغرفة رقم 52 ، توجه ماجد إلى غرفة محمد وكان اللقاء بعد غياب طويل،
تعانقا وبدأ مسلسل الهراء الذي دائما ما يحدث عندما يلتقي الأصدقاء ببعضهم – هلا
والله، كيف الحال؟ بشرنا عنك؟ علوومك؟ وينك يا رجال؟.... – وأثناء حديثهما قال ماجد:
لقد شاهدت موظف الاستقبال يكتب اسمك بالطريقة التالية muhamed ، هل اسمك بالفعل مدون في إثباتك الشخصي
بهذه الطريقة ؟ اندهش محمد وقال لا، بل هو مدون بالطريقة التالية Mohammed ، وقد قام الموظف الذي استقبلني بإدخال
بياناتي كما هي مدونة في إثباتي الشخصي! تعجب ماجد ومحمد وتسائلوا: كيف استطاع
نظام الفندق التعرف على العملاء الذين أسمائهم الأولى تشبه الاسم الأول الذي
استخدمه موظف الاستقبال للبحث عن محمد وهو Muhamed؟ ، كيف نجيب على تساؤلهم؟
بتلك
القصة السخيفة أبدأ تمهيدي لهذه المقالة، وأجيب على التساؤل الأخير بأن الإجابة –
مع إمكانية تنوع الإجابات - تكمن في دالة SOUNDEX ، تستخدم هذه الدالة ضمن الاستعلامات
المنفذة على قواعد بيانات Microsoft
SQL Server
لمعرفة النتائج المتشابهة في اللفظ، تستقبل هذه الدالة معطى واحد فقط وهو تعبير
نصي وتقوم بإرجاع قيمة تتكون من أربعة رموز: الرمز الأول هو الحرف الأول الذي تبدأ
به الكلمة التي تم تمريرها إلى الدالة، والرموز الثلاثة المتبقية هي أرقام تقيس
طريقة اللفظ. يفترض عند تمرير كلمتين مشابهتين في اللفظ أن تقوم الدالة SOUNDEX بإرجاع نفس القيمة لكلتا الكلمتين، على سبيل
المثال عند تمرير القيمة Muhamed إلى الدالة فإن الناتج هو القيمة M530 ، أيضا عن تمرير الكلمة Mohammed فإن الناتج هو القيمة M530 .
قم بتنفيذ جملة الاستعلام التالية لتشاهد النتيجة بنفسك لمجموعة من الكلمات
التي تشابه كلمة Muhamed في اللفظ:
SELECT soundex('Mohammed')AS Mohammed_column,soundex('Muhamed') AS Muhamed, soundex('Muhamad')AS Muhamad, soundex('Muhammed') AS Muhammed, soundex('Mouhamed')AS Mouhamed;
النتيجة
هي:
توجد
أيضا دالة أخرى لها علاقة بالدالة السابقة وهي دالة DIFFERENCE ، تستقبل هذه الدالة مدخلان وهما التعبيران
النصيان المطلوب معرفة الفرق بينهما في طريقة اللفظ، وتعيد قيمة عددية صحيحة
محصورة بين 0 و 4 وتمثل مقدار الفرق بين الكلمتين في طريقة اللفظ، بحيث لو كانت
القيمة العائدة هي 4 فهذا يعني أن الكلمتين متشابتهان جداً، وإذا كانت 3 فهذا يعني
وجود تشابه ولكنه أقل من الحالة السابقة وهلم جراً مع القيم 2 و 1 ، وإذا كانت
القيمة العائدة صفر فهذا يعني عدم وجود تشابه في اللفظ على الإطلاق. استخدام دالة DIFFERENCE سيكون مفيد لصياغة استعلام يبحث في جدول عن
نتائج تتشابه في اللفظ مع كلمة معينة، وقبل صياغة هذا الاستعلام بإمكانك تجربة
الاستعلامات التالية لتتعرف على دالة DIFFERENCE وترى المخرجات التي ستظهر عند مقارنة كلمة Muhamed مع كلمات أخرى:
SELECT DIFFERENCE('Muhamed','Mohammed'); -- Output: 4
SELECT DIFFERENCE('Muhamed', 'Mohame'); -- Output: 3
SELECT DIFFERENCE('Muhamed', 'Microsoft'); -- Output: 1
الآن
سنقوم باستخدام الدالة DIFFERENCE
للبحث في جدول النزلاء Guests عن النزلاء الذين تشابه أسمائهم الأولى
الاسم Muhamed على
البيانات التالية:
الاستعلام
كالآتي:
SELECT * FROM
Guests WHERE DIFFERENCE(FirstName, 'Muhamed')= 4;
والنتيجة
هي:
وهي
الكلمات المشابهة جداً لكلمة Muhamed. إذا أردت إظهار مزيد من النتائج على حساب
دقة البحث فيمكنك تحديد الفرق المطلوب ليكون 4 أو 3 وليس 4 فقط ، سيكون الاستعلام
كما يلي:
SELECT * FROM
Guests WHERE DIFFERENCE(FirstName, 'Muhamed')>= 3;
رأينا
أن دالة Soundex وأختها الدالة Difference تعملان بشكل رائع مع اللغة الإنجليزية،
السؤال الآن هل تدعم دالة soundex اللغة العربية؟ للأسف لا تدعم دالة soundex اللغة العربية، ولكن بإمكاننا توفير حلول بديلة.
أثناء تسكعي في الانترنت وجدت المقالة التالية التي تتحدث عن خوارزمية Soundex http://www.codeproject.com/Articles/26880/Arabic-Soundex ، وقد قام كاتب المقالة بعد فهم طريقة عمل الخوارزمية بتعديل
سلوكها لكي تعمل مع اللغة العربية، ما سأقوم به الآن هو توفير الكود البرمجي الذي
كتبه المؤلف بلغة C# ليكون دالة يمكن استخدامها ضمن استعلامات
قواعد بيانات SQL
Server.
مع ملاحظة أني قمت بتعديل بسيط على الكود الموجود بالمقالة بحيث أصبح شكل الدالة
كالآتي:
public static string SoundexAr(string word)
{
int length = 4;
// Value to return
string value = "";
try
{
switch (word[0])
{
case 'ا':
case 'أ':
case 'إ':
case 'آ':
{
word =
word.Substring(1, word.Length - 1);
}
break;
}
// Size of the word to process
int size = word.Length;
// Make sure the word is at least two
characters in length
if (size > 1)
{
// Convert the word to
character array for faster processing
char[] chars =
word.ToCharArray();
// Buffer to build up with character codes
StringBuilder buffer = new StringBuilder();
buffer.Length = 0;
// The current and
previous character codes
int prevCode = 0;
int currCode = 0;
// Ignore first
character and replace it with fixed value
buffer.Append('x');
// Loop through all
the characters and convert them to the proper character code
for (int i = 1; i < size;
i++)
{
switch (chars[i])
{
case 'ا':
case 'أ':
case 'إ':
case 'آ':
case 'ح':
case 'خ':
case 'ه':
case 'ع':
case 'غ':
case 'ش':
case 'و':
case 'ي':
currCode = 0;
break;
case 'ف':
case 'ب':
currCode = 1;
break;
case 'ج':
case 'ز':
case 'س':
case 'ص':
case 'ظ':
case 'ق':
case 'ك':
currCode = 2;
break;
case 'ت':
case 'ث':
case 'د':
case 'ذ':
case 'ض':
case 'ط':
currCode = 3;
break;
case 'ل':
currCode = 4;
break;
case 'م':
case 'ن':
currCode = 5;
break;
case 'ر':
currCode = 6;
break;
}
// Check to see if the
current code is the same as the last one
if (currCode !=
prevCode)
{
// Check to see if the
current code is 0 (a vowel); do not process vowels
if (currCode != 0)
buffer.Append(currCode);
}
// Set the new
previous character code
prevCode = currCode;
// If the buffer size
meets the length limit, then exit the loop
if (buffer.Length ==
length)
break;
}
// Pad the buffer, if
required
size = buffer.Length;
if (size < length)
buffer.Append('0', (length - size));
// Set the value to
return
value = buffer.ToString();
}
// Return the value
return value;
}
catch
{
return "0000";
}
}
كل
ما تبقى عليك الآن هو تحويل دالة C# السابقة إلى دالة SQL Server ، لمعرفة طريقة عمل ذلك يرجى قراءة مقالتي
"تحويل الدوال المكتوبة بلغة C# إلى دوال SQL Server"، وبعد القيام بالخطوة السابقة قم
بإضافة المرجع الذي أنشأته إلى قاعدة البيانات، ومن ثم قم بإنشاء دالة SQL Server تستخدم المرجع السابق، يمكنك عمل ذلك عبر
تنفيذ الاستعلام التالي على قاعدة البيانات مع تغيير ما يلزم في الكود – مثل مسار
المرجع - :
-- Install
Assembly
CREATE ASSEMBLY MyHotelAssembly FROM
'C:\MyHotelDatabaseProject1.dll'
GO
-- Create
SoundexAr Function
CREATE FUNCTION [dbo].[SoundexAr](@word nvarchar(max))
RETURNS nvarchar(4)
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME
MyHotelAssembly.UserDefinedFunctions.SoundexAr;
GO
الآن
يمكنك الاستمتاع بمنافع دالة Soundex للغة العربية، قم بتجربة الاستعلام التالي
لترى النتيجة:
SELECT dbo.SoundexAr(N'احمد'), dbo.SoundexAr(N'أحمد'), dbo.SoundexAr(N'أحميد'), dbo.SoundexAr(N'احمدد');
بذلك
أكون قد انتهيت من الحديث عن دالة soundex وبقي أن أشير إلى أن دالة soundex ليست دالة مثالية ولا تعمل في جميع الحالات
بنسبة 100%، هي دالة جيدة وتؤدي الغرض ولكن لها بعض الحدود التي لا تجعلها دالة
مثالية للتعرف على الكلمات المتشابهة في اللفظ، من تلك الحدود على سبيل المثال
أنها سوف تفشل في التعرف على الكلمات المتشابهة في اللفظ ولكنها مختلفة في تهجئة
الكتابة، على سبيل المثال كلمة photo وكلمة foto كلمتان متشابهتان في اللفظ ومختلفتان في
تهجئة الكتابة، لذلك لن تستطيع دالة soundex إخراج نفس القيمة لكلتا الكلمتين، فنتيجة تمرير الكلمة photo للدالة soundex هي P300 ، بينما نتيجة foto هي F300 ، أيضا من حدود هذه الدالة أنها لا تستطيع التعرف على الكلمات
التي تحوي رموز أو مسافة، على سبيل المثال، اسمي الأخير في جواز سفري مدون كما يلي
AL-MAWSAMI – وحاله هو حال معظم أسماء
العائلات العربية التي تبدأ بـ(أل) التعريف – ، فلو قام موظف استقبال الفندق
بتسجيله بهذه الطريقة، ثم جاء شخص غريب يريد اغتيالي في الفندق، فسأل موظف
الاستقبال عن شخص اسمه الأخير هو ALMAWSAMI
ولم يخبر الموظف عن إضافة علامة الشرطة بعد AL ، وقام موظف الاستقبال بالاستعلام عن ذاك الشخص،
فإنه لن يجد شيئاً في نتائج البحث، وبذلك أكون قد نجوت من الموت المحقق بسبب سلوك
دالة soundex ، والسبب أن النتيجة التي تعيدها الدالة مع
الحالة الأولى AL-MAWSAMI هي A400 ، ولكنها مع الحالة الثانية ALMAWSAMI ستكون A452 ، وتفسير ذلك أن دالة soundex قامت بقراءة القيمة الممررة لها إلى أن وجدت
رمز أو مسافة فتوقفت عندها وقامت بإرجاع القيمة التي تخص النص الذي يسبق الرمز أو
المسافة، وبذلك فإن القيمة العائدة لكلمة AL-MAWSAMI هي نفسها القيمة العائدة لكلمة AL !
SELECT soundex('almawsami'); -- Output: A452
SELECT soundex('al mawsami'); -- Output: A400
SELECT soundex('al-mawsami'); -- Output: A400
SELECT soundex('al'); -- Output: A400
ليست هناك تعليقات:
إرسال تعليق