功能
创建索引和映射
使用postman添加映射和查询
查询所有的文章信息,批量导入到es索引库中
server : port : 9999
spring : application : name : es- articledatasource : driver-class-name : com.mysql.jdbc.Driverurl : jdbc: mysql: //localhost: 3306/leadnews_article? useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username : rootpassword : root
mybatis-plus : mapper-locations : classpath*:mapper/*.xml type-aliases-package : com.heima.model.article.pojos
elasticsearch : host : 192.168.200.130port : 9200
导入到es索引库
@Test
public void init ( ) throws Exception { List < SearchArticleVo > searchArticleVos = apArticleMapper. loadArticleList ( ) ; BulkRequest bulkRequest = new BulkRequest ( "app_info_article" ) ; for ( SearchArticleVo searchArticleVo : searchArticleVos) { IndexRequest indexRequest = new IndexRequest ( ) . id ( searchArticleVo. getId ( ) . toString ( ) ) . source ( JSON . toJSONString ( searchArticleVo) , XContentType . JSON ) ; bulkRequest. add ( indexRequest) ; } restHighLevelClient. bulk ( bulkRequest, RequestOptions . DEFAULT ) ;
}
需求说明
搜索接口定义
UserSearchDto
实现步骤
文章搜索服务实现
@Override public ResponseResult search ( UserSearchDto dto) throws IOException { if ( dto == null || StringUtils . isBlank ( dto. getSearchWords ( ) ) ) { return ResponseResult . errorResult ( AppHttpCodeEnum . PARAM_INVALID ) ; } ApUser user = AppThreadLocalUtil . getUser ( ) ; if ( user != null && dto. getFromIndex ( ) == 0 ) { apUserSearchService. insert ( dto. getSearchWords ( ) , user. getId ( ) ) ; } SearchRequest searchRequest = new SearchRequest ( "app_info_article" ) ; SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ( ) ; BoolQueryBuilder boolQueryBuilder = QueryBuilders . boolQuery ( ) ; QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders . queryStringQuery ( dto. getSearchWords ( ) ) . field ( "title" ) . field ( "content" ) . defaultOperator ( Operator . OR ) ; boolQueryBuilder. must ( queryStringQueryBuilder) ; RangeQueryBuilder rangeQueryBuilder = QueryBuilders . rangeQuery ( "publishTime" ) . lt ( dto. getMinBehotTime ( ) . getTime ( ) ) ; boolQueryBuilder. filter ( rangeQueryBuilder) ; searchSourceBuilder. from ( 0 ) ; searchSourceBuilder. size ( dto. getPageSize ( ) ) ; searchSourceBuilder. sort ( "publishTime" , SortOrder . DESC ) ; HighlightBuilder highlightBuilder = new HighlightBuilder ( ) ; highlightBuilder. field ( "title" ) ; highlightBuilder. preTags ( "<font style='color: red; font-size: inherit;'>" ) ; highlightBuilder. postTags ( "</font>" ) ; searchSourceBuilder. highlighter ( highlightBuilder) ; searchSourceBuilder. query ( boolQueryBuilder) ; searchRequest. source ( searchSourceBuilder) ; SearchResponse searchResponse = restHighLevelClient. search ( searchRequest, RequestOptions . DEFAULT ) ; List < Map > list = new ArrayList < > ( ) ; SearchHit [ ] hits = searchResponse. getHits ( ) . getHits ( ) ; for ( SearchHit hit : hits) { String json = hit. getSourceAsString ( ) ; Map map = JSON . parseObject ( json, Map . class ) ; if ( hit. getHighlightFields ( ) != null && hit. getHighlightFields ( ) . size ( ) > 0 ) { Text [ ] titles = hit. getHighlightFields ( ) . get ( "title" ) . getFragments ( ) ; String title = StringUtils . join ( titles) ; map. put ( "h_title" , title) ; } else { map. put ( "h_title" , map. get ( "title" ) ) ; } list. add ( map) ; } return ResponseResult . okResult ( list) ; }
新增文章同步添加索引
private void createArticleEsIndex ( ApArticle apArticle, String content, String path) { SearchArticleVo vo = new SearchArticleVo ( ) ; BeanUtils . copyProperties ( apArticle, vo) ; vo. setContent ( content) ; vo. setStaticUrl ( path) ; kafkaTemplate. send ( ArticleConstants . ARTICLE_ES_SYNC_TOPIC , JSON . toJSONString ( vo) ) ;
}
同步文章数据
@Component
@Slf4j
public class SyncArticleListener { @Autowired private RestHighLevelClient restHighLevelClient; @KafkaListener ( topics = ArticleConstants . ARTICLE_ES_SYNC_TOPIC ) public void onMessage ( String message) { if ( StringUtils . isNotBlank ( message) ) { SearchArticleVo searchArticleVo = JSON . parseObject ( message, SearchArticleVo . class ) ; IndexRequest indexRequest = new IndexRequest ( "app_info_article" ) ; indexRequest. id ( searchArticleVo. getId ( ) . toString ( ) ) ; indexRequest. source ( message, XContentType . JSON ) ; try { restHighLevelClient. index ( indexRequest, RequestOptions . DEFAULT ) ; } catch ( IOException e) { log. error ( "sync es error = {}" , e. getMessage ( ) , e) ; } } }
}
搜索记录
需求说明
数据存储说明
保存搜索记录-实现思路
用户搜索服务实现
保存用户搜索历史记录
@Override @Async public void insert ( String keyword, Integer userId) { Query query = Query . query ( Criteria . where ( "userId" ) . is ( userId) . and ( "keyword" ) . is ( keyword) ) ; ApUserSearch apUserSearch = mongoTemplate. findOne ( query, ApUserSearch . class ) ; if ( apUserSearch != null ) { apUserSearch. setCreatedTime ( new Date ( ) ) ; mongoTemplate. save ( apUserSearch) ; return ; } apUserSearch = new ApUserSearch ( ) ; apUserSearch. setUserId ( userId) ; apUserSearch. setKeyword ( keyword) ; apUserSearch. setCreatedTime ( new Date ( ) ) ; Query query1 = Query . query ( Criteria . where ( "userId" ) . is ( userId) ) ; query1. with ( Sort . by ( Sort. Direction . DESC , "createdTime" ) ) ; List < ApUserSearch > apUserSearchList = mongoTemplate. find ( query1, ApUserSearch . class ) ; if ( apUserSearchList == null || apUserSearchList. size ( ) < 10 ) { mongoTemplate. save ( apUserSearch) ; } else { ApUserSearch lastUserSearch = apUserSearchList. get ( apUserSearchList. size ( ) - 1 ) ; mongoTemplate. findAndReplace ( Query . query ( Criteria . where ( "id" ) . is ( lastUserSearch. getId ( ) ) ) , apUserSearch) ; } }
查询用户搜索历史记录
@Override public ResponseResult findUserSearch ( ) { ApUser user = AppThreadLocalUtil . getUser ( ) ; if ( user == null ) { return ResponseResult . errorResult ( AppHttpCodeEnum . NEED_LOGIN ) ; } List < ApUserSearch > apUserSearches = mongoTemplate. find ( Query . query ( Criteria . where ( "userId" ) . is ( user. getId ( ) ) ) . with ( Sort . by ( Sort. Direction . DESC , "createdTime" ) ) , ApUserSearch . class ) ; return ResponseResult . okResult ( apUserSearches) ; }
删除用户搜索历史记录
/*** 删除用户搜索历史记录* @param dto* @return*/@Overridepublic ResponseResult delUserSearch(HistorySearchDto dto) {// 检查参数if (dto.getId() == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}// 判断是否登录ApUser user = AppThreadLocalUtil.getUser();if (user == null) {return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);}// 删除mongoTemplate.remove(Query.query(Criteria.where("userId").is(user.getId()).and("id").is(dto.getId())), ApUserSearch.class);return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}
关键字联想词服务实现
联想词查询
@Override
public ResponseResult search ( UserSearchDto dto) { if ( StringUtils . isBlank ( dto. getSearchWords ( ) ) ) { return ResponseResult . errorResult ( AppHttpCodeEnum . PARAM_INVALID ) ; } if ( dto. getPageSize ( ) > 20 ) { dto. setPageSize ( 20 ) ; } Query query = Query . query ( Criteria . where ( "associateWords" ) . regex ( ".*?\\" + dto. getSearchWords ( ) + ".*" ) ) ; query. limit ( dto. getPageSize ( ) ) ; List < ApAssociateWords > apAssociateWords = mongoTemplate. find ( query, ApAssociateWords . class ) ; return ResponseResult . okResult ( apAssociateWords) ;
}