在Guava Cache中查找一个区间内的记录
Finding a record in an interval in 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);
}
}
我的解决方案是找到包含给定 dateTime
的 interval
的记录:
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)
甚至 Guavas CacheLoader
以便它可以自动输入值吗?
随着性能的提高,我一次最多会有 5-10 条记录,但我会从中读取很多,所以读取时间对我来说非常重要,我不确定我的一直迭代 5-10 条记录并检查每条记录的当前实现是最好的方法。
阅读路易斯写的评论后我的最终解决方案:
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;
}
}
我正在使用 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);
}
}
我的解决方案是找到包含给定 dateTime
的 interval
的记录:
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)
甚至 Guavas CacheLoader
以便它可以自动输入值吗?
随着性能的提高,我一次最多会有 5-10 条记录,但我会从中读取很多,所以读取时间对我来说非常重要,我不确定我的一直迭代 5-10 条记录并检查每条记录的当前实现是最好的方法。
阅读路易斯写的评论后我的最终解决方案:
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;
}
}