I had a Map<Range<Double>, String>
that checks where a particular Double
value (score) is mapped to a String
(level). The end users want to be able to dynamically change this mapping, in the long term we would like for there to be a web based GUI
where they control this but for the short term they're happy for a file to be in S3
and to editing that whenever a change is needed. I don't want to hit S3
for each request and want to cache this as it doesn't change too frequently(Once a week or so). I don't want to have to make a code change and bounce my service either.
Here is what I have come up with -
public class Mapper() {
private LoadingCache<Score, String> scoreToLevelCache;
public Mapper() {
scoreToLevelCache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(new CacheLoader<Score, String>() {
public String load(Score score) {
Map<Range<Double>, String> scoreToLevelMap = readMappingFromS3(); //readMappingFromS3 omitted for brevity
for(Range<Double> key : scoreToLevelMap.keySet()) {
if(key.contains(score.getCount())) { return scoreToLevelMap.get(key); }
}
throw new IllegalArgumentException("The score couldn't be mapped to a level. Either the score passed in was incorrect or the mapping is incorrect");
}
});
}
public String getContentLevelForScore(Score Score) {
try {
return scoreToLevelCache.get(Score);
} catch (ExecutionException e) { throw new InternalServerException(e); }
}
}
The obvious problem with this approach is in the load
method when I do Map<Range<Double>, String> scoreToLevelMap = readMappingFromS3();
For each key I'm loading the entire map over and over. This isn't a performance issue but it could become one when the size increases, in any case this is not an efficient approach.
I think that keeping this entire map in the cache would be better, but I'm not sure how to do that here. Can anyone help with this or suggest a more elegant way of achieving this.
Aucun commentaire:
Enregistrer un commentaire