业务要求是对商品标题可以进行模糊搜索

例如用户输入了【我想查询下雅思托福考试】,这里我们需要先将这句话分词成【查询】【雅思】【托福】【考试】,然后搜索包含相关词汇的商品。

思路如下

首先我们需要把数据库里的所有商品内容,自动同步到 Lucene 的分词索引目录下缓存,效果如下

这里就用到了之前写的自动作业 Hangfire 大家可以参考下面的博文

https://www.cnblogs.com/jhli/p/10027074.html

定时更新缓存,后面就可以分词搜索了,更新索引代码如下

        public void UpdateMerchIndex()
{
try
{
Console.WriteLine($"[{DateTime.Now}] UpdateMerchIndex job begin..."); var indexDir = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "temp", "lucene", "merchs");
if (System.IO.Directory.Exists(indexDir) == false)
{
System.IO.Directory.CreateDirectory(indexDir);
} var VERSION = Lucene.Net.Util.LuceneVersion.LUCENE_48;
var director = FSDirectory.Open(new DirectoryInfo(indexDir));
var analyzer = new JieBaAnalyzer(TokenizerMode.Search);
var indexWriterConfig = new IndexWriterConfig(VERSION, analyzer); using (var indexWriter = new IndexWriter(director, indexWriterConfig))
{
if (File.Exists(Path.Combine(indexDir, "segments.gen")) == true)
{
indexWriter.DeleteAll();
} var query = _merchService.Where(t => t.IsDel == false); var index = ;
var size = ; var count = query.Count(); if (count > )
{
while (true)
{
var rs = query.OrderBy(t => t.CreateTime)
.Skip((index - ) * size)
.Take(size).ToList(); if (rs.Count == )
{
break;
} var addDocs = new List<Document>(); foreach (var item in rs)
{
var merchid = item.IdentityId.ToLowerString(); var doc = new Document();
var field1 = new StringField("merchid", merchid, Field.Store.YES);
var field2 = new TextField("name", item.Name?.ToLower(), Field.Store.YES);
doc.Add(field1);
doc.Add(field2);
addDocs.Add(doc);// 添加文本到索引中 } if (addDocs.Count > )
{
indexWriter.AddDocuments(addDocs);
} index = index + ;
} } } Console.WriteLine($"[{DateTime.Now}] UpdateMerchIndex job end!");
}
catch (Exception ex)
{
Console.WriteLine($"UpdateMerchIndex ex={ex}");
}
}

剩下的就是去查询索引内容,匹配到id,然后去数据库查询响应id的项。

搜索代码

        protected List<Guid> SearchMerchs(string key)
{
if (string.IsNullOrEmpty(key))
{
return null;
}
key = key.Trim().ToLower(); var rs = new List<Guid>(); try
{
var indexDir = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "temp", "lucene", "merchs"); var VERSION = Lucene.Net.Util.LuceneVersion.LUCENE_48; if (System.IO.Directory.Exists(indexDir) == true)
{
var reader = DirectoryReader.Open(FSDirectory.Open(new DirectoryInfo(indexDir)));
var search = new IndexSearcher(reader); var directory = FSDirectory.Open(new DirectoryInfo(indexDir), NoLockFactory.GetNoLockFactory());
var reader2 = IndexReader.Open(directory);
var searcher = new IndexSearcher(reader2); var parser = new QueryParser(VERSION, "name", new JieBaAnalyzer(TokenizerMode.Search));
var booleanQuery = new BooleanQuery(); var list = CutKeyWord(key);
foreach (var word in list)
{
var query1 = new TermQuery(new Term("name", word));
booleanQuery.Add(query1, Occur.SHOULD);
} var collector = TopScoreDocCollector.Create(, true);
searcher.Search(booleanQuery, null, collector);
var docs = collector.GetTopDocs(, collector.TotalHits).ScoreDocs; foreach (var d in docs)
{
var num = d.Doc;
var document = search.Doc(num);// 拿到指定的文档 var merchid = document.Get("merchid");
var name = document.Get("name"); if (Guid.TryParse(merchid, out Guid mid) == true)
{
rs.Add(mid);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"SearchMerchs ex={ex}");
} return rs;
}

对用户输入的话进行拆分分词代码 JiebaNet

        protected List<string> CutKeyWord(string key)
{
var rs = new List<string>();
var segmenter = new JiebaSegmenter();
var list = segmenter.Cut(key);
if (list != null && list.Count() > )
{
foreach (var item in list)
{
if (string.IsNullOrEmpty(item) || item.Length <= )
{
continue;
} rs.Add(item);
}
}
return rs;
}

需要添加的 nuget 引用的包和对应版本

Hangfire 1.7.0-beta1

Lucene.Net 4.8.0-beta00005

Lucene.Net.Analysis.Common 4.8.0-beta00005

Lucene.Net.QueryParser 4.8.0-beta00005

需要单独引用的dll文件

JiebaNet.Segmenter.dll 

下载地址

https://pan.baidu.com/s/1D7mQnow0FmoqedNYzugfKw

如果本地调试没有问题,发布到服务器上 自动执行作业就遇到这个问题

https://stackoverflow.com/questions/47746582/hangfire-job-throws-system-typeloadexception

 
System.TypeLoadException

Could not load type ‘***’ from assembly ‘***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’.

其实这个报错并不是原因,把异常打印出来就知道了

原因是没有将 Resources 文件夹下的字典文件 dict.txt 发布到服务器上

这个坑让我浪费了半天时间。。。

【netcore基础】.Net core通过 Lucene.Net 和 jieba.NET 处理分词搜索功能的更多相关文章

  1. 【netcore基础】CentOS 7.6.1810 搭建.net core 2.1 linux 运行环境 nginx反向代理 supervisor配置自启动

    之前写过一篇Ubuntu的环境搭建博客,感觉一些配置大同小异,这里重点记录下 nginx 作为静态 angular 项目文件服务器的配置 参考链接 [netcore基础]ubuntu 16.04 搭建 ...

  2. Python3 与 C# 面向对象之~继承与多态 Python3 与 C# 面向对象之~封装 Python3 与 NetCore 基础语法对比(Function专栏) [C#]C#时间日期操作 [C#]C#中字符串的操作 [ASP.NET]NTKO插件使用常见问题 我对C#的认知。

    Python3 与 C# 面向对象之-继承与多态   文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html 目录: 2.继承 ¶ 2.1.单继 ...

  3. .netCore+Vue 搭建的简捷开发框架 (4)--NetCore 基础 -2

    上节中,我们初步的介绍了一下NetCore的一些基础知识,为了控制篇幅(其实也是因为偷懒),我将NetCore 基础分为两部分来写. 0.WebAPI 项目的建立 1..NetCore 项目执行(加载 ...

  4. 动画基础--基于Core Animation(3)

    参考:https://zsisme.gitbooks.io/ios-/content/ 前面的文章动画基础--基于Core Animation(1),动画基础--基于Core Animation(2) ...

  5. 动画基础--基于Core Animation(2)

    参考:https://zsisme.gitbooks.io/ios-/content/ 前面的文章动画基础--基于Core Animation(1)提到了图层的基本概念以及可动画参数几何学等知识. 本 ...

  6. 动画基础--基于Core Animation(1)

    1.简介 上一篇文章[New learn]动画-基于UIView了解到了一些直接由UIView这个在UIKIT提供的类中提供的一些动画方法. 使用UIView的动画特性已经能够满足我们很多的需求,它是 ...

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

    Lucene.net Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎, ...

  8. Lucene.net(4.8.0) 学习问题记录五: JIEba分词和Lucene的结合,以及对分词器的思考

    前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...

  9. 【lucene系列学习四】使用IKAnalyzer分词器实现敏感词和停用词过滤

    Lucene自带的中文分词器SmartChineseAnalyzer不太好扩展,于是我用了IKAnalyzer来进行敏感词和停用词的过滤. 首先,下载IKAnalyzer,我下载了 然后,由于IKAn ...

随机推荐

  1. Linux命令之tar篇

    作业一: 1)   将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/1.txt(覆盖) [root@localhost ~]# cat /etc/passwd /etc/group > ...

  2. cout.setf()

    cout用来实现格式输出,类似于C语言中通过printf(). cout.setf()的作用是通过设置格式标志来控制输出形式,如,其中ios_base::fixed表示:用正常的记数方法显示浮点数(与 ...

  3. ES6_函数方法

    //2017/7/15 //Javascript 中的方法:在一个对象中绑定函数,称为这个对象的方法. */ var boy={ name:'xiaoming', birth:2007, age:fu ...

  4. 开源流媒体服务器SRS学习笔记(1) - 安装、推流、拉流

    SRS(Simple RTMP Server)  是国人写的一款非常优秀的开源流媒体服务器软件,可用于直播/录播/视频客服等多种场景,其定位是运营级的互联网直播服务器集群. 一.安装 官网提供了3种安 ...

  5. 关于kafka重新消费数据问题

    我们在使用consumer消费数据时,有些情况下我们需要对已经消费过的数据进行重新消费,这里介绍kafka中两种重新消费数据的方法. 1. 修改offset 我们在使用consumer消费的时候,每个 ...

  6. 【独家】硅谷创业公司在中国常跌的五个坑|禾赛科技CEO李一帆柏林亚太周主题演讲

    [独家]硅谷创业公司在中国常跌的五个坑|禾赛科技CEO李一帆柏林亚太周主题演讲 李一帆 Xtecher特稿作者 关注  Xtecher推荐   演讲者:李一帆   翻译:晓娜   网址:www.xt ...

  7. wget整站抓取、网站抓取功能;下载整个网站;下载网站到本地

    wget -r   -p -np -k -E  http://www.xxx.com 抓取整站 wget -l 1 -p -np -k       http://www.xxx.com 抓取第一级 - ...

  8. 自定义spring参数注解 - 打破@RequestBody单体限制

    本文主要描述怎样自定义类似@RequestBody这样的参数注解来打破@RequestBody的单体限制. 目录1 @RequestBody的单体限制2 自定义spring的参数注解3 编写sprin ...

  9. ionic中android的返回键

    ionic中android的返回键 在ionic框架中已经注册了几个返回事件,分别是 view sideMenu modal actionSheet popup loading 他们的优先级分别是 v ...

  10. LIN 笔记

    LIN 使用了 1 根线来进行通信,但是,它必须要参考 VBat 和 GND.离开这两个参考电平,并没有办法来判断线上的 bit 状态. 另外,根据经典的 LIN 驱动电路(一个 OC 门),RX 接 ...