|
@@ -0,0 +1,198 @@
|
|
|
+package com.dayou.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.dayou.annotation.LuceneResource;
|
|
|
+import com.dayou.annotation.LuceneSearchable;
|
|
|
+import com.dayou.configuration.DfsConfig;
|
|
|
+import com.dayou.service.ILuceneSearchService;
|
|
|
+import com.dayou.utils.MybatisPlusUtils;
|
|
|
+import com.dayou.utils.ReflectUtils;
|
|
|
+import com.dayou.utils.SpringContextHolder;
|
|
|
+import com.dayou.vo.LuceneSearchVO;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.lucene.analysis.Analyzer;
|
|
|
+import org.apache.lucene.document.Document;
|
|
|
+import org.apache.lucene.document.StringField;
|
|
|
+import org.apache.lucene.document.TextField;
|
|
|
+import org.apache.lucene.index.IndexWriter;
|
|
|
+import org.apache.lucene.index.IndexWriterConfig;
|
|
|
+import org.apache.lucene.store.Directory;
|
|
|
+import org.apache.lucene.store.FSDirectory;
|
|
|
+import org.apache.poi.ss.formula.functions.T;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.io.Resource;
|
|
|
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
|
+import org.springframework.core.io.support.ResourcePatternResolver;
|
|
|
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|
|
+import org.springframework.core.type.classreading.MetadataReader;
|
|
|
+import org.springframework.core.type.classreading.MetadataReaderFactory;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.ClassUtils;
|
|
|
+import org.wltea.analyzer.lucene.IKAnalyzer;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.nio.file.FileSystems;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 类说明:全局搜索服务
|
|
|
+ *
|
|
|
+ * @author: wucl
|
|
|
+ * @since: 2024/4/26
|
|
|
+ * created with IntelliJ IDEA.
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class LuceneSearchServiceImpl implements ILuceneSearchService {
|
|
|
+
|
|
|
+ private final String BASE_PACKAGE = "com.dayou.entity";
|
|
|
+
|
|
|
+ private final String RESOURCE_PATTERN = "/**/*.class";
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DfsConfig dfsConfig;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void initializeIndex() {
|
|
|
+ Map<String, Class> luceneResourceEntity = scanLuceneEntity();
|
|
|
+ if (CollectionUtil.isNotEmpty(luceneResourceEntity)){
|
|
|
+ Collection<Document> docs = new ArrayList<>();
|
|
|
+ for(Map.Entry<String,Class> entry :luceneResourceEntity.entrySet()){
|
|
|
+ Class clazz = entry.getValue();
|
|
|
+ String beanName = entry.getKey();
|
|
|
+ ServiceImpl serviceBean = (ServiceImpl) SpringContextHolder.getBean(beanName);
|
|
|
+ Field[] fields = clazz.getDeclaredFields();
|
|
|
+ List<String> searchAbleFields = new ArrayList<>();
|
|
|
+ for (Field field :fields){
|
|
|
+ LuceneSearchable annotation = field.getAnnotation(LuceneSearchable.class);
|
|
|
+ if (annotation!=null){
|
|
|
+ String value = annotation.value();
|
|
|
+ if (StrUtil.isBlank(value)){
|
|
|
+ value = field.getName();
|
|
|
+ }
|
|
|
+ searchAbleFields.add(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ LambdaQueryWrapper wrapper = MybatisPlusUtils.fieldValues(searchAbleFields, queryWrapper, clazz);
|
|
|
+ if (wrapper!=null){
|
|
|
+ List list = serviceBean.list(wrapper);
|
|
|
+ try {
|
|
|
+ doCreatedLuceneIndex(list,docs);
|
|
|
+ } catch (NoSuchFieldException e) {
|
|
|
+ log.error("!!!create index field error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<LuceneSearchVO> queryIndex(String keyword) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void addIndex() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void removeIndex() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private Map<String, Class> scanLuceneEntity(){
|
|
|
+ Map<String, Class> luceneResourceEntity = new HashMap<>();
|
|
|
+ //spring工具类,可以获取指定路径下的全部类
|
|
|
+ ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
|
|
+ try {
|
|
|
+ String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
|
|
+ ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
|
|
|
+ Resource[] resources = resourcePatternResolver.getResources(pattern);
|
|
|
+ //MetadataReader 的工厂类
|
|
|
+ MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
|
|
+ for (Resource resource : resources) {
|
|
|
+ //用于读取类信息
|
|
|
+ MetadataReader reader = readerfactory.getMetadataReader(resource);
|
|
|
+ //扫描到的class
|
|
|
+ String classname = reader.getClassMetadata().getClassName();
|
|
|
+ Class<?> clazz = Class.forName(classname);
|
|
|
+ //判断是否有指定主解
|
|
|
+ LuceneResource anno = clazz.getAnnotation(LuceneResource.class);
|
|
|
+ if (anno != null) {
|
|
|
+ //将注解中的类型值作为key,对应的类作为 value
|
|
|
+ String serviceImplClassName = anno.serviceImplClassName();
|
|
|
+ luceneResourceEntity.put(serviceImplClassName, clazz);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (IOException | ClassNotFoundException e) {
|
|
|
+ }
|
|
|
+ return luceneResourceEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void doCreatedLuceneIndex(List<Object> luceneData, Collection<Document> docs ) throws NoSuchFieldException {
|
|
|
+ Class aClass = luceneData.get(0).getClass();
|
|
|
+ LuceneResource annotation = (LuceneResource) aClass.getAnnotation(LuceneResource.class);
|
|
|
+ String businessType = annotation.value().getMsg();
|
|
|
+ String menuName = annotation.menuName();
|
|
|
+ String url = annotation.url();
|
|
|
+ String checkField = annotation.checkField();
|
|
|
+ Field[] declaredFields = aClass.getDeclaredFields();
|
|
|
+ for (Object t : luceneData) {
|
|
|
+ Object id = ReflectUtils.getFieldValue(t, "id");
|
|
|
+ String xUrl = url;
|
|
|
+ String xMenuName = menuName;
|
|
|
+ Boolean checkValue = false;
|
|
|
+ if (StrUtil.isNotBlank(checkField)){
|
|
|
+ checkValue = ReflectUtils.getFieldValue(t, checkField);
|
|
|
+ if (checkValue){
|
|
|
+ LuceneSearchable declaredField = aClass.getDeclaredField(checkField).getAnnotation(LuceneSearchable.class);
|
|
|
+ xUrl = declaredField.url();
|
|
|
+ xMenuName = declaredField.menuName();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ for (Field field : declaredFields) {
|
|
|
+ LuceneSearchable anno = field.getAnnotation(LuceneSearchable.class);
|
|
|
+ if (anno != null) {
|
|
|
+ Object fieldValue = ReflectUtils.getFieldValue(t, field.getName());
|
|
|
+ if (fieldValue != null) {
|
|
|
+ Document document = new Document();
|
|
|
+ document.add(new StringField("id", String.valueOf(id), org.apache.lucene.document.Field.Store.YES));
|
|
|
+ document.add(new TextField("result", String.valueOf(fieldValue), org.apache.lucene.document.Field.Store.YES));
|
|
|
+ document.add(new TextField("businessEnum", businessType, org.apache.lucene.document.Field.Store.YES));
|
|
|
+ if (checkValue){
|
|
|
+ document.add(new TextField("menuName", xMenuName, org.apache.lucene.document.Field.Store.YES));
|
|
|
+ document.add(new TextField("url", xUrl, org.apache.lucene.document.Field.Store.YES));
|
|
|
+ }else{
|
|
|
+ document.add(new TextField("menuName", menuName, org.apache.lucene.document.Field.Store.YES));
|
|
|
+ document.add(new TextField("url", url, org.apache.lucene.document.Field.Store.YES));
|
|
|
+ }
|
|
|
+ docs.add(document);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Analyzer analyzer = new IKAnalyzer();
|
|
|
+ IndexWriterConfig config = new IndexWriterConfig(analyzer);
|
|
|
+ config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
|
|
|
+
|
|
|
+ try (Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(dfsConfig.getLuceneDir()));
|
|
|
+ IndexWriter indexWriter = new IndexWriter(directory, config)) {
|
|
|
+ indexWriter.addDocuments(docs);
|
|
|
+ indexWriter.commit();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("!!!create index error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|