|
@@ -24,14 +24,22 @@ import shop.alien.entity.store.LifeBlacklist;
|
|
|
import shop.alien.entity.store.StoreImg;
|
|
import shop.alien.entity.store.StoreImg;
|
|
|
import shop.alien.entity.store.StoreUser;
|
|
import shop.alien.entity.store.StoreUser;
|
|
|
import shop.alien.entity.store.vo.StoreInfoVo;
|
|
import shop.alien.entity.store.vo.StoreInfoVo;
|
|
|
|
|
+import shop.alien.entity.store.CommonRating;
|
|
|
|
|
+import shop.alien.mapper.CommonRatingMapper;
|
|
|
import shop.alien.mapper.LifeBlacklistMapper;
|
|
import shop.alien.mapper.LifeBlacklistMapper;
|
|
|
import shop.alien.mapper.StoreImgMapper;
|
|
import shop.alien.mapper.StoreImgMapper;
|
|
|
import shop.alien.mapper.StoreUserMapper;
|
|
import shop.alien.mapper.StoreUserMapper;
|
|
|
import shop.alien.store.annotation.TrackEvent;
|
|
import shop.alien.store.annotation.TrackEvent;
|
|
|
import shop.alien.store.service.CommonRatingService;
|
|
import shop.alien.store.service.CommonRatingService;
|
|
|
import shop.alien.store.service.StoreImgService;
|
|
import shop.alien.store.service.StoreImgService;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
|
|
|
|
|
+import java.time.Instant;
|
|
|
|
|
+import java.time.ZoneId;
|
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
|
|
+import java.util.concurrent.Executor;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -56,6 +64,7 @@ public class AiSearchController {
|
|
|
private final RestTemplate restTemplate;
|
|
private final RestTemplate restTemplate;
|
|
|
private final StoreImgService storeImgService;
|
|
private final StoreImgService storeImgService;
|
|
|
private final CommonRatingService commonRatingService;
|
|
private final CommonRatingService commonRatingService;
|
|
|
|
|
+ private final CommonRatingMapper commonRatingMapper;
|
|
|
|
|
|
|
|
private final LifeBlacklistMapper lifeBlacklistMapper;
|
|
private final LifeBlacklistMapper lifeBlacklistMapper;
|
|
|
|
|
|
|
@@ -135,19 +144,22 @@ public class AiSearchController {
|
|
|
|
|
|
|
|
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, null);
|
|
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, null);
|
|
|
try {
|
|
try {
|
|
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneId.systemDefault());
|
|
|
|
|
+ log.info("调用AI模糊搜索接口 请求参数------{} 时间: {}", requestBody, formatter.format(Instant.now()));
|
|
|
ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(aiSearchFuzzyUrl, request, String.class);
|
|
ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(aiSearchFuzzyUrl, request, String.class);
|
|
|
String body = stringResponseEntity.getBody();
|
|
String body = stringResponseEntity.getBody();
|
|
|
- log.info("调用AI列表接口 处理前v 接口返回------{}", body);
|
|
|
|
|
|
|
+ log.info("调用AI列表接口 处理前v 接口返回------{} 时间: {}", body, formatter.format(Instant.now()));
|
|
|
JSONObject jsonObject = JSONObject.parseObject(body);
|
|
JSONObject jsonObject = JSONObject.parseObject(body);
|
|
|
JSONObject jsonObject1 = new JSONObject();
|
|
JSONObject jsonObject1 = new JSONObject();
|
|
|
// 模糊搜索:从related_results和matched_results字段获取数据
|
|
// 模糊搜索:从related_results和matched_results字段获取数据
|
|
|
List<StoreInfoVo> result = convertToStoreInfoList(jsonObject.getJSONArray("results"),map.get("userId"));
|
|
List<StoreInfoVo> result = convertToStoreInfoList(jsonObject.getJSONArray("results"),map.get("userId"));
|
|
|
|
|
|
|
|
- // 查找图片并设置到result中(图片类型1-入口图)
|
|
|
|
|
- fillStoreImages(result, 1);
|
|
|
|
|
-
|
|
|
|
|
- // 填充评论总数
|
|
|
|
|
- fillRatingCount(result);
|
|
|
|
|
|
|
+ // 并发处理图片和评论数据,提升性能
|
|
|
|
|
+ CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> fillStoreImages(result, 1));
|
|
|
|
|
+ CompletableFuture<Void> ratingFuture = CompletableFuture.runAsync(() -> fillRatingCountBatch(result));
|
|
|
|
|
+
|
|
|
|
|
+ // 等待两个任务完成
|
|
|
|
|
+ CompletableFuture.allOf(imageFuture, ratingFuture).join();
|
|
|
|
|
|
|
|
jsonObject1.put("records", result);
|
|
jsonObject1.put("records", result);
|
|
|
|
|
|
|
@@ -203,24 +215,7 @@ public class AiSearchController {
|
|
|
if(collect.contains(storeInfo.getId())){
|
|
if(collect.contains(storeInfo.getId())){
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
- Integer totalCount = 0;
|
|
|
|
|
- double storeScore;
|
|
|
|
|
- Object ratingObj = commonRatingService.getRatingCount(storeInfo.getId(), 1);
|
|
|
|
|
- if (ratingObj != null) {
|
|
|
|
|
- Map<String, Object> ratingMap = (Map<String, Object>) ratingObj;
|
|
|
|
|
- Object totalCountObj = ratingMap.get("totalCount");
|
|
|
|
|
- if (totalCountObj != null) {
|
|
|
|
|
- // 安全转换为整数
|
|
|
|
|
- try {
|
|
|
|
|
- totalCount = Integer.parseInt(totalCountObj.toString().trim());
|
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
|
- totalCount = 0; // 转换失败时默认值
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- totalCount = 0;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- storeInfo.setTotalNum(totalCount.toString());
|
|
|
|
|
|
|
+ // 移除这里的getRatingCount调用,统一在fillRatingCountBatch中批量处理
|
|
|
storeInfoList.add(storeInfo);
|
|
storeInfoList.add(storeInfo);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -282,34 +277,72 @@ public class AiSearchController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 填充评论总数到StoreInfoVo列表中
|
|
|
|
|
|
|
+ * 填充评论总数到StoreInfoVo列表中(批量查询优化版本)
|
|
|
|
|
+ * 使用批量查询替代N+1查询,大幅提升性能
|
|
|
*
|
|
*
|
|
|
* @param result StoreInfoVo列表
|
|
* @param result StoreInfoVo列表
|
|
|
*/
|
|
*/
|
|
|
- private void fillRatingCount(List<StoreInfoVo> result) {
|
|
|
|
|
|
|
+ private void fillRatingCountBatch(List<StoreInfoVo> result) {
|
|
|
if (result == null || result.isEmpty()) {
|
|
if (result == null || result.isEmpty()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- for (StoreInfoVo storeInfo : result) {
|
|
|
|
|
- if (storeInfo.getId() != null) {
|
|
|
|
|
- try {
|
|
|
|
|
- // 调用评论服务获取评论总数,businessId传id,businessType传1
|
|
|
|
|
- Object ratingCountObj = commonRatingService.getRatingCount(storeInfo.getId(), 1);
|
|
|
|
|
-
|
|
|
|
|
- // 将返回的Object转换为Map
|
|
|
|
|
- if (ratingCountObj instanceof Map) {
|
|
|
|
|
- Map<String, Object> ratingCountMap = (Map<String, Object>) ratingCountObj;
|
|
|
|
|
- // 从map中取出totalCount字段
|
|
|
|
|
- Object totalCount = ratingCountMap.get("totalCount");
|
|
|
|
|
- if (totalCount != null) {
|
|
|
|
|
- // 赋值给totalNum字段(转为String类型)
|
|
|
|
|
- storeInfo.setTotalNum(String.valueOf(totalCount));
|
|
|
|
|
|
|
+ // 提取所有storeId
|
|
|
|
|
+ List<Integer> storeIdList = result.stream()
|
|
|
|
|
+ .map(StoreInfoVo::getId)
|
|
|
|
|
+ .filter(id -> id != null)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ if (storeIdList.isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 批量查询所有store的评价记录(只查询审核通过且展示的)
|
|
|
|
|
+ LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.in(CommonRating::getBusinessId, storeIdList)
|
|
|
|
|
+ .eq(CommonRating::getBusinessType, 1)
|
|
|
|
|
+ .eq(CommonRating::getAuditStatus, 1)
|
|
|
|
|
+ .eq(CommonRating::getIsShow, 1);
|
|
|
|
|
+ List<CommonRating> allRatings = commonRatingMapper.selectList(wrapper);
|
|
|
|
|
+
|
|
|
|
|
+ // 按businessId分组统计评论总数
|
|
|
|
|
+ Map<Integer, Long> ratingCountMap = allRatings.stream()
|
|
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
|
|
+ CommonRating::getBusinessId,
|
|
|
|
|
+ Collectors.counting()
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ // 设置评论总数到对应的StoreInfoVo
|
|
|
|
|
+ for (StoreInfoVo storeInfo : result) {
|
|
|
|
|
+ if (storeInfo.getId() != null) {
|
|
|
|
|
+ Long count = ratingCountMap.get(storeInfo.getId());
|
|
|
|
|
+ storeInfo.setTotalNum(count != null ? String.valueOf(count) : "0");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("批量获取评论总数失败", e);
|
|
|
|
|
+ // 如果批量查询失败,回退到单个查询(兜底策略)
|
|
|
|
|
+ for (StoreInfoVo storeInfo : result) {
|
|
|
|
|
+ if (storeInfo.getId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Object ratingCountObj = commonRatingService.getRatingCount(storeInfo.getId(), 1);
|
|
|
|
|
+ if (ratingCountObj instanceof Map) {
|
|
|
|
|
+ Map<String, Object> ratingCountMap = (Map<String, Object>) ratingCountObj;
|
|
|
|
|
+ Object totalCount = ratingCountMap.get("totalCount");
|
|
|
|
|
+ if (totalCount != null) {
|
|
|
|
|
+ storeInfo.setTotalNum(String.valueOf(totalCount));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeInfo.setTotalNum("0");
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeInfo.setTotalNum("0");
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
|
+ log.warn("获取评论总数失败,storeId: {}", storeInfo.getId(), ex);
|
|
|
|
|
+ storeInfo.setTotalNum("0");
|
|
|
}
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.warn("获取评论总数失败,storeId: {}", storeInfo.getId(), e);
|
|
|
|
|
- // 如果获取失败,继续处理下一个,不影响其他数据
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|