Commit 946c0ffae135b2bfa2743026628de379e9972884

Authored by boyang
1 parent 51e537e0

优化产品搜索逻辑,提升匹配准确性

shop/src/main/java/com/canrd/shop/service/impl/ProductServiceImpl.java
@@ -462,54 +462,105 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im @@ -462,54 +462,105 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im
462 Set<String> productIds = null; 462 Set<String> productIds = null;
463 Map<String,List<TicketTypeDO>> pId2ttDOsMap = null; 463 Map<String,List<TicketTypeDO>> pId2ttDOsMap = null;
464 boolean needLikeMatch = false; 464 boolean needLikeMatch = false;
465 - if(StringUtils.isNotBlank(productQueryVO.getKeyword())){  
466 - List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery().like(TicketTypeDO::getRank, productQueryVO.getKeyword()).list(); 465 +// if(StringUtils.isNotBlank(productQueryVO.getKeyword())){
  466 +// List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery().like(TicketTypeDO::getRank, productQueryVO.getKeyword()).list();
  467 +// productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet());
  468 +// needLikeMatch = true;
  469 +// pId2ttDOsMap = new HashMap<>();
  470 +// for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) {
  471 +// pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>());
  472 +// pId2ttDOsMap.get(ticketTypeDO.getProductId()).add(ticketTypeDO);
  473 +// }
  474 +// Set<String> finalProductIds = productIds;
  475 +// queryWapper.and(subQueryWapper -> {
  476 +// subQueryWapper.like("p.name", productQueryVO.getKeyword()).or().in(CollUtil.isNotEmpty(finalProductIds),"p.id", finalProductIds);
  477 +// });
  478 +// }
  479 + String keyword = productQueryVO.getKeyword().trim();
  480 + if (StringUtils.isNotBlank(productQueryVO.getKeyword())) {
  481 +// String keyword = productQueryVO.getKeyword().trim();
  482 +
  483 + // 先精确匹配完整的关键字
  484 + List<TicketTypeDO> tickeyTypeDOList = ticketTypeService.lambdaQuery()
  485 + .like(TicketTypeDO::getRank, keyword)
  486 + .list();
  487 +
467 productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet()); 488 productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet());
468 needLikeMatch = true; 489 needLikeMatch = true;
469 pId2ttDOsMap = new HashMap<>(); 490 pId2ttDOsMap = new HashMap<>();
  491 +
470 for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) { 492 for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) {
471 pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>()); 493 pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>());
472 pId2ttDOsMap.get(ticketTypeDO.getProductId()).add(ticketTypeDO); 494 pId2ttDOsMap.get(ticketTypeDO.getProductId()).add(ticketTypeDO);
473 } 495 }
474 - Set<String> finalProductIds = productIds;  
475 - queryWapper.and(subQueryWapper -> {  
476 - subQueryWapper.like("p.name", productQueryVO.getKeyword()).or().in(CollUtil.isNotEmpty(finalProductIds),"p.id", finalProductIds);  
477 - }); 496 +
  497 + if (productIds.isEmpty()) {
  498 + // 如果没有匹配到,分词处理
  499 + String[] keywords = keyword.split("\\s+");
  500 +
  501 + queryWapper.and(subQueryWapper -> {
  502 + // 查询包含所有分词的记录
  503 + for (String key : keywords) {
  504 + subQueryWapper.like("p.name", key).or();
  505 + }
  506 + });
  507 + } else {
  508 + Set<String> finalProductIds = productIds;
  509 +
  510 + queryWapper.and(subQueryWapper -> {
  511 + subQueryWapper.like("p.name", keyword).or().in(CollUtil.isNotEmpty(finalProductIds), "p.id", finalProductIds);
  512 + });
  513 + }
478 } 514 }
479 List<ProductDO> productDOS = this.baseMapper.queryList(queryWapper); 515 List<ProductDO> productDOS = this.baseMapper.queryList(queryWapper);
  516 + // Split the keyword into individual words
  517 + String[] keywords = keyword.split("\\s+");
  518 + Map<ProductDO, Integer> collect = productDOS.stream().collect(Collectors.toMap(Function.identity(), productDO -> {
  519 + int matchCount = 0;
  520 + for (String key : keywords) {
  521 + if (productDO.getName().toLowerCase().contains(key.toLowerCase())) {
  522 + matchCount++;
  523 + }
  524 + }
  525 + return matchCount;
  526 + }));
  527 + productDOS.sort((product1, product2) -> {
  528 + int matchCount1 = collect.get(product1);
  529 + int matchCount2 = collect.get(product2);
  530 + // Return the comparison result: higher match count comes first
  531 + return Integer.compare(matchCount2, matchCount1);
  532 + });
480 List<ProductDO> accurateProducts = Lists.newArrayList(); 533 List<ProductDO> accurateProducts = Lists.newArrayList();
481 Set<String> accurateProductIdSet = Sets.newHashSet(); 534 Set<String> accurateProductIdSet = Sets.newHashSet();
482 //区分大小写 535 //区分大小写
483 productDOS.forEach(x -> { 536 productDOS.forEach(x -> {
484 - if(x.getName().trim().contains(productQueryVO.getKeyword().trim())){  
485 - accurateProducts.add(x);  
486 - accurateProductIdSet.add(x.getId());  
487 - } 537 + accurateProducts.add(x);
  538 + accurateProductIdSet.add(x.getId());
488 }); 539 });
489 List<ProductDO> similarProductList = Lists.newArrayList(); 540 List<ProductDO> similarProductList = Lists.newArrayList();
490 - for(ProductDO product:productDOS){  
491 - if(accurateProductIdSet.contains(product.getId())){ 541 + for (ProductDO product : productDOS) {
  542 + if (accurateProductIdSet.contains(product.getId())) {
492 continue; 543 continue;
493 } 544 }
494 String name = product.getName(); 545 String name = product.getName();
495 - int similar = LevenshteinDistanceService.LevenshteinDistancePercent(productQueryVO.getKeyword(),name);  
496 - if(similar>=0) {//模糊匹配 546 + int similar = LevenshteinDistanceService.LevenshteinDistancePercent(productQueryVO.getKeyword(), name);
  547 + if (similar >= 0) {//模糊匹配
497 similarProductList.add(product); 548 similarProductList.add(product);
498 product.setSimilar(similar); 549 product.setSimilar(similar);
499 } 550 }
500 - if(needLikeMatch&&productIds.contains(product.getId())){ 551 + if (needLikeMatch && productIds.contains(product.getId())) {
501 pId2ttDOsMap.get(product.getId()).forEach(x -> { 552 pId2ttDOsMap.get(product.getId()).forEach(x -> {
502 - int ttSimilar = LevenshteinDistanceService.LevenshteinDistancePercent(productQueryVO.getKeyword(),x.getRank()); 553 + int ttSimilar = LevenshteinDistanceService.LevenshteinDistancePercent(productQueryVO.getKeyword(), x.getRank());
503 product.setTtsTotalSimilar(product.getTtsTotalSimilar() + ttSimilar); 554 product.setTtsTotalSimilar(product.getTtsTotalSimilar() + ttSimilar);
504 }); 555 });
505 } 556 }
506 } 557 }
507 Collections.sort(similarProductList, (o1, o2) -> 558 Collections.sort(similarProductList, (o1, o2) ->
508 { 559 {
509 - if (o2.getSimilar()-o1.getSimilar()!=0) {  
510 - return o2.getSimilar()-o1.getSimilar();  
511 - }else {  
512 - return o2.getTtsTotalSimilar()-o1.getTtsTotalSimilar(); 560 + if (o2.getSimilar() - o1.getSimilar() != 0) {
  561 + return o2.getSimilar() - o1.getSimilar();
  562 + } else {
  563 + return o2.getTtsTotalSimilar() - o1.getTtsTotalSimilar();
513 } 564 }
514 } 565 }
515 ); 566 );