使用Elasticsearch查询历史热点消息,搜索的内容包括:根据关键词搜索,可以多个关键词;根据热点标题查找历史热度值变化。
搜索框DTO
用来接收前端传递的搜索框内容。
@Data
public class SearchKeywords {
@NotEmpty
private String keywords;
@NotEmpty
private String relation;
@NotEmpty
@NotNull
private String type;
}
定义SeachData
接收从ES返回的数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SearchData {
private String titleText;
private String titleKeyword;
private Integer rank;
private Integer hotNumber;
private String timestamp;
private Integer uId;
}
服务接口
public interface SearchService {
/**
* 根据标题查找历史信息
* @param title 标题
* @param type 哪个表
* @return 历史信息
*/
public List<SearchData> searchByName(String title, String type);
/**
* 根据关键词查找
* @param keyword 关键词
* @param type 表名
* @param relation 关键词之间的关系
* @return 历史信息
*/
public List<SearchData> searchByKeyword(String keyword, String type, String relation);
/**
* 根据uId查找内容详情
* @param type 热榜名称
* @param uId 唯一键
* @return 详情
*/
public List<SearchDetail> searchDetail(String type, int uId);
}
包括两个查询内容,还包含了一个根据uId查找历史消息,uId在数据库中建立了索引。
服务实现
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private EsUtil esUtil;
@Autowired
private SearchDetailMapper searchDetailMapper;
@Override
public List<SearchData> searchByName(String title, String type) {
// 创建bool query
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
// 查找title_keyword中有查找的关键词
boolQueryBuilder.filter(QueryBuilders.termQuery("title_keyword", title));
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(boolQueryBuilder);
// 根据时间倒序
builder.sort("timestamp", SortOrder.ASC);
// 取前30个
builder.size(30);
return esUtil.search(type+"_data", builder, SearchData.class);
}
@Override
public List<SearchData> searchByKeyword(String keyword, String type, String relation) {
// 创建simple query string
SimpleQueryStringBuilder simpleQueryStringBuilder = new SimpleQueryStringBuilder(keyword);
// 根据title_text匹配
simpleQueryStringBuilder.field("title_text");
// 关键词关系有和与或
if("OR".equals(relation) || "or".equals(relation)){
simpleQueryStringBuilder.defaultOperator(Operator.OR);
}else {
simpleQueryStringBuilder.defaultOperator(Operator.AND);
}
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(simpleQueryStringBuilder);
builder.sort("timestamp", SortOrder.DESC);
// 找出历史排序最高的一条
CollapseBuilder collapseBuilder = new CollapseBuilder("title_keyword");
InnerHitBuilder innerHitBuilder = new InnerHitBuilder("top_hot");
innerHitBuilder.setSize(1);
SortBuilder sortBuilder = SortBuilders.fieldSort("hot_number").order(SortOrder.DESC);
innerHitBuilder.addSort(sortBuilder);
collapseBuilder.setInnerHits(innerHitBuilder);
builder.collapse(collapseBuilder);
builder.size(30);
return esUtil.search(type+"_data", builder, SearchData.class);
}
@Override
public List<SearchDetail> searchDetail(String type, int uId) {
return searchDetailMapper.queryDetail(type, uId);
}
}
EsUtil
ES实现工具类
@Component
public class EsUtil {
@Value("${es.host}")
private String host;
@Value("${es.port}")
private int port;
@Value("${es.scheme}")
private String scheme;
private static RestHighLevelClient client = null;
@PostConstruct
public void init() {
try {
if (client != null) {
client.close();
}
client = new RestHighLevelClient(RestClient.builder(new HttpHost(host, port, scheme)));
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
/**
* Description: 搜索
*
* @param index index
* @param builder 查询参数
* @param c 结果类对象
* @return java.util.ArrayList
* @author fanxb
* @date 2019/7/25 13:46
*/
public <T> List<T> search(String index, SearchSourceBuilder builder, Class<T> c) {
SearchRequest request = new SearchRequest(index);
request.source(builder);
try {
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
List<T> res = new ArrayList<>(hits.length);
for (SearchHit hit : hits) {
res.add(JSON.parseObject(hit.getSourceAsString(), c));
}
return res;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Controller
@Controller
@RequestMapping("/search")
public class searchController {
private static Logger logger = LoggerFactory.getLogger(IndexController.class);
@Resource
SearchService searchService;
@RequestMapping(value = "/searchTitle", method = RequestMethod.GET)
public String searchTitle(@RequestParam(value = "title") String title, @RequestParam(value = "type") String type ,ModelMap map){
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = userDetails.getUsername();
logger.info("用户名=" + name + "&行为=历史热度查看:" + title + "|" + type);
map.addAttribute("titleData", title);
List<String> time = new ArrayList<>();
List<Integer> hotNumber = new ArrayList<>();
List<SearchData> hotSpots = searchService.searchByName(title, type);
for (SearchData hotSpot: hotSpots){
time.add(hotSpot.getTimestamp().replace('T', ' '));
hotNumber.add(hotSpot.getHotNumber());
}
map.addAttribute("timeData", time);
map.addAttribute("hotNumberData", hotNumber);
return "search/searchTitle";
}
@RequestMapping(value = "/searchDetail", method = RequestMethod.GET)
@ResponseBody
public SearchDetail searchDetail(@RequestParam(value = "uId") int uId, @RequestParam(value = "type") String type ,ModelMap map){
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = userDetails.getUsername();
logger.info("用户名=" + name + "&行为=详情查看:" + uId + "|" + type);
List<SearchDetail> searchDetails = searchService.searchDetail(type, uId);
return searchDetails.get(0);
}
@PostMapping(value = "/searchKeywords")
public String searchKeywords(@ModelAttribute("searchKeywords") @Valid SearchKeywords searchKeywords, BindingResult result, Model model){
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = userDetails.getUsername();
logger.info("用户名=" + name + "&行为=关键词查找:" + searchKeywords.getKeywords() + "|" + searchKeywords.getType() + "|" + searchKeywords.getRelation());
if (result.hasErrors()){
return "search/searchKeywords";
}
String type = getTypeName(searchKeywords.getType());
List<SearchData> searchHotSpotData = searchService.searchByKeyword(searchKeywords.getKeywords(), type, searchKeywords.getRelation());
model.addAttribute("searchHotSpotData", searchHotSpotData);
model.addAttribute("dataType", type);
return "search/searchKeywords";
}
@GetMapping(value = "/searchKeywords")
public String toSearchKeywords(Model model){
model.addAttribute("searchKeywords", new SearchKeywords());
return "search/searchKeywords";
}
private String getTypeName(String type) {
switch (type){
case "微博":
return "weibo";
case "牛客":
return "niuke";
case "虎扑":
return "hupu";
case "掘金":
return "juejin";
default:
return "weibo";
}
}
}
网友评论