在番石榴缓存中查找间隔中的记录

时间:2017-01-26 23:50:01

标签: java caching guava google-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)甚至是Guavas CacheLoader,以便它可以自动输入值吗?

随着表演的进行,我一次最多会有5-10条记录,但我会从中读到很多,所以阅读时间对我来说非常重要,我不确定我的当前实现一直迭代5-10个记录并检查每个记录是最好的方法。

1 个答案:

答案 0 :(得分:0)

在阅读评论后,我的最终解决方案路易写道:

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;
    }
}