ورود

View Full Version : جستجو در یک بانک بزرگ و مشکل زمان



raha_hakhamanesh
شنبه 05 اسفند 1391, 13:15 عصر
با سلام خدمت اساتید بزرگوار
من در یک پروژه متن کاوی با مشکل جستجو و رتبه بندی در دیتابیس مواجه هستم لطفا در این خصوص نظرات و راهنمایی های خودتان را دریغ نفرمایید.
یک بانک اطاعاتی با دو میلیون رکورد داریم که هر رکورد محتوای یک ایمیل است. برای دسته بندی باید به دنبال کلمات کلیدی مورد نظر در این ایمیل ها بگردیم و بر اساس تعداد تکرارشان، رکوردها را وزن دهی یا اولویت گذاری کنیم، نهایتا رکوردهای با بیشترین تکرار در اولویت نمایش قرار گیرند.
کاری که من انجام داده ام

ابتدا همه رکوردهایی را که شامل کلمه کلیدی هستند از دیتابیس فراخوانی کردم:


StrCmd = " SELECT [EmID],[Sub],[Body] FROM Tbl_Source WHERE ( ";

StrCmd += " Sub LIKE '%" + word1 + "%' OR Body LIKE '%" + word1 + "%' ";

StrCmd += " Sub LIKE '%" + word2 + "%' OR Body LIKE '%" + word2 + "%') ";


تا اینجای کار بد نیست، سپس رکوردهایی که با دستور فوق انتخاب شدن را یکی یکی به تابع Search ارسال می کنم تا تعداد حضور کلمات مورد نظرمان را بشمارد:



dr = Cmd.ExecuteReader();
while (dr.Read())
{
EID = dr["EID"].ToString();
Subject = dr["Sub"].ToString();
Body = dr["Body"].ToString();

ret_Rate = Search(EID, Subject, Body);
UpdateRecord(EID, ret_Rate);
}
dr.Close();


تابع جستجو هم به شرح زیر است:

[1] Rate = 0;
[2] for (int i = 0; i < word.Length; i++)
[3] if (words[i].Length > 0)
{
//============================== find how many occurrence in subject
[4] Subject = Subject.ToLower();
[5] Rate += new Regex(words[i]).Matches(Subject).Count * 2;
//============================== find how many occurrence in Body
[6] Body = Body.ToLower();
[7] Rate += new Regex(words[i]).Matches(Body).Count;
}


که در کد فوق، خط 7 تعداد کلمات (words[i]) موجود در فیلد Body رو بر می گردونه، در خط 4 هم بطور مشابه؛ با این تفاوت که در یک عدد 2 ضرب میشه تا وزن بیشتری از خودش نشون بده و دلیلش هم اینه که کلمه مربوطه در عنوان ایمیل است که برای ما مهمتر می باشد.

اما اشکال کار»
بعد از تحلیل برنامه، متوجه شدم برای یک تحلیل بر روی 500 هزار رکورد برنامه ما، یک ثانیه زمان می خواد تا اطلاعات رو از دیتابیس Fetch کنه (کد اول)، ولی 147 ثانیه طول میکشه تا رکوردها رو یکی یکی به تابع Search بفرسته و تعداد تکرار کلمات (رتبه اون رکورد) را محاسبه کند!
متاسفانه این زمان قابل قبول نیست و نمی تونیم با اون کار کنیم
چیزی که بنظرم می رسه این است که قطعه کد دوم که هر رکورد را یکی یکی از طریق DataReader برای ارزیابی به تابع Search می فرسته بهینه نیست!؟ (البته مطمئن نیستم) و شاید بتوان در دستورات SQL این را جایگزین کنیم!

منتظر نظرات و راهنمایی های شما عزیزان هستم
(هر نکته ای ممکن است گره ای از این مشکل را باز کند، بسم الله)

ad.davachi
شنبه 05 اسفند 1391, 13:33 عصر
جستجو رو توی sql انجام بدید سرعت بالا نمیره؟

raha_hakhamanesh
شنبه 05 اسفند 1391, 16:56 عصر
جستجو رو توی sql انجام بدید سرعت بالا نمیره؟

با سلام و تشکر
بله ظاهرا باید دنبال همین ایده بگردم ولی چطورش رو نمی دونم لطفا یک خطی بدید که کار پیش بره
مثلا اگر نمونه ای در دسترس است لطف بفرمایید
یا حتی چند خطی از کار را خودتان مطابق آنچه در ذهنتان است بنویسید مهم نیست عین کد باشه فقط برای اینکه بدونم چطور این ایده رو شروع کنم
در حقیقت چطور میشه بجای رکورد به رکورد پردازش کردن، همین تابع توسط SQL پردازش بشه؟

لطفا راهنمایی
متشکرم

baktash.n81@gmail.com
یک شنبه 06 اسفند 1391, 07:40 صبح
سلام دوست عزیز

یکی از روش های شمردن کلامات در متن : اندازه کل رشته رو با تابع len ابدست می آریم بعد با تابع replace این کلمه رو با '' جای خالی جایگزین می کنیم و دوباره طولشو بدست می آریم حال اگه طول رشته قبل از حذف رو از طول رشته بعد از حذف کم کنیم و تقسیم بر تعداد کاراکتر های کلمه مورد جستجو کنیم تعداد تکرار بدست می آد ...

declare @s nvarchar(2000)
set @s = N'test shomarandey test testtest test2 test'

declare @tedad int

set @tedad = (len(@s)-(len(REPLACE(@s,'test',''))))/len('test')

print @tedad

اینو امتحان کن شاید بهتر باشه ...

raha_hakhamanesh
یک شنبه 06 اسفند 1391, 13:28 عصر
سلام دوست عزیز

یکی از روش های شمردن کلامات در متن : اندازه کل رشته رو با تابع len ابدست می آریم بعد با تابع replace این کلمه رو با '' جای خالی جایگزین می کنیم و دوباره طولشو بدست می آریم حال اگه طول رشته قبل از حذف رو از طول رشته بعد از حذف کم کنیم و تقسیم بر تعداد کاراکتر های کلمه مورد جستجو کنیم تعداد تکرار بدست می آد ...

declare @s nvarchar(2000)
set @s = N'test shomarandey test testtest test2 test'

declare @tedad int

set @tedad = (len(@s)-(len(REPLACE(@s,'test',''))))/len('test')

print @tedad

اینو امتحان کن شاید بهتر باشه ...


بله دست شما درد نکنه، ایده درسته و نتیجه هم میده ولی اشکال من اینه که تبحر شما رو در دیتابیس ندارم

از نظر من یک تشکر برای این راهنمایی شما کم بود مجدد سپاسگزارم