Поиск записи в интервале в Guava Cache
Я оцениваю некоторые результаты с помощью Spring SpEL и хочу кэшировать эти результаты, чтобы мне не приходилось оценивать выражения с одинаковыми параметрами.
Кешированный ключевой объект:
@Data
@AllArgsConstructor
public class CachedResult {
private String baseName;
private Interval interval;
public boolean isBetweenInclusive(final DateTime date) {
return interval.contains(date) || interval.getEnd().isEqual(date);
}
}
Мое решение найти запись с interval
что охватывает данное dateTime
:
public String getEvaluatedResult(final String baseName, final DateTime dateTime) {
return cache.asMap().entrySet()
.stream()
.filter(entry -> entry.getKey().getBaseName().equals(baseName) && entry.getKey().isBetweenInclusive(dateTime))
.findFirst()
.map(Map.Entry::getValue)
.orElse(null);
}
Я хотел использовать cache.get(key, valueLoader)
метод, так что он может поместить значения в сам кеш при необходимости, но я не могу придумать, как использовать isBetweenInclusive
и этот метод.
Моя попытка с комментарием, где я попал в проблемы:
public class MyCache {
private final Cache<CachedResult, String> cache;
public DefaultRolloverCache(final int expiration) {
this.cache = CacheBuilder.newBuilder()
.expireAfterWrite(expiration, TimeUnit.MINUTES)
.build();
}
public String getFileName(final String baseName, final DateTime dateTime, final Callable<String> valueLoader) {
try {
return cache.get(new CachedResult(baseName, null/*How to find an interval that covers the given dateTime?*/), valueLoader);
} catch (final ExecutionException e) {
throw new IllegalArgumentException(String.format("Cannot read fileName from cache with basename: '%s' and dateTime: %s", baseName, dateTime), e);
}
}
}
Я называю этот метод как:
cache.getFileName(baseName, new DateTime(), () -> doSlowCalculations(baseName));
Конечно, так как я не знаю, как использовать упомянутый метод, я должен использовать cache.put(new CachedResult(...))
ставить записи в кеш сам.
Есть ли лучший способ отфильтровать кэш, чем вызов asMap
и фильтровать его как карту? Могу ли я как-то использовать cache.get(key, valueLoader)
или даже гуавы CacheLoader
чтобы он мог вводить значения автоматически?
По мере увеличения производительности у меня будет максимум 5-10 записей одновременно, но я буду много читать из них, поэтому время чтения очень важно для меня, и я не уверен, что моя текущая реализация, которая повторяется 5-10 записей все время и проверка каждого из них - лучший подход.
1 ответ
Мое окончательное решение после прочтения комментария Луи написал:
public String getFileName(final String baseName, final DateTime dateTime, final Supplier<String> valueLoader) {
final Optional<String> cached = cache.asMap().entrySet()
.stream()
.filter(entry -> entry.getKey().getBaseName().equals(baseName) && entry.getKey().isBetweenInclusive(dateTime))
.findFirst()
.map(Map.Entry::getValue);
if (cached.isPresent()) {
return cached.get();
} else {
final String evaluatedValue = valueLoader.get();
cache.put(new CachedResult(baseName, intervalCalculator.getInterval(dateTime)), evaluatedValue);
return evaluatedValue;
}
}