2017-01-26 26 views
0

私はSpring SpELでいくつかの結果を評価しています。これらの結果をキャッシュしたいので、同じパラメータで式を評価する必要はありません。グワバキャッシュで一定間隔でレコードを検索する

私のキャッシュされた鍵オブジェクト:

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)方法の使用を作りたかった。私のソリューション

@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でレコードを検索しますキャッシュ自体の値は必要に応じて、私は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

あなたのアプローチは、おそらく恋愛小説家です。 5-10のレコードを繰り返すことは基本的にはとても速くなりますが、それ以外のものは遅くなります(とにかく良い方法はないでしょう)。 –

+0

'asMap'を呼び出した後にMapエントリを反復処理すると、' cache.get'を呼び出すのとは異なる方法で期限が変わりますか?つまり、キャッシュに1つのレコードがある場合、これらの2つの呼び出しは同じです: 'cache.asMap()。entrySet()。stream().getFirst()。getValue();' 'cache.get(record);' – aturkovic

答えて

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; 
    } 
} 
関連する問題