1. @Slf4j
    2. @Service
    3. public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    4. @Autowired
    5. private RestHighLevelClient restHighLevelClient;
    6. @Override
    7. public PageResult search(RequestParams params) {
    8. try {
    9. // 1.准备Request
    10. SearchRequest request = new SearchRequest("hotel");
    11. // 2.准备请求参数
    12. // 2.1.query
    13. buildBasicQuery(params, request);
    14. // 2.2.分页
    15. int page = params.getPage();
    16. int size = params.getSize();
    17. request.source().from((page - 1) * size).size(size);
    18. // 2.3.距离排序
    19. String location = params.getLocation();
    20. if (StringUtils.isNotBlank(location)) {
    21. request.source().sort(SortBuilders
    22. .geoDistanceSort("location", new GeoPoint(location))
    23. .order(SortOrder.ASC)
    24. .unit(DistanceUnit.KILOMETERS)
    25. );
    26. }
    27. // 3.发送请求
    28. SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
    29. // 4.解析响应
    30. return handleResponse(response);
    31. } catch (IOException e) {
    32. throw new RuntimeException("搜索数据失败", e);
    33. }
    34. }
    35. private void buildBasicQuery(RequestParams params, SearchRequest request) {
    36. // 1.准备Boolean查询
    37. BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    38. // 1.1.关键字搜索,match查询,放到must中
    39. String key = params.getKey();
    40. if (StringUtils.isNotBlank(key)) {
    41. // 不为空,根据关键字查询
    42. boolQuery.must(QueryBuilders.matchQuery("all", key));
    43. } else {
    44. // 为空,查询所有
    45. boolQuery.must(QueryBuilders.matchAllQuery());
    46. }
    47. // 1.2.品牌
    48. String brand = params.getBrand();
    49. if (StringUtils.isNotBlank(brand)) {
    50. boolQuery.filter(QueryBuilders.termQuery("brand", brand));
    51. }
    52. // 1.3.城市
    53. String city = params.getCity();
    54. if (StringUtils.isNotBlank(city)) {
    55. boolQuery.filter(QueryBuilders.termQuery("city", city));
    56. }
    57. // 1.4.星级
    58. String starName = params.getStarName();
    59. if (StringUtils.isNotBlank(starName)) {
    60. boolQuery.filter(QueryBuilders.termQuery("starName", starName));
    61. }
    62. // 1.5.价格范围
    63. Integer minPrice = params.getMinPrice();
    64. Integer maxPrice = params.getMaxPrice();
    65. if (minPrice != null && maxPrice != null) {
    66. maxPrice = maxPrice == 0 ? Integer.MAX_VALUE : maxPrice;
    67. boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
    68. }
    69. // 2.算分函数查询
    70. FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
    71. boolQuery, // 原始查询,boolQuery
    72. new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // function数组
    73. new FunctionScoreQueryBuilder.FilterFunctionBuilder(
    74. QueryBuilders.termQuery("isAD", true), // 过滤条件
    75. ScoreFunctionBuilders.weightFactorFunction(10) // 算分函数
    76. )
    77. }
    78. );
    79. // 3.设置查询条件
    80. request.source().query(functionScoreQuery);
    81. }
    82. private PageResult handleResponse(SearchResponse response) {
    83. SearchHits searchHits = response.getHits();
    84. // 4.1.总条数
    85. long total = searchHits.getTotalHits().value;
    86. // 4.2.获取文档数组
    87. SearchHit[] hits = searchHits.getHits();
    88. // 4.3.遍历
    89. List<HotelDoc> hotels = new ArrayList<>(hits.length);
    90. for (SearchHit hit : hits) {
    91. // 4.4.获取source
    92. String json = hit.getSourceAsString();
    93. // 4.5.反序列化,非高亮的
    94. HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
    95. // 4.6.处理高亮结果
    96. // 1)获取高亮map
    97. Map<String, HighlightField> map = hit.getHighlightFields();
    98. if (map != null && !map.isEmpty()) {
    99. // 2)根据字段名,获取高亮结果
    100. HighlightField highlightField = map.get("name");
    101. if (highlightField != null) {
    102. // 3)获取高亮结果字符串数组中的第1个元素
    103. String hName = highlightField.getFragments()[0].toString();
    104. // 4)把高亮结果放到HotelDoc中
    105. hotelDoc.setName(hName);
    106. }
    107. }
    108. // 4.8.排序信息
    109. Object[] sortValues = hit.getSortValues();
    110. if (sortValues.length > 0) {
    111. hotelDoc.setDistance(sortValues[0]);
    112. }
    113. // 4.9.放入集合
    114. hotels.add(hotelDoc);
    115. }
    116. return new PageResult(total, hotels);
    117. }
    118. }