lucene-plus依赖spring-boot 2.xx实现,使用spring或其他spring-boot工程的同学可根据自己的需求调整源码,源码坐标:lucene-plus: 基于lucene进行通用CRUD的封装,享受lucene丝滑般的操作。
有需求的同学可以fork工程的master分支进行调整开发,原则上不建议直接下载源码。lucene本身没有“初始化索引”的概念,所到之处皆是new,这给我一种很不爽的体验,所以创建lucene-plus的时候第一个实现的功能便是“初始化索引”,为什么是“lucene-plus”?因为我只是基于lucene进行了顶层的封装,而没有调整lucene任何源码。下面开始介绍lucene-plus如何进行索引的初始化。
1、引入maven坐标:
<dependency>
<groupId>cn.juque</groupId>
<artifactId>lucene-plus</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2、application-${profile}.yml文件添加配置:
# 指定索引所在目录
lucene:
index:
directory: D:\DOC\multiFile\index\
3、添加lucene-plus的扫描目录(lucene-plus依赖hutool工具的bean操作,所以"cn.hutool.extra.spring"必须能被工程扫描到):
@ComponentScans(value = {@ComponentScan("cn.juque.luceneplus"), @ComponentScan("cn.hutool.extra.spring")})
4、至此,便已完成lucene-plus的依赖引入。比如我们需要初始化一个关于文件信息的索引,我们首先需要实现接口:IndexTemplate,定义整个索引的json形式:
@Component("indexFileHandler")
public class IndexFileHandler implements IndexTemplate {
@Override
public String getTemplate() {
return "{\n"
+ " \"indexName\":\"file_info\",\n"
+ " \"fieldDTOList\":[\n"
+ " {\n"
+ " \"fieldName\":\"module_id\",\n"
+ " \"fieldType\":\"STRING\",\n"
+ " \"value\":\"${module_id}\",\n"
+ " \"store\":\"YES\"\n"
+ " },\n"
+ " {\n"
+ " \"fieldName\":\"server_path\",\n"
+ " \"fieldType\":\"STRING\",\n"
+ " \"value\":\"${server_path}\",\n"
+ " \"store\":\"YES\"\n"
+ " },\n"
+ " {\n"
+ " \"fieldName\":\"server_file_name\",\n"
+ " \"fieldType\":\"STRING\",\n"
+ " \"value\":\"${server_file_name}\",\n"
+ " \"store\":\"YES\"\n"
+ " },\n"
+ " {\n"
+ " \"fieldName\":\"client_file_name\",\n"
+ " \"fieldType\":\"STRING\",\n"
+ " \"value\":\"${client_file_name}\",\n"
+ " \"store\":\"YES\"\n"
+ " },\n"
+ " {\n"
+ " \"fieldName\":\"file_size\",\n"
+ " \"fieldType\":\"DOUBLE\",\n"
+ " \"value\":\"${file_size}\"\n"
+ " }\n"
+ " ]\n"
+ "}";
}
}
索引参数:
参数: | 描述 |
indexName | 索引名称 |
fieldDTOList | 字段信息的列表 |
fieldDTOList.fieldName | 字段名称 |
fieldDTOList.fieldType | 字段类型 |
fieldDTOList.value | 当前保留参数,没有实际意义 |
fieldDTOList.store | 是否存储。YES:存储;NO:不存储 |
fieldDTOList.point | 是否支持范围查询,只对fieldType:{INTEGER、LONG、DOUBLE}有效 |
fieldDTOList.analyzer | 分词器,支持的分词器参考:AnalyzerEnum |
完成索引的json定义,启动服务后索引信息会自动完成初始化,后续新增、编辑都会基于初始化的索引信息进行Document实例化。(注:索引字段只允许增量操作,变更、删除操作均无效,索引名称变更无效)
5、查询操作(支持查询单个Document,普通分页、滚动式分页):
BooleanQuery.Builder builder = new BooleanQuery.Builder();
Term term = new Term(IndexFileEnum.SERVER_FILE_NAME.getName(), serverName);
TermQuery termQuery = new TermQuery(term);
builder.add(termQuery, Occur.MUST);
Document document = this.documentPlusService.searchDocument(IndexFileEnum.FILE_INFO.getName(), builder);
普通分页查询实现的是逻辑分页,目前支持最大20万数据量的分页。如果有同学能实现物理分页,可以分享下。
6、新增文档操作:
// 保存
Map<String, Object> params = CollUtil.newHashMap(10);
params.put(IndexFileEnum.MODULE_ID.getName(), multiFileBo.getModuleId());
params.put(IndexFileEnum.CLIENT_FILE_NAME.getName(), multiFileBo.getFileName());
params.put(IndexFileEnum.SERVER_FILE_NAME.getName(), serverName);
params.put(IndexFileEnum.SERVER_PATH.getName(), serverPath);
params.put(IndexFileEnum.DOWNLOAD_TIMES.getName(), 0);
params.put(IndexFileEnum.UPLOAD_USER_ID.getName(), multiFileBo.getUserId());
try {
this.documentPlusService.addDocument(IndexFileEnum.FILE_INFO.getName(), params);
} catch (IOException e) {
log.error("save file error", e);
throw new AppException(InternetStorageMsgEnum.SYSTEM_ERROR);
}
lucene-plus会根据fieldName映射实例化Field,所以大家如果新增了字段,要先调整索引模板,否则单独添加到Map里面将无法生效。
7、更新操作:
BooleanQuery.Builder builder = new BooleanQuery.Builder();
serverNames.forEach(t->{
Term term = new Term(IndexFileEnum.SERVER_FILE_NAME.getName(), t);
builder.add(new TermQuery(term), Occur.SHOULD);
});
Map<String, Object> params = CollUtil.newHashMap(1);
params.put(IndexFileEnum.IS_VALID.getName(), Boolean.TRUE.toString());
this.documentPlusService.updateDocument(IndexFileEnum.FILE_INFO.getName(), builder, params);
api会根据传递过来的条件查出相关Document,然后执行delete-insert。lucene的updateDocument的实现逻辑实际也是delete-insert,区别在于:lucene-plus实现了Document的局部更新,而原生update方法是全量字段更新;
8、删除操作,与原生的删除操作并没有多大区别。至此,基于lucene-plus的增删改查的介绍也告一段落了。
文章结尾记录下开发过程遇到的问题,如有答案的同学,烦请告知一下
1、lucene-plus的更新操作是先查出来,然后把Document和Maps进行合并,最后根据条件执行delete操作,把合并后的Document重新保存。在实际操作中,最后一步调用原生的addDocument保存一直没成功,或是用原生的updateDocument也只是删除成功,而没有保存新的Document。无奈下,我改成调用lucene-plus的addDocument居然保存成功了,这个骚操作一直没整明白。。。