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居然保存成功了,这个骚操作一直没整明白。。。