使用Lucene.Net实现全文检索

Lucene.Net概述

  Lucene.Net是一个C#开发的开源全文索引库,其源码包括"核心"与"外围"两部分。外围部分实现辅助功能,而核心部分包括:

  • Lucene.Net.Index 提供索引管理,词组排序。
  • Lucene.Net.Search 提供查询相关功能。
  • Lucene.Net.Store 支持数据存储管理,主要包括I/O操作。
  • Lucene.Net.Util 公共类。
  • Lucene.Net.Documents 负责描述索引存储时的文件结构管理。
  • Lucene.Net.QueryParsers 提供查询语法。
  • Lucene.Net.Analysis 负责分析文本。

  全文检索流程如下:

  一个简单的全文检索实例:

  创建索引:

  关键代码形如:

复制代码
        static void createIndex(string title, string content)
        {
            LN.Analysis.Analyzer analyzer = new LN.Analysis.Standard.StandardAnalyzer();
            LN.Index.IndexWriter iw = new LN.Index.IndexWriter("Index", analyzer, false);
            LN.Documents.Document document = new LN.Documents.Document();
            document.Add(new LN.Documents.Field("title", title, LN.Documents.Field.Store.YES, LN.Documents.Field.Index.TOKENIZED));
            document.Add(new LN.Documents.Field("content", content, LN.Documents.Field.Store.YES, LN.Documents.Field.Index.TOKENIZED));
            iw.AddDocument(document);
            iw.Optimize();
            iw.Close();
        }        

  查询:

  关键代码形如:

复制代码
     static List<Item> search(string keyWord)
        {
            List<Item> results = new List<Item>();
            LN.Analysis.Analyzer analyzer = new LN.Analysis.Standard.StandardAnalyzer();
            LN.Search.IndexSearcher searcher = new LN.Search.IndexSearcher("Index");
            LN.QueryParsers.MultiFieldQueryParser parser = new LN.QueryParsers.MultiFieldQueryParser(new string[] { "title", "content" }, analyzer);
            LN.Search.Query query = parser.Parse(keyWord);
            LN.Search.Hits hits = searcher.Search(query);
            for (int i = 0; i < hits.Length(); i++)
            {
                LN.Documents.Document doc = hits.Doc(i);
                results.Add(new Item() { Title = doc.Get("title"), Content = doc.Get("content") });
            }
            searcher.Close();
            return results;
        }

二 分词

(一)内置分词器

  分词(切词)是实现全文检索的基础,之所以我们能够让机器理解我们的自然语言,是因为有了分词的帮助。分词工作由Analyzer类完成,它负责把文本切成Token序列,Token就是索引中的单词。Lucene.Net在两个地方用到分词:创建文档索引和分析搜索关键字。其过程示意如下:

  由此可知,在创建索引和搜索时,必须使用同样的分词器,保证其切出相同的Token才能检索到结果。(Lucene.Net把查询关键字中的单词叫做"Term",Term和Token的文本是一样的,只是某些属性不一样。)

  Lucene.Net实现了一些分词器,其对英文支持较好,但是对中文支持欠佳。

  针对内置分词器测试结果如下:

  关键代码形如:

复制代码
        private static List<string> cutWords(string words, Analyzer analyzer)
        {
            List<string> results = new List<string>();
            TokenStream ts = analyzer.ReusableTokenStream("", new StringReader(words));
            Token token;
            while ((token = ts.Next()) != null)
            {
                results.Add(token.TermText());
            }
            ts.Close();
            return results;
        }    

  可见,除了StandardAnalyzer外,其它分词器对中文基本无法处理,需要用户自行解决。

(二)分词过程

  分词实际是由以下类型完成:

  查看WhitespaceAnalyzer的部分源码如下:

复制代码
   public sealed class WhitespaceAnalyzer:Analyzer
    {
        public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
        {
            return new WhitespaceTokenizer(reader);
        }
     ...
    }

  由此可见,WhitespaceAnalyzer的工作都是交给WhitespaceTokenizer来完成的,并且没有使用筛选器,这也与之前测试的结果相符。我们可以利用TokenStream的派生类型来实现自定义分词器。 例如修改上述代码来得到一个新的分词器,功能类似WhitespaceAnalyzer,不同的是将大写字母变为小写,其代码形如:

复制代码
    public sealed class NewWhitespaceAnalyzer:Analyzer
    {
        public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
        {
            TokenStream ts = new WhitespaceTokenizer(reader);
            return new LowerCaseFilter(ts);
        }
     ...
    }

(三)中文分词

  显然,用户可以自定义分词器,来实现中文分词。但是,大多数用户不熟悉中文分词算法,同时也没有时间和精力来实现自定义分词,毕竟分词并不是我们系统的核心功能。因此,笔者引用了另一个中文分词组件------盘古分词。测试结果如下:

  盘古分词使用步骤如下:

Setp 1:添加相关程序集引用

这里需要添加2个程序集,PanGu.dll(盘古分词的核心组件)和PanGu.Lucene.Analyzer.dll(盘古分词的Lucene组件)。

Step 2:添加中文分词库

Step 3:添加并设置配置文件

Step 4:在Lucene.Net使用盘古分词

  PanGu.Lucene.Analyzer.dll中定义了Analyzer的派生类型Lucene.Net.Analysis.PanGu.PanGuAnalyzer,与Tokenizer的派生类Lucene.Net.Analysis.PanGu.PanGuTokenizer,语法与Lucene.Net内置分词器相同。

Step 5:维护分词库

  使用DictManage.exe管理和维护词库:

三 索引

(一)索引的存储结构

  为了方便索引大量文档,Lucene.Net中的一个索引包括多个子索引,叫做Segment(段)。每个Segment包括多个可搜索的文档,叫做Document;每个Document包括多个Field;每个Field又包括多个Term。综上所述,Lucene.Net的索引文件的逻辑结构如下:

  索引文件的物理表示如下:

  Lucene.Net把一个文档写入索引时,首先生成这个文档的到排索引,然后再把文档的倒排索引合并到段的倒排索引中。

(二)常用类型

  • DirectoryLucene.Net的Directory类型实现索引的存储。常用类型继承树如下:
相关推荐
随心(cracker)16 小时前
BeaverX Admin:一套真正能跑起来的开源管理后台
vue·.net·管理后台
忧郁的紫菜20 小时前
异步编程 In .NET
.net
Denuin多啦咧梦1 天前
玩转 .NET 依赖注入:Microsoft.Extensions.DependencyInjection 深度指南
c#·.net·依赖注入
长孙豪翔2 天前
在.net中读写config文件的各种方法
java·数据库·.net
Elastic 中国社区官方博客2 天前
跟踪资金流向:使用 ES|QL 和跨集群搜索追踪洗钱网络
大数据·人工智能·安全·elasticsearch·搜索引擎·金融·全文检索
GV191rLvq2 天前
查看w3wp进程占用的内存及.NET内存泄露,死锁分析
.net
界面开发小八哥2 天前
界面控件DevExpress .NET Reports v26.1新版亮点 - 持续增强可访问性
.net·界面控件·devexpress·ui开发·报表控件
wei1986213 天前
.net添加web引用和添加服务引用有什么区别?
java·前端·.net
pW3g3lLuu3 天前
.NET 高级开发 | http 接口对接和客户端开发技巧
网络协议·http·.net