其实这个搜索的功能反倒跟redis没啥关系了,所以我也没归类在redis里。基于es的搜索也不无非是增删改查,先简单说一下项目里用到的这两个功能和api。后续我会详细学习
elasticsearch
es是一个搜索器,具体怎么搜的我不知道(笑)。目前的理解是在新增blog的时候同时把这个对象给es服务器,它通过索引的方式进行缓存。后续查找的时候就可以根据field,也就是字段名来指定匹配位置。
比如这里要搜索文章标题的关键字,就用title;如果是内容的,就用content。经过我的实验发现黑马给的分词器只能检索中文,我想要搜素字母“s”,都搜不到。
项目里的应用也比较简单,就是上述的关键字搜索,然后返回前端的时候要标红,这个步骤是通过在前后加font标签完成的。
首先是配置:
这里用到的对象是RestHighLevelClient,我们只需要配置端口号和ip就可以了,这个客户端会使用es的restful端口进行增删改查。
我们对其的增删改查操作就跟redistemplate一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Configuration public class ElasticSearchConfig { @Value("${elasticsearch.host}") private String host; @Value("${elasticsearch.port}") private Integer port;
@Bean public RestHighLevelClient restHighLevelClient() { return new RestHighLevelClient( RestClient.builder( new HttpHost(host, port, "http"))); } }
|
用这个RestHighLevelClient,传输的是一个httprequest,返回的是response。思路是创建一个request,查询标题和内容两个方面的关键词。
返回以后进行一个转换,返回的加上颜色标签的hits是一个数组,需要转换成字符串。最后向前端返回这个字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| @Override public Result searchBlog(QueryBlogDto dto) throws IOException { if (dto == null){ return Result.fail("输入为空"); } if (dto.getKeyWord() == null || dto.getKeyWord().isEmpty()){ return Result.fail("输入关键词为空"); } insertSearchHistory(dto.getKeyWord());
SearchRequest searchRequest = new SearchRequest("hmdp_blogs"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder builder = QueryBuilders.boolQuery();
QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getKeyWord()).field("content").field("title").defaultOperator(Operator.OR); builder.must(queryStringQueryBuilder);
HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); highlightBuilder.field("content"); highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>"); highlightBuilder.postTags("</font>"); searchSourceBuilder.highlighter(highlightBuilder);
searchSourceBuilder.query(builder); searchRequest.source(searchSourceBuilder);
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits(); List<Map> list = new ArrayList<>(); for (SearchHit hit : hits){ String json = hit.getSourceAsString(); Map map = JSONUtil.toBean(json, Map.class); Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if (highlightFields != null){ HighlightField title = highlightFields.get("title"); HighlightField content = highlightFields.get("content"); if (title != null){ Text[] titleFragments = title.getFragments(); String collect = Arrays.stream(titleFragments).map((value) -> value.toString()).collect(Collectors.joining()); map.put("title",collect); } if (content != null){ Text[] contentFragments = content.getFragments(); String collect = Arrays.stream(contentFragments).map((value) -> value.toString()).collect(Collectors.joining()); map.put("content",collect); } }
list.add(map); } return Result.ok(list); }
|
mongodb
登录用户的查询记录很多而且变化频繁。需要用非关系型数据库来存储。(其实我个人觉得没必要存在服务器上,这些缓存应该都是在客户端上保留的)
mongodb的配置比较简单,甚至不用写配置类。直接看使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
@Async public void insertSearchHistory(String keyWord){
Long userID = UserHolder.getUser().getId(); Query query = Query.query(Criteria.where("userId").is(userID).and("keyWord").is(keyWord)); QueryBlogDto searchHistory = mongoTemplate.findOne(query, QueryBlogDto.class); if (searchHistory != null){ searchHistory.setCreateTime(new Date()); } QueryBlogDto dto = new QueryBlogDto(); dto.setCreateTime(new Date()); dto.setUserId(userID); dto.setKeyWord(keyWord);
Query query1 = Query.query(Criteria.where("userId").is(userID)) .with(Sort.by(Sort.Direction.DESC,"createTime")); List<QueryBlogDto> dtos = mongoTemplate.find(query1, QueryBlogDto.class); if (dtos.size() < 10){ mongoTemplate.save(dto); } else { QueryBlogDto last = dtos.get(dtos.size() - 1); mongoTemplate.findAndReplace(Query.query(Criteria.where("keyWord").is(last.getKeyWord())),dto); }
}
|
值得注意的是这里使用了@Async,gpt给我的答案是这个跟你新开一个线程没有区别,但是注意要在启动类上enable。这里query更像lambdaQueryWrapper那种。具体的增删改查语法以后再学。