本类来源于LimFx.Common
Es(ElasticSearch)提供了极其强大的字符串搜索功能,但是很多开发人员却因为没学习过es的用法,或不了解es而使用mongodb自带的搜索。然而mongodb自带的搜索是必须全词匹配的,意味着如果你的英文单词拼写错了很可能搜不出对应的结果。并且mongodb的community版本对于中文搜索的支持极差,基本只能全字匹配。
本类为开发者提供了便捷使用es协同mongodb进行搜索的方法,而使用者不需要学习es的任何知识。
高度封装,使用者不需要了解es的任何知识
巧妙设计,搜索功能可以配合mongodb的任意filter、sort一起使用,就和直接用mongodb一样
高度可自定义,所有方法都可以在继承后重写,并且提供接口
性能优秀
首先,EsDBQueryService
是继承DBQueryServiceSlim
的,并且重写了其中的所有AddAsync
、DeleteAsync
方法,添加了一个特殊的、增加了query
参数的GetAsync
方法(用于搜索)AddAsync
相比基类,在调用基类AddAsync
前对Entity的SearchAbleString
属性使用es进行Tokenize
,比如我爱中国
会被es的smartcn分析器拆解为['我','我爱','中国','爱','中','国']
这些token,然后我们会把这些Token存入Entity的Tokens
属性中。
在调用基类AddAsync
后,我们会把Entity映射为需要存入es中的EsSearchEntity(EsSearchEntity也是泛型)然后存入es 然后再delete时,我们会同时删除es里的对应实体。
然后在GetAsync
中,搜索可以分为两种情况:
搜索时,orderby参数传入null或者空字符串,那么
搜索结果将按照相关性排序
搜索将会使用es
细节:先从es中获取按相关性排序的实例id,然后去mongodb查询到对应实例,再按照es中id顺序排序
这种情况建议不要使用其它filter,尽管这么做不会报错
若orderby传入非空的字符串,那么
搜索按照orderby排序
搜索不使用es的查询功能
细节:将query使用es化为tokens,对entity的tokens使用anyinfilter查询,结果以orderby排序,直接返回结果
这种情况可以随意使用filter
由此可见,以搜索相关性排序的搜索性能稍差一点点。 并且,使用者需要手动重写update方法,在update之前调用BeforeAddAndUpdate(T t)
,update之后调用AfterAddAndUpdate(T t)
,update的时候更新Tokens。例如:
public async ValueTask UpDateProjectAsync(Project researchProject)
{
await BeforeAddAndUpdate(researchProject);
var ud = Builders<Project>.Update
.Set(b => b.Name, researchProject.Name)
.Set(b => b.Description, researchProject.Description)
.Set(b => b.KeyWords, researchProject.KeyWords)
.Set(b => b.SearchAbleString, researchProject.SearchAbleString)
.Set(b => b.PrefixName, researchProject.PrefixName?.Trim())
.Set(b => b.Tokens, researchProject.Tokens);//设置tokens
if (!string.IsNullOrEmpty(researchProject.CoverUrl))
{
ud = ud.Set(b => b.CoverUrl, researchProject.CoverUrl);
}
await UpDateAsync(researchProject.Id, ud);
await AfterAddAndUpdate(researchProject);
}
其它使用方面与DBQueryServiceSlim完全一样
本文章使用limfx的vsocde插件快速发布