use cache for popular words

This commit is contained in:
Shinsuke Sugaya 2015-12-19 20:02:49 +09:00
parent 952c63363b
commit b9b1851d38
3 changed files with 117 additions and 18 deletions

View file

@ -16,7 +16,13 @@
package org.codelibs.fess.helper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.codelibs.fess.mylasta.direction.FessConfig;
import org.codelibs.fess.suggest.request.popularwords.PopularWordsRequestBuilder;
@ -25,9 +31,26 @@ import org.codelibs.fess.util.StreamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
public class PopularWordHelper {
private static final Logger logger = LoggerFactory.getLogger(PopularWordHelper.class);
private static final char CACHE_KEY_SPLITTER = '\n';
private Cache<String, List<String>> cache;
private FessConfig fessConfig;
@PostConstruct
public void init() {
fessConfig = ComponentUtil.getFessConfig();
cache =
CacheBuilder.newBuilder().maximumSize(fessConfig.getSuggestPopularWordCacheSizeAsInteger().longValue())
.expireAfterWrite(fessConfig.getSuggestPopularWordCacheExpireAsInteger().longValue(), TimeUnit.MINUTES).build();
}
public List<String> getWordList(String seed, String[] tags, String[] fields, String[] excludes) {
RoleQueryHelper roleQueryHelper = ComponentUtil.getRoleQueryHelper();
String[] roles = roleQueryHelper.build().stream().toArray(n -> new String[n]);
@ -35,25 +58,46 @@ public class PopularWordHelper {
}
public List<String> getWordList(String seed, String[] tags, String[] roles, String[] fields, String[] excludes) {
// TODO cache
final List<String> wordList = new ArrayList<String>();
FessConfig fessConfig = ComponentUtil.getFessConfig();
SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper();
final PopularWordsRequestBuilder popularWordsRequestBuilder =
suggestHelper.suggester().popularWords().setSize(fessConfig.getSuggestPopularWordSizeAsInteger().intValue())
.setWindowSize(fessConfig.getSuggestPopularWordWindowSizeAsInteger().intValue());
if (seed != null) {
popularWordsRequestBuilder.setSeed(seed);
}
StreamUtil.of(tags).forEach(tag -> popularWordsRequestBuilder.addTag(tag));
StreamUtil.of(roles).forEach(role -> popularWordsRequestBuilder.addRole(role));
StreamUtil.of(fields).forEach(field -> popularWordsRequestBuilder.addField(field));
StreamUtil.of(excludes).forEach(exclude -> popularWordsRequestBuilder.addExcludeWord(exclude));
popularWordsRequestBuilder.execute().then(r -> {
r.getItems().stream().forEach(item -> wordList.add(item.getText()));
}).error(t -> logger.warn("Failed to generate popular words.", t));
try {
return cache.get(getCacheKey(seed, tags, roles, fields, excludes), new Callable<List<String>>() {
@Override
public List<String> call() throws Exception {
final List<String> wordList = new ArrayList<String>();
SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper();
final PopularWordsRequestBuilder popularWordsRequestBuilder =
suggestHelper.suggester().popularWords().setSize(fessConfig.getSuggestPopularWordSizeAsInteger().intValue())
.setWindowSize(fessConfig.getSuggestPopularWordWindowSizeAsInteger().intValue());
if (seed != null) {
popularWordsRequestBuilder.setSeed(seed);
}
StreamUtil.of(tags).forEach(tag -> popularWordsRequestBuilder.addTag(tag));
StreamUtil.of(roles).forEach(role -> popularWordsRequestBuilder.addRole(role));
StreamUtil.of(fields).forEach(field -> popularWordsRequestBuilder.addField(field));
StreamUtil.of(excludes).forEach(exclude -> popularWordsRequestBuilder.addExcludeWord(exclude));
popularWordsRequestBuilder.execute().then(r -> {
r.getItems().stream().forEach(item -> wordList.add(item.getText()));
}).error(t -> logger.warn("Failed to generate popular words.", t));
return wordList;
return wordList;
}
});
} catch (ExecutionException e) {
logger.warn("Failed to load popular words.", e);
}
return Collections.emptyList();
}
protected String getCacheKey(String seed, String[] tags, String[] roles, String[] fields, String[] excludes) {
StringBuilder buf = new StringBuilder(100);
buf.append(seed).append(CACHE_KEY_SPLITTER);
StreamUtil.of(tags).sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v));
buf.append(CACHE_KEY_SPLITTER);
StreamUtil.of(roles).sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v));
buf.append(CACHE_KEY_SPLITTER);
StreamUtil.of(fields).sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v));
buf.append(CACHE_KEY_SPLITTER);
StreamUtil.of(excludes).sorted().reduce((l, r) -> l + r).ifPresent(v -> buf.append(v));
return buf.toString();
}
}

View file

@ -343,6 +343,12 @@ public interface FessConfig extends FessEnv {
/** The key of the configuration. e.g. 1 */
String SUGGEST_SOURCE_READER_SCROLL_SIZE = "suggest.source.reader.scroll.size";
/** The key of the configuration. e.g. 1000 */
String SUGGEST_POPULAR_WORD_CACHE_SIZE = "suggest.popular.word.cache.size";
/** The key of the configuration. e.g. 60 */
String SUGGEST_POPULAR_WORD_CACHE_EXPIRE = "suggest.popular.word.cache.expire";
/** The key of the configuration. e.g. guest */
String SUGGEST_ROLE_FILTERS = "suggest.role.filters";
@ -1357,6 +1363,36 @@ public interface FessConfig extends FessEnv {
*/
Integer getSuggestSourceReaderScrollSizeAsInteger();
/**
* Get the value for the key 'suggest.popular.word.cache.size'. <br>
* The value is, e.g. 1000 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSuggestPopularWordCacheSize();
/**
* Get the value for the key 'suggest.popular.word.cache.size' as {@link Integer}. <br>
* The value is, e.g. 1000 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
* @throws NumberFormatException When the property is not integer.
*/
Integer getSuggestPopularWordCacheSizeAsInteger();
/**
* Get the value for the key 'suggest.popular.word.cache.expire'. <br>
* The value is, e.g. 60 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSuggestPopularWordCacheExpire();
/**
* Get the value for the key 'suggest.popular.word.cache.expire' as {@link Integer}. <br>
* The value is, e.g. 60 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
* @throws NumberFormatException When the property is not integer.
*/
Integer getSuggestPopularWordCacheExpireAsInteger();
/**
* Get the value for the key 'suggest.role.filters'. <br>
* The value is, e.g. guest <br>
@ -1909,6 +1945,22 @@ public interface FessConfig extends FessEnv {
return getAsInteger(FessConfig.SUGGEST_SOURCE_READER_SCROLL_SIZE);
}
public String getSuggestPopularWordCacheSize() {
return get(FessConfig.SUGGEST_POPULAR_WORD_CACHE_SIZE);
}
public Integer getSuggestPopularWordCacheSizeAsInteger() {
return getAsInteger(FessConfig.SUGGEST_POPULAR_WORD_CACHE_SIZE);
}
public String getSuggestPopularWordCacheExpire() {
return get(FessConfig.SUGGEST_POPULAR_WORD_CACHE_EXPIRE);
}
public Integer getSuggestPopularWordCacheExpireAsInteger() {
return getAsInteger(FessConfig.SUGGEST_POPULAR_WORD_CACHE_EXPIRE);
}
public String getSuggestRoleFilters() {
return get(FessConfig.SUGGEST_ROLE_FILTERS);
}

View file

@ -206,6 +206,9 @@ suggest.field.roles=role
suggest.field.index.contents=content,title
suggest.update.request.interval=1
suggest.source.reader.scroll.size=1
suggest.popular.word.cache.size=1000
suggest.popular.word.cache.expire=60
suggest.role.filters=\
guest