1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.helper;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.TimeUnit;
25
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.Logger;
28 import org.codelibs.core.lang.StringUtil;
29 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
30 import org.codelibs.fess.mylasta.direction.FessConfig;
31 import org.codelibs.fess.suggest.exception.SuggesterException;
32 import org.codelibs.fess.suggest.request.popularwords.PopularWordsRequestBuilder;
33 import org.codelibs.fess.util.ComponentUtil;
34
35 import com.google.common.cache.Cache;
36 import com.google.common.cache.CacheBuilder;
37
38 import jakarta.annotation.PostConstruct;
39
40
41
42
43
44
45 public class PopularWordHelper {
46
47 private static final Logger logger = LogManager.getLogger(PopularWordHelper.class);
48
49
50 protected static final char CACHE_KEY_SPLITTER = '\n';
51
52
53 protected Cache<String, List<String>> cache;
54
55
56 protected FessConfig fessConfig;
57
58
59
60
61 public PopularWordHelper() {
62
63 }
64
65
66
67
68
69 @PostConstruct
70 public void init() {
71 if (logger.isDebugEnabled()) {
72 logger.debug("Initializing {}", this.getClass().getSimpleName());
73 }
74 fessConfig = ComponentUtil.getFessConfig();
75 cache = CacheBuilder.newBuilder()
76 .maximumSize(fessConfig.getSuggestPopularWordCacheSizeAsInteger().longValue())
77 .expireAfterWrite(fessConfig.getSuggestPopularWordCacheExpireAsInteger().longValue(), TimeUnit.MINUTES)
78 .build();
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public List<String> getWordList(final SearchRequestType searchRequestType, final String seed, final String[] tags, final String[] roles,
94 final String[] fields, final String[] excludes) {
95 final String baseSeed = seed != null ? seed : fessConfig.getSuggestPopularWordSeed();
96 final String[] baseTags = tags != null ? tags : fessConfig.getSuggestPopularWordTagsAsArray();
97 final String[] baseRoles = roles != null ? roles
98 : ComponentUtil.getRoleQueryHelper()
99 .build(searchRequestType)
100 .stream()
101 .filter(StringUtil::isNotBlank)
102 .toArray(n -> new String[n]);
103 final String[] baseFields = fields != null ? fields : fessConfig.getSuggestPopularWordFieldsAsArray();
104 final String[] baseExcludes = excludes != null ? excludes : fessConfig.getSuggestPopularWordExcludesAsArray();
105 try {
106 return cache.get(getCacheKey(baseSeed, baseTags, baseRoles, baseFields, baseExcludes), () -> {
107 final List<String> wordList = new ArrayList<>();
108 final SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper();
109 final PopularWordsRequestBuilder popularWordsRequestBuilder = suggestHelper.suggester()
110 .popularWords()
111 .setSize(fessConfig.getSuggestPopularWordSizeAsInteger())
112 .setWindowSize(fessConfig.getSuggestPopularWordWindowSizeAsInteger())
113 .setQueryFreqThreshold(fessConfig.getSuggestPopularWordQueryFreqAsInteger());
114 popularWordsRequestBuilder.setSeed(baseSeed);
115 stream(baseTags).of(stream -> stream.forEach(tag -> popularWordsRequestBuilder.addTag(tag)));
116 stream(baseRoles).of(stream -> stream.forEach(role -> popularWordsRequestBuilder.addRole(role)));
117 stream(baseFields).of(stream -> stream.forEach(field -> popularWordsRequestBuilder.addField(field)));
118 stream(baseExcludes).of(stream -> stream.forEach(exclude -> popularWordsRequestBuilder.addExcludeWord(exclude)));
119 try {
120 popularWordsRequestBuilder.execute().getResponse().getItems().stream().forEach(item -> wordList.add(item.getText()));
121 } catch (final SuggesterException e) {
122 logger.warn("Failed to generate popular words.", e);
123 }
124
125 return wordList;
126 });
127 } catch (final ExecutionException e) {
128 logger.warn("Failed to load popular words.", e);
129 }
130 return Collections.emptyList();
131 }
132
133
134
135
136 public void clearCache() {
137 cache.invalidateAll();
138 }
139
140
141
142
143
144
145
146
147
148
149
150 protected String getCacheKey(final String seed, final String[] tags, final String[] roles, final String[] fields,
151 final String[] excludes) {
152 final StringBuilder buf = new StringBuilder(100);
153 buf.append(seed).append(CACHE_KEY_SPLITTER);
154 stream(tags).of(stream -> stream.sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v)));
155 buf.append(CACHE_KEY_SPLITTER);
156 stream(roles).of(stream -> stream.sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v)));
157 buf.append(CACHE_KEY_SPLITTER);
158 stream(fields).of(stream -> stream.sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v)));
159 buf.append(CACHE_KEY_SPLITTER);
160 stream(excludes).of(stream -> stream.sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v)));
161 return buf.toString();
162 }
163
164 }