|
19 | 19 |
|
20 | 20 | import java.time.LocalDateTime; |
21 | 21 | import java.util.ArrayList; |
| 22 | +import java.util.Comparator; |
22 | 23 | import java.util.LinkedHashSet; |
23 | 24 | import java.util.List; |
24 | 25 | import java.util.UUID; |
25 | 26 | import java.util.stream.Collectors; |
| 27 | +import org.apache.commons.text.similarity.LevenshteinDistance; |
26 | 28 |
|
27 | 29 | import co.elastic.clients.elasticsearch._types.aggregations.StringTermsAggregate; |
28 | 30 | import lombok.extern.slf4j.Slf4j; |
@@ -67,25 +69,38 @@ public SearchResDto search(String query, Long userId) { |
67 | 69 | return SearchResDto.of(List.of(), alternatives); |
68 | 70 | } |
69 | 71 |
|
70 | | - public List<String> recommendAlternatives(String keyword, int limit) { |
| 72 | + public List<String> recommendAlternatives(String keyword, int size) { |
71 | 73 | NativeQuery nativeQuery = NativeQuery.builder() |
72 | | - .withQuery(q -> q.fuzzy(f -> f |
73 | | - .field("keyword") |
74 | | - .value(keyword) |
75 | | - .fuzziness("2") |
76 | | - .prefixLength(1) |
| 74 | + .withQuery(q -> q.bool(b -> b |
| 75 | + .should(s -> s.match(m -> m.field("brandName.autocomplete").query(keyword))) |
| 76 | + .should(s -> s.match(m -> m.field("categoryName.autocomplete").query(keyword))) |
| 77 | + .should(s -> s.match(m -> m.field("name.autocomplete").query(keyword))) |
77 | 78 | )) |
78 | | - .withMinScore(0.1f) |
79 | | - .withMaxResults(limit * 2) |
| 79 | + .withMaxResults(50) |
80 | 80 | .build(); |
81 | 81 |
|
82 | | - SearchHits<SearchLogDocument> hits = elasticsearchOperations.search(nativeQuery, SearchLogDocument.class); |
| 82 | + SearchHits<ProductDocument> hits = |
| 83 | + elasticsearchOperations.search(nativeQuery, ProductDocument.class); |
| 84 | + |
| 85 | + LevenshteinDistance levenshtein = new LevenshteinDistance(); |
| 86 | + String lowerKeyword = keyword.toLowerCase(); |
83 | 87 |
|
84 | 88 | return hits.getSearchHits().stream() |
85 | | - .map(hit -> hit.getContent().getKeyword()) |
86 | | - .filter(k -> !k.equals(keyword)) |
| 89 | + .map(hit -> { |
| 90 | + ProductDocument doc = hit.getContent(); |
| 91 | + List<String> candidates = new ArrayList<>(); |
| 92 | + if (doc.getBrandName() != null) candidates.add(doc.getBrandName()); |
| 93 | + if (doc.getCategoryName() != null) candidates.add(doc.getCategoryName()); |
| 94 | + if (doc.getName() != null) candidates.add(doc.getName()); |
| 95 | + return candidates; |
| 96 | + }) |
| 97 | + .flatMap(List::stream) |
87 | 98 | .distinct() |
88 | | - .limit(limit) |
| 99 | + .sorted(Comparator.comparingInt(val -> |
| 100 | + levenshtein.apply(lowerKeyword, val.toLowerCase()) |
| 101 | + )) |
| 102 | + .filter(val -> !val.equalsIgnoreCase(keyword)) |
| 103 | + .limit(size) |
89 | 104 | .toList(); |
90 | 105 | } |
91 | 106 |
|
|
0 commit comments