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

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

思路如下

首先我们需要把数据库里的所有商品内容,自动同步到 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. js小题目(持续更新)

    总是感觉之前做过的问题很久没碰的话就会忘掉,于是打算专门开一个记录小题目的随笔当题典用. 目录 五种主要数据类型进行值复制 数组去重 数组去重并计数 实现clone()方法,对五种主要数据类型进行值复 ...

  2. python正则表达式里引入变量

    import re def reg_exp(senten): jiqiren = "阿童木" matchObj1 = re.search( r'(你(.*?)(男|女))|(机器( ...

  3. HTML常用标签3

    1.<a>标签,是内联标签 href:需要跳转的网址 2.id属性: 相当于一个身份证 例如: 设置id属性 3.列表标签 <ul>: 无序列表 [type属性:disc(实心 ...

  4. sql 索引笔记2

    以下资料都来于MSDN. 聚集索引指南: 一.此列和列值供内部使用,用户不能查看或访问. 查询注意事项 在创建聚集索引之前,应先了解数据是如何被访问的.考虑对具有以下特点的查询使用聚集索引: 使用运算 ...

  5. Java知识回顾 (9) 同步、异步IO

    一.基本概念 同步和异步: 同步和异步是针对应用程序和内核的交互而言的. 同步指的是用户进程触发IO 操作并等待或者轮询的去查看IO 操作是否就绪: 而异步是指用户进程触发IO 操作以后便开始做自己的 ...

  6. Python 和 Scikit-Learn

    Reference:http://mp.weixin.qq.com/s?src=3&timestamp=1474985436&ver=1&signature=at24GKibw ...

  7. 理解Docker镜像分层

    关于base镜像 base 镜像有两层含义: 不依赖其他镜像,从 scratch 构建. 其他镜像可以之为基础进行扩展. 所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker ...

  8. How to copy the contents of std::vector to c-style static array,safely?

    [问题] I am getting warning when using the std copy function. I have a byte array that I declare. byte ...

  9. c# System.Threading.Thread

    using System; using System.Threading; // Simple threading scenario: Start a static method running // ...

  10. 【redis持久化】redis持久化理解

    1.以下内容仅为个人理解和总结,仅供参考,万万不可全盘真信,内容会进行实时改进和修正 2.redis持久化: 参考链接1.https://redis.io/topics/persistence  -- ...