✨ 文章用户作品集lucene索引更新
This commit is contained in:
parent
1a0571a7e8
commit
c8df03ccd1
@ -5,13 +5,17 @@ import com.github.pagehelper.PageInfo;
|
|||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
import com.rymcu.forest.dto.ArticleDTO;
|
import com.rymcu.forest.dto.ArticleDTO;
|
||||||
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
import com.rymcu.forest.dto.UserDTO;
|
import com.rymcu.forest.dto.UserDTO;
|
||||||
import com.rymcu.forest.lucene.model.ArticleLucene;
|
import com.rymcu.forest.lucene.model.ArticleLucene;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
import com.rymcu.forest.lucene.model.UserLucene;
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
import com.rymcu.forest.lucene.service.LuceneService;
|
import com.rymcu.forest.lucene.service.LuceneService;
|
||||||
|
import com.rymcu.forest.lucene.service.PortfolioLuceneService;
|
||||||
import com.rymcu.forest.lucene.service.UserDicService;
|
import com.rymcu.forest.lucene.service.UserDicService;
|
||||||
import com.rymcu.forest.lucene.service.UserLuceneService;
|
import com.rymcu.forest.lucene.service.UserLuceneService;
|
||||||
import com.rymcu.forest.lucene.util.ArticleIndexUtil;
|
import com.rymcu.forest.lucene.util.ArticleIndexUtil;
|
||||||
|
import com.rymcu.forest.lucene.util.PortfolioIndexUtil;
|
||||||
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.Utils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -36,13 +40,15 @@ public class LuceneSearchController {
|
|||||||
|
|
||||||
@Resource private LuceneService luceneService;
|
@Resource private LuceneService luceneService;
|
||||||
@Resource private UserLuceneService userLuceneService;
|
@Resource private UserLuceneService userLuceneService;
|
||||||
|
@Resource private PortfolioLuceneService portfolioLuceneService;
|
||||||
@Resource private UserDicService dicService;
|
@Resource private UserDicService dicService;
|
||||||
|
|
||||||
// @PostConstruct
|
@PostConstruct
|
||||||
public void createIndex() {
|
public void createIndex() {
|
||||||
// 删除系统运行时保存的索引,重新创建索引
|
// 删除系统运行时保存的索引,重新创建索引
|
||||||
ArticleIndexUtil.deleteAllIndex();
|
ArticleIndexUtil.deleteAllIndex();
|
||||||
UserIndexUtil.deleteAllIndex();
|
UserIndexUtil.deleteAllIndex();
|
||||||
|
PortfolioIndexUtil.deleteAllIndex();
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
CompletableFuture<String> future =
|
CompletableFuture<String> future =
|
||||||
CompletableFuture.supplyAsync(
|
CompletableFuture.supplyAsync(
|
||||||
@ -50,21 +56,23 @@ public class LuceneSearchController {
|
|||||||
System.out.println(">>>>>>>>> 开始创建索引 <<<<<<<<<<<");
|
System.out.println(">>>>>>>>> 开始创建索引 <<<<<<<<<<<");
|
||||||
luceneService.writeArticle(luceneService.getAllArticleLucene());
|
luceneService.writeArticle(luceneService.getAllArticleLucene());
|
||||||
userLuceneService.writeUser(userLuceneService.getAllUserLucene());
|
userLuceneService.writeUser(userLuceneService.getAllUserLucene());
|
||||||
|
portfolioLuceneService.writePortfolio(portfolioLuceneService.getAllPortfolioLucene());
|
||||||
System.out.println(">>>>>>>>> 索引创建完毕 <<<<<<<<<<<");
|
System.out.println(">>>>>>>>> 索引创建完毕 <<<<<<<<<<<");
|
||||||
System.out.println("加载用户配置的自定义扩展词典到主词库表");
|
System.out.println("加载用户配置的自定义扩展词典到主词库表");
|
||||||
try {
|
try {
|
||||||
|
System.out.println(">>>>>>>>> 开始加载用户词典 <<<<<<<<<<<");
|
||||||
dicService.writeUserDic();
|
dicService.writeUserDic();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("加载用户词典失败,未成功创建用户词典");
|
System.out.println("加载用户词典失败,未成功创建用户词典");
|
||||||
}
|
}
|
||||||
return "索引成功创建";
|
return ">>>>>>>>> 加载用户词典完毕 <<<<<<<<<<<";
|
||||||
},
|
},
|
||||||
executor);
|
executor);
|
||||||
future.thenAccept(System.out::println);
|
future.thenAccept(System.out::println);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索,实现高亮
|
* 文章搜索,实现高亮
|
||||||
*
|
*
|
||||||
* @param q
|
* @param q
|
||||||
* @return
|
* @return
|
||||||
@ -106,7 +114,7 @@ public class LuceneSearchController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索,实现高亮
|
* 用户搜索,实现高亮
|
||||||
*
|
*
|
||||||
* @param q
|
* @param q
|
||||||
* @return
|
* @return
|
||||||
@ -146,4 +154,46 @@ public class LuceneSearchController {
|
|||||||
PageInfo<UserDTO> pageInfo = new PageInfo<>(page);
|
PageInfo<UserDTO> pageInfo = new PageInfo<>(page);
|
||||||
return GlobalResultGenerator.genSuccessResult(Utils.getUserGlobalResult(pageInfo));
|
return GlobalResultGenerator.genSuccessResult(Utils.getUserGlobalResult(pageInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作品集搜索,实现高亮
|
||||||
|
*
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/searchPortfolio/{q}")
|
||||||
|
public GlobalResult<?> searchPortfolio(
|
||||||
|
@PathVariable String q,
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||||
|
// 找出相关文章,相关度倒序
|
||||||
|
List<PortfolioLucene> resList = portfolioLuceneService.searchPortfolio(q);
|
||||||
|
// 分页组装文章详情
|
||||||
|
int total = resList.size();
|
||||||
|
if (total == 0) {
|
||||||
|
return GlobalResultGenerator.genSuccessResult("未找到相关作品集");
|
||||||
|
}
|
||||||
|
Page<PortfolioDTO> page = new Page<>(pageNum, pageSize);
|
||||||
|
page.setTotal(total);
|
||||||
|
int startIndex = (pageNum - 1) * pageSize;
|
||||||
|
int endIndex = Math.min(startIndex + pageSize, total);
|
||||||
|
// 分割子列表
|
||||||
|
List<PortfolioLucene> subList = resList.subList(startIndex, endIndex);
|
||||||
|
String[] ids = subList.stream().map(PortfolioLucene::getIdPortfolio).toArray(String[]::new);
|
||||||
|
List<PortfolioDTO> portfolioDTOList = portfolioLuceneService.getPortfoliosByIds(ids);
|
||||||
|
PortfolioDTO temp;
|
||||||
|
// 写入文章关键词信息
|
||||||
|
for (int i = 0; i < portfolioDTOList.size(); i++) {
|
||||||
|
temp = portfolioDTOList.get(i);
|
||||||
|
temp.setPortfolioTitle(subList.get(i).getPortfolioTitle());
|
||||||
|
if (subList.get(i).getPortfolioDescription().length() > 10) {
|
||||||
|
// 内容中命中太少则不替换
|
||||||
|
temp.setPortfolioDescription(subList.get(i).getPortfolioDescription());
|
||||||
|
}
|
||||||
|
portfolioDTOList.set(i, temp);
|
||||||
|
}
|
||||||
|
page.addAll(portfolioDTOList);
|
||||||
|
PageInfo<PortfolioDTO> pageInfo = new PageInfo<>(page);
|
||||||
|
return GlobalResultGenerator.genSuccessResult(Utils.getPortfolioGlobalResult(pageInfo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.rymcu.forest.lucene.lucene;
|
||||||
|
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.document.Field;
|
||||||
|
import org.apache.lucene.document.TextField;
|
||||||
|
import org.apache.lucene.index.IndexWriter;
|
||||||
|
import org.apache.lucene.index.IndexWriterConfig;
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PortfolioBeanIndex
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
* @date 2021/4/17 14:10
|
||||||
|
*/
|
||||||
|
public class PortfolioBeanIndex extends BaseIndex<PortfolioLucene> {
|
||||||
|
|
||||||
|
public PortfolioBeanIndex(
|
||||||
|
String parentIndexPath,
|
||||||
|
int subIndex,
|
||||||
|
CountDownLatch countDownLatch1,
|
||||||
|
CountDownLatch countDownLatch2,
|
||||||
|
List<PortfolioLucene> list) {
|
||||||
|
super(parentIndexPath, subIndex, countDownLatch1, countDownLatch2, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void indexDoc(IndexWriter writer, PortfolioLucene user) throws Exception {
|
||||||
|
Document doc = new Document();
|
||||||
|
Field id = new Field("id", user.getIdPortfolio() + "", TextField.TYPE_STORED);
|
||||||
|
Field title = new Field("title", user.getPortfolioTitle(), TextField.TYPE_STORED);
|
||||||
|
Field summary = new Field("summary", user.getPortfolioDescription(), TextField.TYPE_STORED);
|
||||||
|
// 添加到Document中
|
||||||
|
doc.add(id);
|
||||||
|
doc.add(title);
|
||||||
|
doc.add(summary);
|
||||||
|
if (writer.getConfig().getOpenMode() == IndexWriterConfig.OpenMode.CREATE) {
|
||||||
|
writer.addDocument(doc);
|
||||||
|
} else {
|
||||||
|
writer.updateDocument(new Term("id", user.getIdPortfolio() + ""), doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.rymcu.forest.lucene.mapper;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
|
import com.rymcu.forest.dto.UserDTO;
|
||||||
|
import com.rymcu.forest.entity.Portfolio;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PortfolioLuceneMapper
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
* @date 2021/4/17 10:00
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PortfolioLuceneMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载所有作品集信息
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<PortfolioLucene> getAllPortfolioLucene();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载所有作品集信息
|
||||||
|
*
|
||||||
|
* @param ids 作品集id(半角逗号分隔)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<PortfolioDTO> getPortfoliosByIds(@Param("ids") String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载作品集
|
||||||
|
*
|
||||||
|
* @param id 用户id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
PortfolioLucene getById(@Param("id") String id);
|
||||||
|
}
|
@ -18,7 +18,7 @@ import lombok.NoArgsConstructor;
|
|||||||
public class PortfolioLucene {
|
public class PortfolioLucene {
|
||||||
|
|
||||||
/** 作品集编号 */
|
/** 作品集编号 */
|
||||||
private Integer idPortfolio;
|
private String idPortfolio;
|
||||||
|
|
||||||
/** 作品集名称 */
|
/** 作品集名称 */
|
||||||
private String portfolioTitle;
|
private String portfolioTitle;
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.rymcu.forest.lucene.service;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PortfolioLuceneService
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
* @date 2021/4/17 10:10
|
||||||
|
*/
|
||||||
|
public interface PortfolioLuceneService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量写入作品集信息到索引
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
void writePortfolio(List<PortfolioLucene> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入单个作品集索引
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void writePortfolio(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入单个作品集索引
|
||||||
|
*
|
||||||
|
* @param portfolioLucene
|
||||||
|
*/
|
||||||
|
void writePortfolio(PortfolioLucene portfolioLucene);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新单个作品集索引
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void updatePortfolio(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除单个作品集索引
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void deletePortfolio(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关键词搜索
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
List<PortfolioLucene> searchPortfolio(String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载所有作品集内容
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<PortfolioLucene> getAllPortfolioLucene();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载所有作品集内容
|
||||||
|
*
|
||||||
|
* @param ids 作品集id(半角逗号分隔)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<PortfolioDTO> getPortfoliosByIds(String[] ids);
|
||||||
|
}
|
@ -0,0 +1,190 @@
|
|||||||
|
package com.rymcu.forest.lucene.service.impl;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
|
import com.rymcu.forest.lucene.lucene.IKAnalyzer;
|
||||||
|
import com.rymcu.forest.lucene.lucene.PortfolioBeanIndex;
|
||||||
|
import com.rymcu.forest.lucene.mapper.PortfolioLuceneMapper;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
import com.rymcu.forest.lucene.service.PortfolioLuceneService;
|
||||||
|
import com.rymcu.forest.lucene.util.LucenePath;
|
||||||
|
import com.rymcu.forest.lucene.util.PortfolioIndexUtil;
|
||||||
|
import com.rymcu.forest.lucene.util.SearchUtil;
|
||||||
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
|
||||||
|
import org.apache.lucene.queryparser.classic.ParseException;
|
||||||
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
|
import org.apache.lucene.search.TopDocs;
|
||||||
|
import org.apache.lucene.search.highlight.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserServiceImpl
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
* @date 2021/3/6 10:29
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class PortfolioLuceneServiceImpl implements PortfolioLuceneService {
|
||||||
|
|
||||||
|
@Resource private PortfolioLuceneMapper portfolioLuceneMapper;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文章的数据解析为一个个关键字词存储到索引文件中
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writePortfolio(List<PortfolioLucene> list) {
|
||||||
|
try {
|
||||||
|
int totalCount = list.size();
|
||||||
|
int perThreadCount = 3000;
|
||||||
|
int threadCount = totalCount / perThreadCount + (totalCount % perThreadCount == 0 ? 0 : 1);
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
|
||||||
|
CountDownLatch countDownLatch1 = new CountDownLatch(1);
|
||||||
|
CountDownLatch countDownLatch2 = new CountDownLatch(threadCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < threadCount; i++) {
|
||||||
|
int start = i * perThreadCount;
|
||||||
|
int end = Math.min((i + 1) * perThreadCount, totalCount);
|
||||||
|
List<PortfolioLucene> subList = list.subList(start, end);
|
||||||
|
Runnable runnable =
|
||||||
|
new PortfolioBeanIndex(LucenePath.PORTFOLIO_PATH, i, countDownLatch1, countDownLatch2, subList);
|
||||||
|
// 子线程交给线程池管理
|
||||||
|
pool.execute(runnable);
|
||||||
|
}
|
||||||
|
countDownLatch1.countDown();
|
||||||
|
System.out.println("开始创建索引");
|
||||||
|
// 等待所有线程都完成
|
||||||
|
countDownLatch2.await();
|
||||||
|
// 线程全部完成工作
|
||||||
|
System.out.println("所有线程都创建索引完毕");
|
||||||
|
// 释放线程池资源
|
||||||
|
pool.shutdown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writePortfolio(String id) {
|
||||||
|
writePortfolio(portfolioLuceneMapper.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writePortfolio(PortfolioLucene portfolioLucene) {
|
||||||
|
PortfolioIndexUtil.addIndex(portfolioLucene);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePortfolio(String id) {
|
||||||
|
PortfolioIndexUtil.updateIndex(portfolioLuceneMapper.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deletePortfolio(String id) {
|
||||||
|
PortfolioIndexUtil.deleteIndex(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PortfolioLucene> getAllPortfolioLucene() {
|
||||||
|
return portfolioLuceneMapper.getAllPortfolioLucene();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PortfolioDTO> getPortfoliosByIds(String[] ids) {
|
||||||
|
return portfolioLuceneMapper.getPortfoliosByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PortfolioLucene> searchPortfolio(String value) {
|
||||||
|
List<PortfolioLucene> resList = new ArrayList<>();
|
||||||
|
ExecutorService service = Executors.newCachedThreadPool();
|
||||||
|
// 定义分词器
|
||||||
|
Analyzer analyzer = new IKAnalyzer();
|
||||||
|
try {
|
||||||
|
IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(LucenePath.PORTFOLIO_PATH, service);
|
||||||
|
String[] fields = {"title", "summary"};
|
||||||
|
// 构造Query对象
|
||||||
|
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
|
||||||
|
|
||||||
|
BufferedReader in =
|
||||||
|
new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
|
||||||
|
String line = value != null ? value : in.readLine();
|
||||||
|
Query query = parser.parse(line);
|
||||||
|
// 最终被分词后添加的前缀和后缀处理器,默认是粗体<B></B>
|
||||||
|
SimpleHTMLFormatter htmlFormatter =
|
||||||
|
new SimpleHTMLFormatter("<font color=" + "\"" + "red" + "\"" + ">", "</font>");
|
||||||
|
// 高亮搜索的词添加到高亮处理器中
|
||||||
|
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
|
||||||
|
|
||||||
|
// 获取搜索的结果,指定返回document返回的个数
|
||||||
|
// TODO 默认搜索结果为显示第一页,1000 条,可以优化
|
||||||
|
TopDocs results = SearchUtil.getScoreDocsByPerPage(1, 100, searcher, query);
|
||||||
|
ScoreDoc[] hits = results.scoreDocs;
|
||||||
|
|
||||||
|
// 遍历,输出
|
||||||
|
for (ScoreDoc hit : hits) {
|
||||||
|
int id = hit.doc;
|
||||||
|
float score = hit.score;
|
||||||
|
Document hitDoc = searcher.doc(hit.doc);
|
||||||
|
// 获取到summary
|
||||||
|
String summary = hitDoc.get("summary");
|
||||||
|
// 将查询的词和搜索词匹配,匹配到添加前缀和后缀
|
||||||
|
TokenStream tokenStream =
|
||||||
|
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "summary", analyzer);
|
||||||
|
// 传入的第二个参数是查询的值
|
||||||
|
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, summary, false, 10);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (TextFragment textFragment : frag) {
|
||||||
|
if ((textFragment != null) && (textFragment.getScore() > 0)) {
|
||||||
|
// if ((frag[j] != null)) {
|
||||||
|
// 获取 summary 的值
|
||||||
|
sb.append(textFragment.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获取到title
|
||||||
|
String title = hitDoc.get("title");
|
||||||
|
TokenStream titleTokenStream =
|
||||||
|
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "title", analyzer);
|
||||||
|
TextFragment[] titleFrag =
|
||||||
|
highlighter.getBestTextFragments(titleTokenStream, title, false, 10);
|
||||||
|
StringBuilder titleValue = new StringBuilder();
|
||||||
|
for (int j = 0; j < titleFrag.length; j++) {
|
||||||
|
if ((frag[j] != null)) {
|
||||||
|
titleValue.append(titleFrag[j].toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resList.add(
|
||||||
|
PortfolioLucene.builder()
|
||||||
|
.idPortfolio(hitDoc.get("id"))
|
||||||
|
.portfolioTitle(titleValue.toString())
|
||||||
|
.portfolioDescription(sb.toString())
|
||||||
|
.score(String.valueOf(score))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
} catch (IOException | ParseException | InvalidTokenOffsetsException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
service.shutdownNow();
|
||||||
|
}
|
||||||
|
return resList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.rymcu.forest.lucene.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.rymcu.forest.lucene.model.ArticleLucene;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.document.Field;
|
||||||
|
import org.apache.lucene.document.StringField;
|
||||||
|
import org.apache.lucene.document.TextField;
|
||||||
|
import org.apache.lucene.index.IndexWriter;
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作品集索引更新工具类
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
*/
|
||||||
|
public class PortfolioIndexUtil {
|
||||||
|
|
||||||
|
/** lucene索引保存目录 */
|
||||||
|
private static final String PATH =
|
||||||
|
System.getProperty("user.dir") + StrUtil.SLASH + LucenePath.PORTFOLIO_PATH;
|
||||||
|
|
||||||
|
/** 删除所有运行中保存的索引 */
|
||||||
|
public static void deleteAllIndex() {
|
||||||
|
if (FileUtil.exist(LucenePath.PORTFOLIO_INCREMENT_INDEX_PATH)) {
|
||||||
|
FileUtil.del(LucenePath.PORTFOLIO_INCREMENT_INDEX_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addIndex(PortfolioLucene t) {
|
||||||
|
creatIndex(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateIndex(PortfolioLucene t) {
|
||||||
|
deleteIndex(t.getIdPortfolio());
|
||||||
|
creatIndex(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加或创建单个索引
|
||||||
|
*
|
||||||
|
* @param t
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static synchronized void creatIndex(PortfolioLucene t) {
|
||||||
|
System.out.println("创建单个索引");
|
||||||
|
IndexWriter writer;
|
||||||
|
try {
|
||||||
|
writer = IndexUtil.getIndexWriter(LucenePath.PORTFOLIO_INCREMENT_INDEX_PATH, false);
|
||||||
|
Document doc = new Document();
|
||||||
|
doc.add(new StringField("id", t.getIdPortfolio() + "", Field.Store.YES));
|
||||||
|
doc.add(new TextField("title", t.getPortfolioTitle(), Field.Store.YES));
|
||||||
|
doc.add(new TextField("summary", t.getPortfolioDescription(), Field.Store.YES));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除单个索引 */
|
||||||
|
public static synchronized void deleteIndex(String id) {
|
||||||
|
Arrays.stream(FileUtil.ls(PATH))
|
||||||
|
.forEach(
|
||||||
|
each -> {
|
||||||
|
if (each.isDirectory()) {
|
||||||
|
IndexWriter writer;
|
||||||
|
try {
|
||||||
|
writer = IndexUtil.getIndexWriter(each.getAbsolutePath(), false);
|
||||||
|
writer.deleteDocuments(new Term("id", id));
|
||||||
|
writer.forceMergeDeletes(); // 强制删除
|
||||||
|
writer.commit();
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,8 @@ import com.rymcu.forest.service.TagService;
|
|||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.*;
|
import com.rymcu.forest.util.*;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.text.StringEscapeUtils;
|
import org.apache.commons.text.StringEscapeUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -32,6 +34,7 @@ import java.util.*;
|
|||||||
* @author ronger
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class ArticleServiceImpl extends AbstractService<Article> implements ArticleService {
|
public class ArticleServiceImpl extends AbstractService<Article> implements ArticleService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@ -178,14 +181,17 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 草稿不更新索引
|
||||||
System.out.println("开始增加索引");
|
if ("0".equals(article.getArticleStatus())) {
|
||||||
if (isUpdate) {
|
System.out.println("开始增加索引");
|
||||||
luceneService.writeArticle(newArticle.getIdArticle().toString());
|
if (isUpdate) {
|
||||||
} else {
|
log.info("更新文章索引,id={}",newArticle.getIdArticle());
|
||||||
luceneService.updateArticle(newArticle.getIdArticle().toString());
|
luceneService.updateArticle(newArticle.getIdArticle().toString());
|
||||||
|
} else {
|
||||||
|
log.info("写入文章索引,id={}",newArticle.getIdArticle());
|
||||||
|
luceneService.writeArticle(newArticle.getIdArticle().toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tagService.saveTagArticle(newArticle, articleContentHtml);
|
tagService.saveTagArticle(newArticle, articleContentHtml);
|
||||||
|
|
||||||
if (defaultStatus.equals(newArticle.getArticleStatus())) {
|
if (defaultStatus.equals(newArticle.getArticleStatus())) {
|
||||||
|
@ -6,6 +6,8 @@ import com.rymcu.forest.core.service.AbstractService;
|
|||||||
import com.rymcu.forest.dto.*;
|
import com.rymcu.forest.dto.*;
|
||||||
import com.rymcu.forest.entity.Portfolio;
|
import com.rymcu.forest.entity.Portfolio;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
|
import com.rymcu.forest.lucene.util.PortfolioIndexUtil;
|
||||||
import com.rymcu.forest.mapper.PortfolioMapper;
|
import com.rymcu.forest.mapper.PortfolioMapper;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.PortfolioService;
|
import com.rymcu.forest.service.PortfolioService;
|
||||||
@ -74,9 +76,21 @@ public class PortfolioServiceImpl extends AbstractService<Portfolio> implements
|
|||||||
portfolio.setCreatedTime(new Date());
|
portfolio.setCreatedTime(new Date());
|
||||||
portfolio.setUpdatedTime(portfolio.getCreatedTime());
|
portfolio.setUpdatedTime(portfolio.getCreatedTime());
|
||||||
portfolioMapper.insertSelective(portfolio);
|
portfolioMapper.insertSelective(portfolio);
|
||||||
|
PortfolioIndexUtil.addIndex(
|
||||||
|
PortfolioLucene.builder()
|
||||||
|
.idPortfolio(portfolio.getIdPortfolio().toString())
|
||||||
|
.portfolioTitle(portfolio.getPortfolioTitle())
|
||||||
|
.portfolioDescription(portfolio.getPortfolioDescription())
|
||||||
|
.build());
|
||||||
} else {
|
} else {
|
||||||
portfolio.setUpdatedTime(new Date());
|
portfolio.setUpdatedTime(new Date());
|
||||||
portfolioMapper.updateByPrimaryKeySelective(portfolio);
|
portfolioMapper.updateByPrimaryKeySelective(portfolio);
|
||||||
|
PortfolioIndexUtil.updateIndex(
|
||||||
|
PortfolioLucene.builder()
|
||||||
|
.idPortfolio(portfolio.getIdPortfolio().toString())
|
||||||
|
.portfolioTitle(portfolio.getPortfolioTitle())
|
||||||
|
.portfolioDescription(portfolio.getPortfolioDescription())
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
return portfolio;
|
return portfolio;
|
||||||
}
|
}
|
||||||
@ -168,6 +182,8 @@ public class PortfolioServiceImpl extends AbstractService<Portfolio> implements
|
|||||||
Integer result = portfolioMapper.deleteByPrimaryKey(idPortfolio);
|
Integer result = portfolioMapper.deleteByPrimaryKey(idPortfolio);
|
||||||
if (result.equals(0)) {
|
if (result.equals(0)) {
|
||||||
map.put("message", "操作失败!");
|
map.put("message", "操作失败!");
|
||||||
|
}else {
|
||||||
|
PortfolioIndexUtil.deleteIndex(String.valueOf(idPortfolio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ import com.rymcu.forest.entity.Role;
|
|||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.entity.UserExtend;
|
import com.rymcu.forest.entity.UserExtend;
|
||||||
import com.rymcu.forest.jwt.service.TokenManager;
|
import com.rymcu.forest.jwt.service.TokenManager;
|
||||||
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
|
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
||||||
import com.rymcu.forest.mapper.RoleMapper;
|
import com.rymcu.forest.mapper.RoleMapper;
|
||||||
import com.rymcu.forest.mapper.UserExtendMapper;
|
import com.rymcu.forest.mapper.UserExtendMapper;
|
||||||
import com.rymcu.forest.mapper.UserMapper;
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
@ -78,6 +80,11 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
user = userMapper.findByAccount(email);
|
user = userMapper.findByAccount(email);
|
||||||
Role role = roleMapper.selectRoleByInputCode("user");
|
Role role = roleMapper.selectRoleByInputCode("user");
|
||||||
userMapper.insertUserRole(user.getIdUser(), role.getIdRole());
|
userMapper.insertUserRole(user.getIdUser(), role.getIdRole());
|
||||||
|
UserIndexUtil.addIndex(UserLucene.builder()
|
||||||
|
.idUser(user.getIdUser())
|
||||||
|
.nickname(user.getNickname())
|
||||||
|
.signature(user.getSignature())
|
||||||
|
.build());
|
||||||
map.put("message","注册成功!");
|
map.put("message","注册成功!");
|
||||||
map.put("flag",1);
|
map.put("flag",1);
|
||||||
redisService.delete(email);
|
redisService.delete(email);
|
||||||
@ -197,6 +204,11 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
}
|
}
|
||||||
Integer result = userMapper.updateUserInfo(user.getIdUser(), user.getNickname(), user.getAvatarType(),user.getAvatarUrl(),
|
Integer result = userMapper.updateUserInfo(user.getIdUser(), user.getNickname(), user.getAvatarType(),user.getAvatarUrl(),
|
||||||
user.getEmail(),user.getPhone(),user.getSignature(), user.getSex());
|
user.getEmail(),user.getPhone(),user.getSignature(), user.getSex());
|
||||||
|
UserIndexUtil.addIndex(UserLucene.builder()
|
||||||
|
.idUser(user.getIdUser())
|
||||||
|
.nickname(user.getNickname())
|
||||||
|
.signature(user.getSignature())
|
||||||
|
.build());
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
map.put("message", "操作失败!");
|
map.put("message", "操作失败!");
|
||||||
return map;
|
return map;
|
||||||
|
@ -3,6 +3,7 @@ package com.rymcu.forest.util;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.rymcu.forest.dto.ArticleDTO;
|
import com.rymcu.forest.dto.ArticleDTO;
|
||||||
import com.rymcu.forest.dto.NotificationDTO;
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
import com.rymcu.forest.dto.UserDTO;
|
import com.rymcu.forest.dto.UserDTO;
|
||||||
import com.rymcu.forest.entity.Notification;
|
import com.rymcu.forest.entity.Notification;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
@ -157,6 +158,17 @@ public class Utils {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map getPortfolioGlobalResult(PageInfo<PortfolioDTO> pageInfo) {
|
||||||
|
Map map = new HashMap(2);
|
||||||
|
map.put("portfolios", pageInfo.getList());
|
||||||
|
Map pagination = new HashMap(4);
|
||||||
|
pagination.put("pageSize",pageInfo.getPageSize());
|
||||||
|
pagination.put("total",pageInfo.getTotal());
|
||||||
|
pagination.put("currentPage",pageInfo.getPageNum());
|
||||||
|
map.put("pagination", pagination);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
public static Map getNotificationsGlobalResult(PageInfo<Notification> pageInfo) {
|
public static Map getNotificationsGlobalResult(PageInfo<Notification> pageInfo) {
|
||||||
Map map = new HashMap(2);
|
Map map = new HashMap(2);
|
||||||
map.put("notifications", pageInfo.getList());
|
map.put("notifications", pageInfo.getList());
|
||||||
|
44
src/main/java/mapper/lucene/PortfolioLuceneMapper.xml
Normal file
44
src/main/java/mapper/lucene/PortfolioLuceneMapper.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="com.rymcu.forest.lucene.mapper.PortfolioLuceneMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.rymcu.forest.lucene.model.PortfolioLucene">
|
||||||
|
<id column="id" property="idPortfolio"></id>
|
||||||
|
<result column="id" property="idPortfolio"></result>
|
||||||
|
<result column="portfolio_title" property="portfolioTitle"></result>
|
||||||
|
<result column="portfolio_description" property="portfolioDescription"></result>
|
||||||
|
</resultMap>
|
||||||
|
<resultMap id="DTOResultMap" type="com.rymcu.forest.dto.PortfolioDTO">
|
||||||
|
<result column="id" property="idPortfolio"></result>
|
||||||
|
<result column="portfolio_head_img_url" property="headImgUrl"></result>
|
||||||
|
<result column="portfolio_title" property="portfolioTitle"></result>
|
||||||
|
<result column="portfolio_author_id" property="portfolioAuthorId"></result>
|
||||||
|
<result column="portfolio_description" property="portfolioDescription"></result>
|
||||||
|
<result column="updated_time" property="updatedTime"></result>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="getAllPortfolioLucene" resultMap="BaseResultMap">
|
||||||
|
SELECT id, portfolio_title, portfolio_description
|
||||||
|
FROM forest_portfolio
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getPortfoliosByIds" resultMap="DTOResultMap">
|
||||||
|
select id, portfolio_head_img_url, portfolio_author_id, portfolio_description, updated_time from forest_portfolio where
|
||||||
|
id in
|
||||||
|
<foreach collection="ids" item="id" index="index"
|
||||||
|
open="(" close=")" separator=",">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
order by
|
||||||
|
field(id
|
||||||
|
<foreach collection="ids" item="id" index="index"
|
||||||
|
open="," close=")" separator=",">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getById" resultMap="BaseResultMap">
|
||||||
|
SELECT id, portfolio_title, portfolio_description
|
||||||
|
FROM forest_portfolio
|
||||||
|
where id = #{id};
|
||||||
|
</select>
|
||||||
|
</mapper>
|
Loading…
Reference in New Issue
Block a user