大部分项目都会涉及模糊搜索功能,而实现模糊搜索一般分为两个派系:
对于较为大型的项目来说,使用Solr、ES或者Milvus之类的引擎是比较流行的选择了(效果只能说优秀),而对于中小型项目,如果考虑这些较为重型的引擎,就意味着开发成本和运维成本
而一个简单的项目,特别是很多后台管理系统,模糊搜索仅仅是一个附带的功能(并非核心功能),所以我并不花太多时间去集成一个重量级的搜索引擎,此时为了方便就会选择like系列(偷懒的时候就这么干)
但是like也存在一些问题:
终究是为一时的懒惰付出了代价…
但是…终究是想抽个空喝一口茶,顺便摸个鱼,如此我只能祭出SimSearch:一个轻量级的springboot项目索引构建工具,实现快速模糊搜索,相比于搜索引擎派系,这是一种轻量级的实现方式
可以有两种使用模式:注解和工具类
先来说说注解使用,在原有的实体类和业务代码上标几个注解即可
cn.langpy simsearch 2.0.0
使用了@Aspect注解,未引入的自行引入,如aspectj或者spring-boot-starter-aop
在application.properties中配置
#索引存储器 默认为内存 [memory,memory-fs,base-fs,nio-fs]
#内存富裕的情况下使用memory,如果是百万以上数据量选用fs系列
sim-search.saver=memory
#索引位置,saver!=memory时需配置
sim-search.dir=/data/indexlocation
#创建索引的核心线程数量,根据cpu自行决定,可不填,默认为5
sim-search.thread-core-size=5
#创建索引的最大线程数量,根据cpu自行决定,可不填,默认为200
sim-search.thread-max-size=10
#创建索引的线程队列容量,自行决定,可不填,默认为200000
sim-search.thread-queue-size=200000
#重启时是否要对之前的索引进行删除,默认为false
sim-search.index.init=true
#最大返回的搜索结果数量
sim-search.result.size=50
import cn.langpy.simsearch.annotation.IndexColumn;
import cn.langpy.simsearch.annotation.IndexId;public class Student {/*索引唯一id 必须*/@IndexId private String id;/*需要创建索引的字段:用来模糊搜索*/@IndexColumnprivate String studentName;@IndexColumnprivate String schoolName;private String age;
}
import cn.langpy.simsearch.annotation.CreateIndex;
import cn.langpy.simsearch.annotation.DeleteIndex;
import cn.langpy.simsearch.annotation.SearchIndex;@Service
public class StudentServiceImpl implements StudentService {/*加上@CreateIndex后 异步创建索引,不影响正常业务的保存逻辑 indexParam:需要创建索引的参数*//*该注解包含了更新操作 有则更新 无则创建*/@CreateIndex(indexParam = "student")public boolean insert(Student student){/*业务逻辑*/}
}
@Service
public class StudentServiceImpl implements StudentService {/*加上@DeleteIndex后 异步删除索引,不影响正常业务的删除逻辑 indexParam:需要删除索引的参数*/@DeleteIndex(indexParam = "student")public boolean delete(Student student){/*业务逻辑*/}
}
@Service
public class StudentServiceImpl implements StudentService {/*根据studentName属性搜索Student 搜索的属性要和实体的属性保持一致 */@SearchIndex(by = "studentName")public List search(Student student){/*方法内部什么都不需要写*/return null;}/*根据schoolName属性搜索Student */@SearchIndex(by = "schoolName")public List search(Student Student){/*方法内部什么都不需要写*//*如果再索引中未查到对应信息,可通过该方法设置默认查询,比如往数据库进行like模糊匹配*/return searchWithLikeByName(schoolName);}
}
注意:搜索结果仅仅是搜索出加上@IndexId和@IndexColumn的字段,具体内容自行往业务数据库查询
public class IndexManager{/*创建索引*/public static void createIndex(IndexContent indexContent);/*删除索引*/public static void deleteIndex(String idName, String idValue,Class entityClass);/*搜索 详见源码的demo项目*/public static List searchIndexIds(String name, String value,Class> entityClass);/*搜索 详见源码的demo项目*/public static List searchIndexObjects(String name, String value,Class entityClass);public static void deleteAll();/*为对象创建索引*/public static void createIndex(Object entity);public static void createIndexs(List
使用100万行中文 进行模糊搜索测试
i7 16g
| 存储模式(saver) | 平均耗时 | 最大耗时 | 最小耗时 |
|---|---|---|---|
| nio-fs(nio文件模式) | 45.93ms | 144.5ms | 15.04ms |
| base-fs(常规文件系统) | 25.93ms | 97.32ms | 12.24ms |
| memory-fs(nmap文件模式) | 23.75ms | 114.12ms | 8.4ms |
| memory(内存模式) | 11.56ms | 42.35ms | 7.04ms |
相对于文件系统,内存性能最好的无疑的,前提是内存有余,或者数据量不是很过分
另外,以上结果仅仅作为一个参考,不能说明nio的性能就最差,根据数据量和场景选择
Gitee
很简单的demo项目
上一篇:校园矛盾纠纷有了新解法