Commit 946c0ffae135b2bfa2743026628de379e9972884
1 parent
51e537e0
优化产品搜索逻辑,提升匹配准确性
Showing
1 changed file
with
71 additions
and
20 deletions
shop/src/main/java/com/canrd/shop/service/impl/ProductServiceImpl.java
... | ... | @@ -462,54 +462,105 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im |
462 | 462 | Set<String> productIds = null; |
463 | 463 | Map<String,List<TicketTypeDO>> pId2ttDOsMap = null; |
464 | 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 | 488 | productIds = tickeyTypeDOList.stream().map(TicketTypeDO::getProductId).collect(Collectors.toSet()); |
468 | 489 | needLikeMatch = true; |
469 | 490 | pId2ttDOsMap = new HashMap<>(); |
491 | + | |
470 | 492 | for (TicketTypeDO ticketTypeDO : tickeyTypeDOList) { |
471 | 493 | pId2ttDOsMap.computeIfAbsent(ticketTypeDO.getProductId(), k -> new ArrayList<>()); |
472 | 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 | 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 | 533 | List<ProductDO> accurateProducts = Lists.newArrayList(); |
481 | 534 | Set<String> accurateProductIdSet = Sets.newHashSet(); |
482 | 535 | //区分大小写 |
483 | 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 | 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 | 543 | continue; |
493 | 544 | } |
494 | 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 | 548 | similarProductList.add(product); |
498 | 549 | product.setSimilar(similar); |
499 | 550 | } |
500 | - if(needLikeMatch&&productIds.contains(product.getId())){ | |
551 | + if (needLikeMatch && productIds.contains(product.getId())) { | |
501 | 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 | 554 | product.setTtsTotalSimilar(product.getTtsTotalSimilar() + ttSimilar); |
504 | 555 | }); |
505 | 556 | } |
506 | 557 | } |
507 | 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 | ); | ... | ... |