Net Core使用Lucene.Net和盘古分词器 实现全文检索

Stella981
• 阅读 377

Lucene.net

Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,是一个高性能、可伸缩的文本搜索引擎库。它的功能就是负责将文本数据按照某种分词算法进行切词,分词后的结果存储在索引库中,从索引库检索数据的速度非常快。Lucene.net需要有索引库,并且只能进行站内搜索。(来自百度百科)

效果图

Net Core使用Lucene.Net和盘古分词器 实现全文检索

盘古分词

如何使用

将PanGu.dIl与PanGu.Lucenet.Analyzer. dl并加入到项目中

Net Core使用Lucene.Net和盘古分词器 实现全文检索  

将Dict文件,拷贝到项目Bin文件夹里面

Net Core使用Lucene.Net和盘古分词器 实现全文检索

Net Core使用Lucene.Net和盘古分词器 实现全文检索

字典文件夹下载:https://pan.baidu.com/s/1HNiLp6bCcodN8vqlck066g 提取码: xydc

测试

Net Core使用Lucene.Net和盘古分词器 实现全文检索

 可以看到,盘古分词相对Lucene.net自带的一元分词来说,是比较好的,因为一元分词不适合进行中文检索。

一元分词是按字拆分的,比如上面一句话,使用一元分词拆分的结果是:"有","一","种","方","言","叫","做","不","老","盖","儿"。如果查找“方言”这个词,是找不到查询结果的。不符合我们的检索习惯,所以基本不使用。

拓展

上面的"不老盖儿"(河南方言),这里想组成一个词,那么需要创建"不老盖儿"词组并添加到字典里面。

使用DictManage工具:https://pan.baidu.com/s/1Yla2DBM74kSbno8cg5kvGw 提取码:tphe

解压,运行 DictManage.exe 

Net Core使用Lucene.Net和盘古分词器 实现全文检索

然后打开 Dict 文件下的 Dict.dct 文件,并添加"不老盖儿"词组

Net Core使用Lucene.Net和盘古分词器 实现全文检索

 然后查找就可以看到"不老盖儿"词组

Net Core使用Lucene.Net和盘古分词器 实现全文检索

 然后保存覆盖原有的 Dict.dct 文件

刷新页面或者重新打开页面看下效果

Net Core使用Lucene.Net和盘古分词器 实现全文检索

Demo文件说明

Net Core使用Lucene.Net和盘古分词器 实现全文检索

简单实现 

创建索引核心代码

Net Core使用Lucene.Net和盘古分词器 实现全文检索 Net Core使用Lucene.Net和盘古分词器 实现全文检索

/// <summary>
        /// 创建索引
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("createIndex")]
        public string CreateIndex()
        {
            //索引保存位置
            var indexPath = Directory.GetCurrentDirectory() + "/Index";
            if (!Directory.Exists(indexPath)) Directory.CreateDirectory(indexPath);
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
            if (IndexWriter.IsLocked(directory))
            {
                //  如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
                //  Lucene.Net在写索引库之前会自动加锁,在close的时候会自动解锁
                IndexWriter.Unlock(directory);
            }
            //Lucene的index模块主要负责索引的创建
            //  创建向索引库写操作对象  IndexWriter(索引目录,指定使用盘古分词进行切词,最大写入长度限制)
            //  补充:使用IndexWriter打开directory时会自动对索引库文件上锁
            //IndexWriter构造函数中第一个参数指定索引文件存储位置;
            //第二个参数指定分词Analyzer,Analyzer有多个子类,
            //然而其分词效果并不好,这里使用的是第三方开源分词工具盘古分词;
            //第三个参数表示是否重新创建索引,true表示重新创建(删除之前的索引文件),
            //最后一个参数指定Field的最大数目。
            IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), true,
                IndexWriter.MaxFieldLength.UNLIMITED);
            var txtPath = Directory.GetCurrentDirectory() + "/Upload/Articles";
            for (int i = 1; i <= 1000; i++)
            {
                //  一条Document相当于一条记录
                Document document = new Document();
                var title = "天骄战纪_" + i + ".txt";
                var content = System.IO.File.ReadAllText(txtPath + "/" + title, Encoding.Default);
                //  每个Document可以有自己的属性(字段),所有字段名都是自定义的,值都是string类型
                //  Field.Store.YES不仅要对文章进行分词记录,也要保存原文,就不用去数据库里查一次了
                document.Add(new Field("Title", "天骄战纪_" + i, Field.Store.YES, Field.Index.NOT_ANALYZED));
                //  需要进行全文检索的字段加 Field.Index. ANALYZED
                //  Field.Index.ANALYZED:指定文章内容按照分词后结果保存,否则无法实现后续的模糊查询 
                //  WITH_POSITIONS_OFFSETS:指示不仅保存分割后的词,还保存词之间的距离
                document.Add(new Field("Content", content, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
                writer.AddDocument(document);
            }
            writer.Close(); // Close后自动对索引库文件解锁
            directory.Close(); //  不要忘了Close,否则索引结果搜不到
            return "索引创建完毕";
        }

View Code

搜索代码

Net Core使用Lucene.Net和盘古分词器 实现全文检索 Net Core使用Lucene.Net和盘古分词器 实现全文检索

/// <summary>
        /// 搜索
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("search")]
        public object Search(string keyWord, int pageIndex, int pageSize)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            string indexPath = Directory.GetCurrentDirectory() + "/Index";
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            //创建IndexSearcher准备进行搜索。
            IndexSearcher searcher = new IndexSearcher(reader);
            // 查询条件
            keyWord = GetKeyWordsSplitBySpace(keyWord, new PanGuTokenizer());
            //创建QueryParser查询解析器。用来对查询语句进行语法分析。
            //QueryParser调用parser进行语法分析,形成查询语法树,放到Query中。
            QueryParser msgQueryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "Content", new PanGuAnalyzer(true));
            Query msgQuery = msgQueryParser.Parse(keyWord);
            //TopScoreDocCollector:盛放查询结果的容器
            //numHits 获取条数
            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
            //IndexSearcher调用search对查询语法树Query进行搜索,得到结果TopScoreDocCollector。
            // 使用query这个查询条件进行搜索,搜索结果放入collector
            searcher.Search(msgQuery, null, collector);
            // 从查询结果中取出第n条到第m条的数据
            ScoreDoc[] docs = collector.TopDocs(0, 1000).scoreDocs;
            stopwatch.Stop();
            // 遍历查询结果
            List<ReturnModel> resultList = new List<ReturnModel>();
            var pm = new Page<ReturnModel>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                TotalRows = docs.Length
            };
            pm.TotalPages = pm.TotalRows / pageSize;
            if (pm.TotalRows % pageSize != 0) pm.TotalPages++;
            for (int i = (pageIndex - 1) * pageSize; i < pageIndex * pageSize && i < docs.Length; i++)
            {
                var doc = searcher.Doc(docs[i].doc);
                var content = HighlightHelper.HighLight(keyWord, doc.Get("Content"));
                var result = new ReturnModel
                {
                    Title = doc.Get("Title"),
                    Content = content,
                    Count = Regex.Matches(content, "<font").Count
                };
                resultList.Add(result);
            }

            pm.LsList = resultList;
            var elapsedTime = stopwatch.ElapsedMilliseconds + "ms";
            var list = new { list = pm, ms = elapsedTime };
            return list;
        }

View Code

盘古分词

Net Core使用Lucene.Net和盘古分词器 实现全文检索 Net Core使用Lucene.Net和盘古分词器 实现全文检索

/// <summary>
        /// 盘古分词
        /// </summary>
        /// <param name="words"></param>
        /// <returns></returns>
        public static object PanGu(string words)
        {
            Analyzer analyzer = new PanGuAnalyzer();
            TokenStream tokenStream = analyzer.TokenStream("", new StringReader(words));
            Lucene.Net.Analysis.Token token = null;
            var str = "";
            while ((token = tokenStream.Next()) != null)
            {
                string word = token.TermText(); // token.TermText() 取得当前分词
                str += word + "   |  ";
            }
            return str;
        }

View Code

搜索结果高亮显示

Net Core使用Lucene.Net和盘古分词器 实现全文检索 Net Core使用Lucene.Net和盘古分词器 实现全文检索

/// <summary>
        /// 搜索结果高亮显示
        /// </summary>
        /// <param name="keyword"> 关键字 </param>
        /// <param name="content"> 搜索结果 </param>
        /// <returns> 高亮后结果 </returns>
        public static string HighLight(string keyword, string content)
        {
            // SimpleHTMLFormatter:这个类是一个HTML的格式类,构造函数有两个,一个是开始标签,一个是结束标签。
            SimpleHTMLFormatter simpleHTMLFormatter =
                new SimpleHTMLFormatter("<font style=\"color:red;" +
                                        "font-family:'Cambria'\"><b>", "</b></font>");
            // 创建 Highlighter ,输入HTMLFormatter 和 盘古分词对象Semgent
            Highlighter highlighter =
                new Highlighter(simpleHTMLFormatter,
                    new Segment());
            // 设置每个摘要段的字符数
            highlighter.FragmentSize = int.MaxValue;
            // 获取最匹配的摘要段
            var str = highlighter.GetBestFragment(keyword, content);
            return str;
        }

View Code

对关键字进行盘古分词处理

Net Core使用Lucene.Net和盘古分词器 实现全文检索 Net Core使用Lucene.Net和盘古分词器 实现全文检索

/// <summary>
        /// 对关键字进行盘古分词处理
        /// </summary>
        /// <param name="keywords"></param>
        /// <param name="ktTokenizer"></param>
        /// <returns></returns>
        private static string GetKeyWordsSplitBySpace(string keywords, PanGuTokenizer ktTokenizer)
        {
            StringBuilder result = new StringBuilder();
            ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);

            foreach (WordInfo word in words)
            {
                if (word == null)
                {
                    continue;
                }
                result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
            }
            return result.ToString().Trim();
        }

View Code

Github:https://github.com/tenghao6/Lucene-PanGu

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
071. ElasticSearch 应用场景及核心概念
1\.ES使用场景给网站/APP添加搜索功能。存储、分析数据。管理、交互、分析空间信息,将ES用于GIS。2\.ES简介Elasticsearch是一个基于Lucene构建的开源、分布式、RESTful接口全文检索引擎。Elast
可莉 可莉
2年前
071. ElasticSearch 应用场景及核心概念
1\.ES使用场景给网站/APP添加搜索功能。存储、分析数据。管理、交互、分析空间信息,将ES用于GIS。2\.ES简介Elasticsearch是一个基于Lucene构建的开源、分布式、RESTful接口全文检索引擎。Elast
Stella981 Stella981
2年前
Lucene5.5学习(1)
认识Lucene下面是百科对Lucene的描述:Lucene是apache软件基金会4jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
Java搜索使用引擎
1、Java全文搜索引擎框架Lucene毫无疑问,Lucene是目前最受欢迎的Java全文搜索框架,准确地说,它是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene为开发人员提供了相当完整的工具包,可以非常方便地实现强大的全文检索功能。下面有几款搜索引擎框架也是基于Lucene实现的。官方网站:http:
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这