@@ -70,36 +70,46 @@ public SearchResDto search(String query, Long userId) {
7070 }
7171
7272 public List <String > recommendAlternatives (String keyword , int size ) {
73- NativeQuery nativeQuery = NativeQuery .builder ()
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 )))
73+ NativeQuery logQuery = NativeQuery .builder ()
74+ .withMaxResults (0 )
75+ .withAggregation ("frequent_keywords" , Aggregation .of (a -> a
76+ .terms (t -> t
77+ .field ("keyword" )
78+ .size (200 )
79+ )
7880 ))
79- .withMaxResults (50 )
8081 .build ();
8182
82- SearchHits <ProductDocument > hits =
83- elasticsearchOperations .search (nativeQuery , ProductDocument .class );
83+ SearchHits <SearchLogDocument > logHits =
84+ elasticsearchOperations .search (logQuery , SearchLogDocument .class );
85+
86+ List <String > logKeywords = new ArrayList <>();
87+ if (logHits .getAggregations () != null ) {
88+ ElasticsearchAggregations aggregations = (ElasticsearchAggregations ) logHits .getAggregations ();
89+ ElasticsearchAggregation aggregation = aggregations .get ("frequent_keywords" );
90+ if (aggregation != null ) {
91+ var aggregate = aggregation .aggregation ().getAggregate ();
92+ if (aggregate != null && aggregate .isSterms ()) {
93+ logKeywords = aggregate .sterms ().buckets ().array ().stream ()
94+ .map (bucket -> bucket .key ().stringValue ())
95+ .toList ();
96+ }
97+ }
98+ }
99+
100+ if (logKeywords .isEmpty ()) {
101+ return List .of ();
102+ }
84103
85104 LevenshteinDistance levenshtein = new LevenshteinDistance ();
86105 String lowerKeyword = keyword .toLowerCase ();
106+ int maxDistance = Math .max (2 , lowerKeyword .length () / 2 );
87107
88- return hits .getSearchHits ().stream ()
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 )
98- .distinct ()
99- .sorted (Comparator .comparingInt (val ->
100- levenshtein .apply (lowerKeyword , val .toLowerCase ())
101- ))
102- .filter (val -> !val .equalsIgnoreCase (keyword ))
108+ return logKeywords .stream ()
109+ .filter (k -> !k .equalsIgnoreCase (keyword ))
110+ .filter (k -> k .length () >= 2 )
111+ .filter (k -> levenshtein .apply (lowerKeyword , k .toLowerCase ()) <= maxDistance )
112+ .sorted (Comparator .comparingInt (k -> levenshtein .apply (lowerKeyword , k .toLowerCase ())))
103113 .limit (size )
104114 .toList ();
105115 }
0 commit comments