用户搜索

This commit is contained in:
Suwen 2021-04-17 11:25:02 +08:00
parent 6ccd66fd2f
commit 1a0571a7e8
11 changed files with 116 additions and 67 deletions

View File

@ -5,7 +5,9 @@ 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.UserDTO;
import com.rymcu.forest.lucene.model.ArticleLucene; import com.rymcu.forest.lucene.model.ArticleLucene;
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.UserDicService; import com.rymcu.forest.lucene.service.UserDicService;
import com.rymcu.forest.lucene.service.UserLuceneService; import com.rymcu.forest.lucene.service.UserLuceneService;
@ -36,7 +38,7 @@ public class LuceneSearchController {
@Resource private UserLuceneService userLuceneService; @Resource private UserLuceneService userLuceneService;
@Resource private UserDicService dicService; @Resource private UserDicService dicService;
@PostConstruct // @PostConstruct
public void createIndex() { public void createIndex() {
// 删除系统运行时保存的索引重新创建索引 // 删除系统运行时保存的索引重新创建索引
ArticleIndexUtil.deleteAllIndex(); ArticleIndexUtil.deleteAllIndex();
@ -46,7 +48,7 @@ public class LuceneSearchController {
CompletableFuture.supplyAsync( CompletableFuture.supplyAsync(
() -> { () -> {
System.out.println(">>>>>>>>> 开始创建索引 <<<<<<<<<<<"); System.out.println(">>>>>>>>> 开始创建索引 <<<<<<<<<<<");
// luceneService.writeArticle(luceneService.getAllArticleLucene()); luceneService.writeArticle(luceneService.getAllArticleLucene());
userLuceneService.writeUser(userLuceneService.getAllUserLucene()); userLuceneService.writeUser(userLuceneService.getAllUserLucene());
System.out.println(">>>>>>>>> 索引创建完毕 <<<<<<<<<<<"); System.out.println(">>>>>>>>> 索引创建完毕 <<<<<<<<<<<");
System.out.println("加载用户配置的自定义扩展词典到主词库表"); System.out.println("加载用户配置的自定义扩展词典到主词库表");
@ -68,7 +70,7 @@ public class LuceneSearchController {
* @return * @return
*/ */
@GetMapping("/searchArticle/{q}") @GetMapping("/searchArticle/{q}")
public GlobalResult searchArticle( public GlobalResult<?> searchArticle(
@PathVariable String q, @PathVariable String q,
@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) { @RequestParam(defaultValue = "10") Integer pageSize) {
@ -102,4 +104,46 @@ public class LuceneSearchController {
PageInfo<ArticleDTO> pageInfo = new PageInfo<>(page); PageInfo<ArticleDTO> pageInfo = new PageInfo<>(page);
return GlobalResultGenerator.genSuccessResult(Utils.getArticlesGlobalResult(pageInfo)); return GlobalResultGenerator.genSuccessResult(Utils.getArticlesGlobalResult(pageInfo));
} }
/**
* 搜索实现高亮
*
* @param q
* @return
*/
@GetMapping("/searchUser/{q}")
public GlobalResult<?> searchUser(
@PathVariable String q,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
// 找出相关文章相关度倒序
List<UserLucene> resList = userLuceneService.searchUser(q);
// 分页组装文章详情
int total = resList.size();
if (total == 0) {
return GlobalResultGenerator.genSuccessResult("未找到相关用户");
}
Page<UserDTO> page = new Page<>(pageNum, pageSize);
page.setTotal(total);
int startIndex = (pageNum - 1) * pageSize;
int endIndex = Math.min(startIndex + pageSize, total);
// 分割子列表
List<UserLucene> subList = resList.subList(startIndex, endIndex);
Integer[] ids = subList.stream().map(UserLucene::getIdUser).toArray(Integer[]::new);
List<UserDTO> userDTOList = userLuceneService.getUsersByIds(ids);
UserDTO temp;
// 写入文章关键词信息
for (int i = 0; i < userDTOList.size(); i++) {
temp = userDTOList.get(i);
temp.setNickname(subList.get(i).getNickname());
if (subList.get(i).getSignature().length() > 10) {
// 内容中命中太少则不替换
temp.setSignature(subList.get(i).getSignature());
}
userDTOList.set(i, temp);
}
page.addAll(userDTOList);
PageInfo<UserDTO> pageInfo = new PageInfo<>(page);
return GlobalResultGenerator.genSuccessResult(Utils.getUserGlobalResult(pageInfo));
}
} }

View File

@ -7,10 +7,7 @@ import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -22,19 +19,6 @@ import java.util.concurrent.CountDownLatch;
*/ */
public class UserBeanIndex extends BaseIndex<UserLucene> { public class UserBeanIndex extends BaseIndex<UserLucene> {
public UserBeanIndex(
String parentIndexPath,int subIndex) {
super(parentIndexPath, subIndex);
}
public UserBeanIndex(
IndexWriter writer,
CountDownLatch countDownLatch1,
CountDownLatch countDownLatch2,
List<UserLucene> list) {
super(writer, countDownLatch1, countDownLatch2, list);
}
public UserBeanIndex( public UserBeanIndex(
String parentIndexPath, String parentIndexPath,
int subIndex, int subIndex,
@ -60,14 +44,4 @@ public class UserBeanIndex extends BaseIndex<UserLucene> {
writer.updateDocument(new Term("id", user.getIdUser() + ""), doc); writer.updateDocument(new Term("id", user.getIdUser() + ""), doc);
} }
} }
public void indexDoc(UserLucene t) throws Exception {
indexDoc(getWriter(),t);
}
@Override
public void deleteDoc( String id) throws IOException {
Query query = new TermQuery(new Term("id", id));
getWriter().deleteDocuments(query);
}
} }

View File

@ -29,7 +29,7 @@ public interface UserLuceneMapper {
* @param ids 用户id(半角逗号分隔) * @param ids 用户id(半角逗号分隔)
* @return * @return
*/ */
List<UserDTO> getUsersByIds(@Param("ids") String[] ids); List<UserDTO> getUsersByIds(@Param("ids") Integer[] ids);
/** /**
* 加载 UserLucene * 加载 UserLucene

View File

@ -70,5 +70,5 @@ public interface UserLuceneService {
* @param ids 用户id(半角逗号分隔) * @param ids 用户id(半角逗号分隔)
* @return * @return
*/ */
List<UserDTO> getUsersByIds(String[] ids); List<UserDTO> getUsersByIds(Integer[] ids);
} }

View File

@ -7,6 +7,7 @@ import com.rymcu.forest.lucene.mapper.ArticleLuceneMapper;
import com.rymcu.forest.lucene.model.ArticleLucene; import com.rymcu.forest.lucene.model.ArticleLucene;
import com.rymcu.forest.lucene.service.LuceneService; import com.rymcu.forest.lucene.service.LuceneService;
import com.rymcu.forest.lucene.util.ArticleIndexUtil; import com.rymcu.forest.lucene.util.ArticleIndexUtil;
import com.rymcu.forest.lucene.util.LucenePath;
import com.rymcu.forest.lucene.util.SearchUtil; import com.rymcu.forest.lucene.util.SearchUtil;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
@ -26,9 +27,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -44,9 +43,6 @@ public class LuceneServiceImpl implements LuceneService {
@Resource private ArticleLuceneMapper luceneMapper; @Resource private ArticleLuceneMapper luceneMapper;
/** Lucene索引文件路径 */
private final String indexPath = "lucene/index";
/** /**
* 将文章的数据解析为一个个关键字词存储到索引文件中 * 将文章的数据解析为一个个关键字词存储到索引文件中
* *
@ -67,7 +63,8 @@ public class LuceneServiceImpl implements LuceneService {
int end = Math.min((i + 1) * perThreadCount, totalCount); int end = Math.min((i + 1) * perThreadCount, totalCount);
List<ArticleLucene> subList = list.subList(start, end); List<ArticleLucene> subList = list.subList(start, end);
Runnable runnable = Runnable runnable =
new ArticleBeanIndex(indexPath, i, countDownLatch1, countDownLatch2, subList); new ArticleBeanIndex(
LucenePath.ARTICLE_INDEX_PATH, i, countDownLatch1, countDownLatch2, subList);
// 子线程交给线程池管理 // 子线程交给线程池管理
pool.execute(runnable); pool.execute(runnable);
} }
@ -118,7 +115,8 @@ public class LuceneServiceImpl implements LuceneService {
// 定义分词器 // 定义分词器
Analyzer analyzer = new IKAnalyzer(); Analyzer analyzer = new IKAnalyzer();
try { try {
IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(indexPath, service); IndexSearcher searcher =
SearchUtil.getIndexSearcherByParentPath(LucenePath.ARTICLE_INDEX_PATH, service);
String[] fields = {"title", "summary"}; String[] fields = {"title", "summary"};
// 构造Query对象 // 构造Query对象
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
@ -143,9 +141,6 @@ public class LuceneServiceImpl implements LuceneService {
int id = hit.doc; int id = hit.doc;
float score = hit.score; float score = hit.score;
Document hitDoc = searcher.doc(hit.doc); Document hitDoc = searcher.doc(hit.doc);
Map<String, String> map = new HashMap<>();
map.put("id", hitDoc.get("id"));
// 获取到summary // 获取到summary
String name = hitDoc.get("summary"); String name = hitDoc.get("summary");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀 // 将查询的词和搜索词匹配匹配到添加前缀和后缀
@ -158,7 +153,7 @@ public class LuceneServiceImpl implements LuceneService {
if ((textFragment != null) && (textFragment.getScore() > 0)) { if ((textFragment != null) && (textFragment.getScore() > 0)) {
// if ((frag[j] != null)) { // if ((frag[j] != null)) {
// 获取 summary 的值 // 获取 summary 的值
baikeValue.append(textFragment.toString()); baikeValue.append(textFragment);
} }
} }
@ -183,7 +178,6 @@ public class LuceneServiceImpl implements LuceneService {
.build()); .build());
} }
} catch (IOException | ParseException | InvalidTokenOffsetsException e) { } catch (IOException | ParseException | InvalidTokenOffsetsException e) {
System.out.println(e.getMessage());
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
service.shutdownNow(); service.shutdownNow();

View File

@ -6,6 +6,7 @@ import com.rymcu.forest.lucene.lucene.IKAnalyzer;
import com.rymcu.forest.lucene.mapper.UserLuceneMapper; import com.rymcu.forest.lucene.mapper.UserLuceneMapper;
import com.rymcu.forest.lucene.model.UserLucene; import com.rymcu.forest.lucene.model.UserLucene;
import com.rymcu.forest.lucene.service.UserLuceneService; import com.rymcu.forest.lucene.service.UserLuceneService;
import com.rymcu.forest.lucene.util.LucenePath;
import com.rymcu.forest.lucene.util.UserIndexUtil; import com.rymcu.forest.lucene.util.UserIndexUtil;
import com.rymcu.forest.lucene.util.SearchUtil; import com.rymcu.forest.lucene.util.SearchUtil;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
@ -26,9 +27,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -44,8 +43,6 @@ public class UserLuceneServiceImpl implements UserLuceneService {
@Resource private UserLuceneMapper userLuceneMapper; @Resource private UserLuceneMapper userLuceneMapper;
/** Lucene索引文件路径 */
private final String indexPath = "lucene/index";
/** /**
* 将文章的数据解析为一个个关键字词存储到索引文件中 * 将文章的数据解析为一个个关键字词存储到索引文件中
@ -67,7 +64,7 @@ public class UserLuceneServiceImpl implements UserLuceneService {
int end = Math.min((i + 1) * perThreadCount, totalCount); int end = Math.min((i + 1) * perThreadCount, totalCount);
List<UserLucene> subList = list.subList(start, end); List<UserLucene> subList = list.subList(start, end);
Runnable runnable = Runnable runnable =
new UserBeanIndex(indexPath, i, countDownLatch1, countDownLatch2, subList); new UserBeanIndex(LucenePath.USER_PATH, i, countDownLatch1, countDownLatch2, subList);
// 子线程交给线程池管理 // 子线程交给线程池管理
pool.execute(runnable); pool.execute(runnable);
} }
@ -111,7 +108,7 @@ public class UserLuceneServiceImpl implements UserLuceneService {
// 定义分词器 // 定义分词器
Analyzer analyzer = new IKAnalyzer(); Analyzer analyzer = new IKAnalyzer();
try { try {
IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(indexPath, service); IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(LucenePath.USER_PATH, service);
String[] fields = {"nickname", "signature"}; String[] fields = {"nickname", "signature"};
// 构造Query对象 // 构造Query对象
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
@ -136,9 +133,6 @@ public class UserLuceneServiceImpl implements UserLuceneService {
int id = hit.doc; int id = hit.doc;
float score = hit.score; float score = hit.score;
Document hitDoc = searcher.doc(hit.doc); Document hitDoc = searcher.doc(hit.doc);
Map<String, String> map = new HashMap<>();
map.put("id", hitDoc.get("id"));
// 获取到summary // 获取到summary
String name = hitDoc.get("signature"); String name = hitDoc.get("signature");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀 // 将查询的词和搜索词匹配匹配到添加前缀和后缀
@ -154,7 +148,6 @@ public class UserLuceneServiceImpl implements UserLuceneService {
baikeValue.append(textFragment.toString()); baikeValue.append(textFragment.toString());
} }
} }
// 获取到title // 获取到title
String title = hitDoc.get("nickname"); String title = hitDoc.get("nickname");
TokenStream titleTokenStream = TokenStream titleTokenStream =
@ -190,7 +183,7 @@ public class UserLuceneServiceImpl implements UserLuceneService {
} }
@Override @Override
public List<UserDTO> getUsersByIds(String[] ids) { public List<UserDTO> getUsersByIds(Integer[] ids) {
return userLuceneMapper.getUsersByIds(ids); return userLuceneMapper.getUsersByIds(ids);
} }
} }

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.lucene.util; package com.rymcu.forest.lucene.util;
import cn.hutool.core.io.FileUtil; 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.ArticleLucene;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
@ -20,16 +21,13 @@ import java.util.Arrays;
public class ArticleIndexUtil { public class ArticleIndexUtil {
/** lucene索引保存目录 */ /** lucene索引保存目录 */
private static final String PATH = System.getProperty("user.dir") + "/lucene/index"; private static final String PATH =
System.getProperty("user.dir") + StrUtil.SLASH + LucenePath.ARTICLE_INDEX_PATH;
/** 系统运行时索引保存目录 */
private static final String INDEX_PATH =
System.getProperty("user.dir") + "/lucene/index/index777";
/** 删除所有运行中保存的索引 */ /** 删除所有运行中保存的索引 */
public static void deleteAllIndex() { public static void deleteAllIndex() {
if (FileUtil.exist(INDEX_PATH)) { if (FileUtil.exist(LucenePath.ARTICLE_INCREMENT_INDEX_PATH)) {
FileUtil.del(INDEX_PATH); FileUtil.del(LucenePath.ARTICLE_INCREMENT_INDEX_PATH);
} }
} }
@ -52,7 +50,7 @@ public class ArticleIndexUtil {
System.out.println("创建单个索引"); System.out.println("创建单个索引");
IndexWriter writer; IndexWriter writer;
try { try {
writer = IndexUtil.getIndexWriter(INDEX_PATH, false); writer = IndexUtil.getIndexWriter(LucenePath.ARTICLE_INCREMENT_INDEX_PATH, false);
Document doc = new Document(); Document doc = new Document();
doc.add(new StringField("id", t.getIdArticle() + "", Field.Store.YES)); doc.add(new StringField("id", t.getIdArticle() + "", Field.Store.YES));
doc.add(new TextField("title", t.getArticleTitle(), Field.Store.YES)); doc.add(new TextField("title", t.getArticleTitle(), Field.Store.YES));

View File

@ -0,0 +1,33 @@
package com.rymcu.forest.lucene.util;
/**
* LucenePath lucene索引地址常量
*
* @author Suwen
*/
public final class LucenePath {
/** lucene 目录 */
public static final String INDEX_PATH = "lucene/index";
/** 文章 lucene 目录 */
public static final String ARTICLE_INDEX_PATH = INDEX_PATH + "/article";
/** 文章增量 lucene 目录 */
public static final String ARTICLE_INCREMENT_INDEX_PATH =
System.getProperty("user.dir") + ARTICLE_INDEX_PATH + "/index777";
/** 用户 lucene 目录 */
public static final String USER_PATH = INDEX_PATH + "/user";
/** 用户增量 lucene 目录 */
public static final String USER_INCREMENT_INDEX_PATH =
System.getProperty("user.dir") + USER_PATH + "/index777";
/** 作品集 lucene 目录 */
public static final String PORTFOLIO_PATH = INDEX_PATH + "/portfolio";
/** 作品集增量 lucene 目录 */
public static final String PORTFOLIO_INCREMENT_INDEX_PATH =
System.getProperty("user.dir") + PORTFOLIO_PATH + "/index777";
}

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.lucene.util; package com.rymcu.forest.lucene.util;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.rymcu.forest.lucene.model.UserLucene; import com.rymcu.forest.lucene.model.UserLucene;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
@ -12,6 +13,7 @@ import org.apache.lucene.index.Term;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
/** /**
* 用户索引更新工具类 * 用户索引更新工具类
* *
@ -20,11 +22,10 @@ import java.util.Arrays;
public class UserIndexUtil { public class UserIndexUtil {
/** lucene索引保存目录 */ /** lucene索引保存目录 */
private static final String PATH = System.getProperty("user.dir") + "/lucene/index"; private static final String PATH = System.getProperty("user.dir") + StrUtil.SLASH + LucenePath.USER_PATH;
/** 系统运行时索引保存目录 */ /** 系统运行时索引保存目录 */
private static final String INDEX_PATH = private static final String INDEX_PATH = LucenePath.USER_INCREMENT_INDEX_PATH;
System.getProperty("user.dir") + "/lucene/index/index777";
/** 删除所有运行中保存的索引 */ /** 删除所有运行中保存的索引 */
public static void deleteAllIndex() { public static void deleteAllIndex() {

View File

@ -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.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;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
@ -145,6 +146,17 @@ public class Utils {
return map; return map;
} }
public static Map getUserGlobalResult(PageInfo<UserDTO> pageInfo) {
Map map = new HashMap(2);
map.put("users", 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());

View File

@ -20,8 +20,8 @@
</select> </select>
<select id="getUsersByIds" resultMap="DTOResultMapper"> <select id="getUsersByIds" resultMap="DTOResultMapper">
select id, nickname, avatar_type, avatar_url, account, signature from forest_user where nickname = #{nickname} select id, nickname, avatar_type, avatar_url, account, signature from forest_user where
and id in id in
<foreach collection="ids" item="id" index="index" <foreach collection="ids" item="id" index="index"
open="(" close=")" separator=","> open="(" close=")" separator=",">
#{id} #{id}