معرفی کتابخانه ی مشهور و قدرتمند Lucene.net -- قسمت دوم
  در این مقاله به تشریح نحوه ی انجام جستجوی پیشرفته با استفاده از کتابخانه مشهور Lucene.net خواهیم پرداخت.
   C#
   ۱۶۶۵۹
   این مقاله حاوی فایل ضمیمه نمی باشد
   مرتضی صحراگرد
   ۱۳۸۹/۳/۲۲
ارسال لینک صفحه برای دوستان ارسال لینک صفحه برای دوستان  اضافه کردن به علاقه مندیها اضافه کردن به علاقه مندیها   نسخه قابل چاپ نسخه قابل چاپ

 

مقدمه:

این مقاله، دومین قسمت از سلسله مقالات معرفی کتابخانه Lucene.net می باشد. برای فراگیری صحیح این مقاله حتما باید قسمت قبلی را فراگرفته باشید.

 در قسمت قبلی ما ایندکس های مربوط به اطلاعات خود را ایجاد نموده و متدی را برای جستجوی ساده نوشتیم. متد مربوطه را جهت یادآوری بیشتر اینجا تکرار می کنم. (شرح عملکرد این متد را مقاله قبلی مطالعه نمایید)

 
private List<News> SearchIndexes(string InputText)
{
    List<News> results = new List<News>();
 
    Lucene.Net.Search.BooleanQuery.SetMaxClauseCount(int.MaxValue);
 
    IndexReader reader = IndexReader.Open(GetNewsIndexDirectory());
    IndexSearcher searcher = new IndexSearcher(reader);
    Hits hits = null;
 
    //are there any wild cards in use?
    if (InputText.Contains("*"))
    {
        WildcardQuery query = new WildcardQuery(new Term("Body", InputText));
 
        hits = searcher.Search(query);
 
    }
    //is this a multi term query?
    else if (InputText.Contains(" "))
    {
        MultiPhraseQuery query = new MultiPhraseQuery();
        foreach (string s in InputText.Split(' '))
        {
            query.Add(new Term("Body", s));
        }
        hits = searcher.Search(query);
    }
    //single term query
    else
    {
        PhraseQuery query = new PhraseQuery();
        query.Add(new Term("Body", InputText));
        hits = searcher.Search(query);
    }
 
    for (int i = 0; i < hits.Length(); i++)
    {
 
        Document doc = hits.Doc(i);
        News news = new News();
        news.NewsID = Convert.ToInt32(doc.GetField("NewsID").StringValue());
        news.Title = doc.GetField("Title").StringValue();
        results.Add(news);
    }
    return results;
}

در متد بالا ما از کلاس های WildcardQuery و MultiPhraseQuery و PhraseQuery جهت انجام انواع جستجو استفاده نموده ایم. مشکل این متد این است که فقط می تواند در یک فیلد جستجو کند. مثلا در متد فوق ما فقط می توانیم در فیلد Body جستجو کنیم و اگر نیاز داشته باشیم که هم زمان در فیلد Title و ٌWriterID نیز جستجو نماییم، این عمل امکان پذیر نمی باشد. فرض کنید نیاز داشته باشیم خبرهایی را که کلمه "است" را در قسمت Body داشته باشند و ضمنا WriterID آن نیز برابر 1 باشند را داشته باشیم، این عمل امکان پذیر نیست.

برای انجام اینگونه از جستجو ها از کلاسی به نام QueryParser استفاده می نماییم. در حقیقت کلاس های قبلی نیز در درون خود از این کلاس جهت ساخت کوئری استفاده می کنند و ما را مستقیما درگیر ساخت کوئری جستجو نمی کردند. ولی برای انجام عملیات جستجوی پیشترفته باید کوئری مورد نظر خود را با گرامر مخصوص کتابخانه Lucene.net بسازیم و سپس کوئری را اجرا نماییم.

آغاز:

معرفی کلاس QueryParser را با مثال انجام می دهیم. اکنون قصد داریم متدی بنوسیم که کلماتی را که قرار است در قسمت Body و Title جستجو شوند را به همراه یک WriterID مشخص گرفته و جستجو نموده و نتایج را برگرداند. (به طور مثال قرار است خبرهایی را بازیابی کنیم که کلمه "اقتصاد" در عنوان آن ذکر شده باشد و کلمه "سیاست" در متن خبر گنجانده شده باشد و ضمنا مربوط به نویسنده ای با شناسه WriterID=1 باشد)

یادآوری:

فقط در فیلدهایی می توانیم عملیات جستجو را انجام دهیم که این قابلیت را هنگام ساخت ایندکس ها برای آن ها فراهم نموده باشیم. (جهت اطلاعات بیشتر به مقاله قبلی مراجعه نمایید)
 

private List<News> AdvancedSearch(string titleTerm, string bodyTerm, int writerID)
{
    //Keeps search's results
    List<News> results = new List<News>();
 
    Lucene.Net.Search.BooleanQuery.SetMaxClauseCount(int.MaxValue);
 
    IndexReader reader = IndexReader.Open(GetNewsIndexDirectory());
    IndexSearcher searcher = new IndexSearcher(reader);
    Hits hits = null;
 
    //////////// Begin the new section
    QueryParser oParser = new QueryParser("Body", new StandardAnalyzer());
    string sTitle = "", sWriterID = "", finalQuery = "";
 
    sTitle = " AND (Title:" + titleTerm + ")";
 
    sWriterID = " AND (WriterID:" + writerID + ")";
 
    finalQuery = "(" + bodyTerm + sTitle + sWriterID + ")";
    hits = searcher.Search(oParser.Parse(finalQuery));
    //////////// End of the new section
 
 
    for (int i = 0; i < hits.Length(); i++)
    {
 
        Document doc = hits.Doc(i);
        News news = new News();
        news.NewsID = Convert.ToInt32(doc.GetField("NewsID").StringValue());
        news.Title = doc.GetField("Title").StringValue();
        results.Add(news);
    }
    return results;
}

در قطعه کد بالا قسمت ما از کلاس QueryParser جهت ساخت کوئری استفاده نموده ایم و اکنون به تشریح عملکرد این قسمت می پردازیم.

هنگام تعریف کلاس QueryParser دو پارامتر به سازنده این کلاس ارسال نموده ایم. پارامتر اول نام یک فیلد (زیرا ارسال حداقل یک فیلد اجباری می باشد که در اینجا Body را ارسال نموده ایم) می باشد و پارامتر دوم تحلیلگر مورد نظر خود می باشد. (شرح آن در مقاله قبلی آمده است)

QueryParser oParser = new QueryParser("Body", new StandardAnalyzer());

اکنون نوبت به ساخت کوئری می رسد. کوئری با یک پرانتز آغاز شده و با یک پرانتز نیز پایان می یابد.

اولین مقدار پس از اولین پرانتز، مقدار فیلدی است که هنگام ایجاد کلاس QueryParser آن را به عنوان پارامتر اول ارسال نموده ایم. در اینجا ما مقدار bodyTerm که قرار است در قسمت Body مربوط به خبر جستجو شود را ارسال نموده ایم.

سپس سایر فیلد ها و مقادیر آن ها را با الگوری زیر می سازیم.

AND (FieldName:"FieldValue")
 

به نحوه ی ساخت کوئزی دقت فرمایید.

string sTitle = "", sWriterID = "", finalQuery = "";
 
sTitle = " AND (Title:" + titleTerm + ")";
 
sWriterID = " AND (WriterID:" + writerID + ")";
 
finalQuery = "(" + bodyTerm + sTitle + sWriterID + ")";

در انتها کوئری نهایی را ساخته و متغیر finalQuery ذخیره نموده ایم. در قسمت زیر یک نمونه از کوئری های ساخته شده را ملاحظه می نمایید.

(سیاست AND (Title:اقتصاد) AND (WriterID:1))

تذکر:

  • در صورتی که نیاز به عملگر OR دارید می توانید به جای AND از OR استفاده نمایید.
  • این کوئری به حروف کوچک و بزرگ حساس می باشد پس به نحوه ساخت کوئری دقت فرمایید.

کوئری مربوطه را اجرا نموده و سایر مراحل نیز مانند مثال مقاله قبل می باشد.

hits = searcher.Search(oParser.Parse(finalQuery));

ادامه مقالات: