Lucene.Net2--建立搜索

转地址:http://blog.csdn.net/xuezhongsong/article/details/4388241

当我们查询Lucene的一个索引时,Lucene会返回一个有序的Hits对象集合(collection)。Lucene使用默认的评分方式对该集合内的对象按照其得分高低进行排序。对于一个给定的查询,Lucene为每个文档计算一个评分(即一个表示相关性的数值)。Hits本身不是实际的匹配文档集,只是指向这些匹配文档的引用(reference)。在许多显示搜索结果的应用程序中,用户访问的只是最开始的一部分匹配文档,因此没有必要对搜索结果中的所有文档都进行检索;而只需检索那些有必要呈现给用户的文档就可以了。对于大型索引来说,系统甚至可能没有足够的物理内存来存储所匹配到的全部文档。在接下来的部分中,我们把IndexSearcher、Query、Hits对象和一些基本的对象的搜索结合起来,下面是一个示例:

/*
 * 建立一个Form,命名为SerchFormDemo,添加四个控件:
 * Button按钮命名button1,添加单击事件
 * TextBox文本框,命名textBox1
 * ListView控件,命名listView1
 * StatusBar,命名statusBar1
 * 分词类使用中文分词类库ChineseAnalyzer,也可以使用Lucene自带的类库
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Lucene.Net.Analysis.Cn;
using Lucene.Net.Store;

namespace WebCheck
{
    public partial class SerchFormDemo : Form
    {
        public SerchFormDemo()
        {
            InitializeComponent();
        }
        #region 字段
        const string INDEX_STORE_PATH = "index";
        //IndexSearcher搜索操作的入口。所有的搜索操作都是通过IndexSercher实例使用一个重载的search方法来实现
        IndexSearcher searcher = null;
        DateTime start = DateTime.Now;
        #endregion
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                listView1.Items.Clear();
                //FSDirectory.GetDirectory()打开了一个由系统属性定义的索引路径的索引,
                //最后一个参数是false,它表示我们希望打开的是一个已经存在的索引而非构造一个新的索引。
                //IndexSearcher是通过使用以Directory实例为参数的构造函数创建的
                FSDirectory directory = FSDirectory.GetDirectory(INDEX_STORE_PATH, false);
                searcher = new IndexSearcher(directory);

                Hits h = Search(textBox1.Text);
                printResult(h);
                statusBar1.Text = "准备";
                searcher.Close();
            }
            catch (Exception ex)
            {
                output("错误信息", ex.Message);
            }
        }
        void printResult(Hits h)
        {
            if (h.Length() == 0)
            {
                output("结果", "对不起,没有搜索到你要的结果。");
            }
            else
            {
                for (int i = 0; i < h.Length(); i++)
                {
                    try
                    {
                        Document doc = h.Doc(i);
                        output((i + 1).ToString(), doc.Get("filename"));
                    }
                    catch (Exception ex)
                    {
                        output("错误信息", ex.Message);
                    }
                }
            }
            output("------", "-------------------");
        }
        /// <summary>
        /// 分割字符串,存入数组里
        /// </summary>
        /// <param name="str">字符串名称</param>
        /// <returns></returns>
        public string[] GetArrayStr(string str)
        {
            str = str.Replace(",", ",");
            str = str.Replace(" ", ",");
            str = str.Replace(";", ",");
            str = str.Replace(";", ",");
            str = str.Replace(";", ",");
            str = str.Replace("、", ",");
            str = str.Replace("/", ",");
            string[] Mstr = str.Split(',');
            return Mstr;
        }
        Hits Search(string key)
        {
            output("", "正在检索关键字" + key);
            try
            {
                /*
                 * TermQuery对索引中的某个项进行搜索是最基本的搜索方式。项是最小的索引片断,每个项里包含了一个域名和一个文本值
                 * 
                 * RangeQuery索引中的各个项会以字典编录的顺序排列好,
                 * 这是因为开发人员在开发Lucene时就考虑到了在一定范围内对特定项进行搜索的效率问题。
                 * Lucene中的RangeQuery类就为我们在指定起始项(starting term)和终止项(ending term)的范围内进行搜索提供了便利。
                 * 起始项与终止项这两个边界上的项,既可以包括在搜索范围之内,也可以不包括在内。
                 * 以下代码示范了如何在包含起始和终止项的范围内进行搜索:
                 *  Term begin, end;
                    begin = new Term("date", "19891010");
                    end = new Term("date", "20090729");
                    RangeQuery query = new RangeQuery(begin, end, false);
                 * 
                 * 组合查询:BooleanQuery通过使用BooleanQuery可以将本章讨论的各种查询类型组合成复杂的查询方式。
                 * BooleanQuery本身是一个布尔子句的容器。这个子句可以是表示逻辑“或”、逻辑“与”或者逻辑“非”的一个子查询。
                 * 这些属性允许进行逻辑的AND、OR或NOT组合
                 * 可以用BooleanQuery的add方法将一个查询子句添加到某个BooleanQuery对象中

                 */

                BooleanQuery query = new BooleanQuery();
                //QueryParser将用户输入的(并且可读的)查询表达式处理为一个具体的Query对象
                QueryParser parser = new QueryParser("contents", new ChineseAnalyzer());
                foreach (string strkey in GetArrayStr(key))
                {
                    if (strkey != "" || strkey.Trim() != "")
                    {
                        //Query子类为每一种特定类型的查询进行了逻辑上的封装。
                        //Query实例被传递到IndexSeracher的serach方法中
                        Query qy = parser.Parse(strkey);
                        query.Add(qy, BooleanClause.Occur.MUST);
                    }
                }
                start = DateTime.Now;
                //Hits提供对搜索结果的访问。Hits对象由IndexSearcher的search方法返回
                //Hits search(Query query)直接进行搜索,无需过滤
                //Hits search(Query query,Filter filter)在过滤标准的约束下,把搜索限制在有效的文档子集之内
                //void search(Query query,HitCollector results)只有当我们需要使用搜索返回的所有文档时才调用这个方法。
                //一般来说,只有搜索结果中前几个文档才是我们所需的,所以使用此方法会降低程序的性能
                /*通过调用search(Query)方法,
                 * 可以对返回的Hits对象进行处理。我们是通过Hits来访问搜索结果。
                 * 你可以使用某一个能够返回Hits对象的search方法。
                 * 这个Hits对象为我们提供了一个访问搜索结果的有效方法。
                 * 搜索结果是通过相关性程度进行排序的,也就是说由文档和查询条件的匹配度进行排序
                 * Hits实例中仅包含有4个方法:
                 * Length()Hits对象集合中所包含的文档的数量
                 * Doc(n)排名第n的Document实例
                 * Id(n) 排名第n的Document ID
                 * Score(n)排名第n的标准分值(以得分最高的文档的评分为标准,将分值标准化),这个分值大于0,小于等于1
                 * 
                 * Hits类对少数文档进行了缓存并且保留了最近使用过的文档。
                 * Lucene会自动检索出前100个文档并将其置入缓存。
                 * Lucene返回的Hits集合只向用户提供少数评分较高的文档,因为可能这些文档才是用户所需要的。
                 */
                Hits hits = searcher.Search(query);
                TimeSpan s = DateTime.Now - start;
                output("", "搜索结果" + hits.Length() + "个结果,共用时:" + s.Milliseconds + "毫秒"); ;
                return hits;
            }
            catch (Exception ex)
            {
                output("错误信息", ex.Message);
                return null;
            }
        }
        void output(string i, string s)
        {
            listView1.Items.Add(new ListViewItem(new string[] { s, i.ToString(), DateTime.Now.ToString() }));
            this.statusBar1.Text = s;
        }
    }
}
posted @ 2012-10-16 23:42  倚楼听雨  阅读(159)  评论(0编辑  收藏  举报