使用Lucene.NET实现数据检索功能

引言


在软件系统中查询数据是再平常不过的事情了,那当数据量非常大,数据存储的媒介不是数据库,或者检索方式要求更为灵活的时候,我们该如何实现数据的检索呢?为数据建立索引吧,利用索引技术可以更灵活更快捷的实现检索功能。


Lucene.NET和盘古分词


Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。开发人员可以基于Lucene.net实现全文检索的功能。

分词技术是索引管理的核心技术,索引的关键词就是通过分词进行切割的。国外的分词技术多数对中文的支持度不高,而盘古分词是一个比较好的中文分词技术。


案例概要


我以一个文件检索系统为例,主要功能就是为硬盘中大量文件建立一个统一的检索平台,并且不使用数据库。


思路


该系统主要分为两部分,第一部分是索引的管理,为文件建立或更新索引;第二部分是文件的检索,根据关键词与索引库进行匹配并获得相关信息。这两部分功能可以整合在一个项目中,也可以分开在不同的项目中。


分词


需要注意的是不论是索引的管理还是文件的检索都离不开一样东西,那就是分词,正是分词的力量将多个关键字可以按照分词规则精确的与庞大的索引库进行匹配。 

因为Lucene是国外的技术,所以对中文分词支持度并不高,这里我推荐使用盘古分词。


索引的管理


索引的管理主要是建立索引、更新索引和删除索引。需要注意的是用做识别的ID字段不能使用带有特殊符号的字符串,尽量使用词或者编号等,不然索引可能无法删除,也无法正常更新。

//指定索引库文件存放文件位置
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(this.IndexDataDir), new NativeFSLockFactory());
//判断索引文件目录是否存在
bool isExist = IndexReader.IndexExists(directory);
if (isExist)
{
    if (IndexWriter.IsLocked(directory))
    {
        IndexWriter.Unlock(directory);
    }
}
//盘古分词器
PanGuAnalyzer analyzer = new PanGuAnalyzer();
//索引写入类
IndexWriter writer = new IndexWriter(directory, analyzer, !isExist, IndexWriter.MaxFieldLength.UNLIMITED);
//循环队列执行操作
while (IndexDataQueue.Count > 0)
{
    Document document = new Document();
//这是我为索引数据自定义的模型类,主要内容是文件的路径、名称、内容和索引管理的操作类型(新增、更新、删除)
    BaseDataMode mode = IndexDataQueue.Dequeue();
    switch (mode.Type)
    {
        case OperationType.Insert:
            {
                foreach (KeyValuePair<string, string> kv in mode.Content)
                {
                    //这里kv.Key是设置索引内字段的名称,kv.Value是这个字段内存储的内容。
                    document.Add(new Field(kv.Key, kv.Value, Field.Store.YES, Field.Index.ANALYZED,Field.TermVector.WITH_POSITIONS_OFFSETS));
                }
                writer.AddDocument(document);
            }; break;
        case OperationType.Update:
        {
            //设置删除条件
            MultiFieldQueryParser parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, new string[] { "id" }, analyzer);
            Query query = parser.Parse(mode.Content["id"]);
            writer.DeleteDocuments(query);
            foreach (KeyValuePair<string, string> kv in mode.Content)
            {
                document.Add(new Field(kv.Key, kv.Value, Field.Store.YES, Field.Index.ANALYZED,Field.TermVector.WITH_POSITIONS_OFFSETS));
            }
            writer.AddDocument(document);
        }; break;
        case OperationType.Delete:
        {
            MultiFieldQueryParser parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, new string[] { "id" }, analyzer);
            Query query = parser.Parse(mode.Content["id"]);
            writer.DeleteDocuments(query);
        }; break;
        default: { }; break;
    }
}
//提交操作
writer.Commit();
//优化
writer.Optimize();
//关闭连接
writer.Close();
directory.Close();

文件检索


文件检索主要的过程是,先对查询的内容进行分词,将其分解为多个关键词,然后使用Lucene内置的搜索功能对已建好的索引库进行查询,最后将搜索结果显示出来。

//指定索引库文件存放文件位置
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(this.IndexDir), new NativeFSLockFactory());
IndexReader reader = IndexReader.Open(directory, true);
IndexSearcher searcher = new IndexSearcher(reader);
//设置关键词在条件中为OR关系
BooleanQuery queryOr = new BooleanQuery();
foreach (string word in SplitContent.SplitByPanGu(keyword))
{
    foreach (KeyValuePair<string, string> kv in Mode.Content)
    {
        TermQuery query = new TermQuery(new Term(kv.Key, word));
        //这里设置条件为Or关系
        queryOr.Add(query, BooleanClause.Occur.SHOULD);
    }
}
//获取搜索结果       
//1000为搜索文件的下标限制,设置这个可以控制检索的范围,也可以用于分页显示
TopDocs tds = searcher.Search(queryOr, null, 1000);
ScoreDoc[] docs = tds.scoreDocs;
for (int i = 0; i < docs.Length; i++)
{
    int docId = docs[i].doc;
    Document doc = searcher.Doc(docId);
string content = doc.Get("索引内字段的名称");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值