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

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

思路如下

首先我们需要把数据库里的所有商品内容,自动同步到 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. 微信小程序-转发

    仅供参考 1,js: onShareAppMessage(res) { return { title: '我在使用俺搜·找客户,10万+材料人都在用,就差你了', path: '/pages/inde ...

  2. html冲刺

    html知识点回顾与面试题<!--1.<DOCTYPE>告诉浏览器当前文档要以何种HTML或者XHTML规范解析2.语义标签strong 粗体em 斜体del 删除线ins 下划线 ...

  3. django之模型层(model)--多表相关操作(图书管理小练习)

    前面几篇随笔的数据库增删改查操作都是在单表的操作上的,然而现实中不可能都是单表操作,更多的是多表操作,一对一,一对多,多对多的表结构才是我们经常需要处理的,本篇将带我们了解多表操作的一些相关操作.也会 ...

  4. tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新ON UPDATE CURRENT_TIMESTAMP列的解决办法

    tk.mybatis是一个很好用的通用插件,把CRUD这些基本的数据操作全都用动态SQL语句自动生成了,mapper和xml里十分清爽,但是昨天发现有一个小坑,记录在此: 有一张表,结构如下(已经简化 ...

  5. new Random().Next(1, 100); 多线程同时执行结果很高概率相同,

    /// <summary> /// new Random().Next(1, 100); 多线程同时执行结果很高概率相同, /// 是用的当前时间为seed,时间相同结果相同 /// // ...

  6. Wireshark抓包实例诊断TCP连接问题

    转载请在文首保留原文出处:EMC中文支持论坛https://community.emc.com/go/chinese  介绍 前文论述了TCP基础知识,从本节开始,通过TCP抓包实例来诊断TCP常见问 ...

  7. 前端工程化系列[04]-Grunt构建工具的使用进阶

    在前端工程化系列[02]-Grunt构建工具的基本使用和前端工程化系列[03]-Grunt构建工具的运转机制这两篇文章中,我们对Grunt以及Grunt插件的使用已经有了初步的认识,并探讨了Grunt ...

  8. 【linux】linux下准确查询正在tomcat下运行的java进程。准确获取正在运行的java进程的PID

    准确获取定位到tomcat下正在运行的java进程的PID命令: ps -ef|grep java | grep catalina | awk '{print $2}' 准确定位到tomcat下正在运 ...

  9. 卷积的三种模式:full, same, valid

    通常用外部api进行卷积的时候,会面临mode选择. 本文清晰展示三种模式的不同之处,其实这三种不同模式是对卷积核移动范围的不同限制. 设 image的大小是7x7,filter的大小是3x3 1,f ...

  10. ELK架构设计

    1.架构一 2.架构二 3.架构三 4.架构四 示例1: 示例二: ELKB简述 E:Elasticsearch 是一个基于Lucene的分布式搜索和分析引擎,具有高可伸缩.高可靠和易管理等特点.支持 ...