我已经实现了类似LFU的Web缓存替换算法,其工作方式如下:在每个请求中,我分配一个由1 /(p ^ reqIndex)给出的权重,其中p是权重因子,reqIndex是请求的索引(第1次请求,第2次请求等)。例如,当p = 0.5时,第1次请求的权重为1,第2次请求为2,第3次为4等。然后为了计算每个请求项目的得分(我称之为加权频率,weightFreq),我只是加上相应的权重。请求的项目仅通过我称为请求ID(reqID)的数字ID(整数)来区分。例如,如果第一个请求是针对ID为7的项目,第二个针对ID为3的项目,而第三个请求针对ID为7的项目,则ID为7的项目应为1 + 4 = 5 (第1次请求的权重+第3次请求的权重),ID为3的项目的得分为2(第2次请求的权重)。
我使用ListMultimap(通过Google Guava库)来获得权重,因为我应该能够为单个键(reqID)提供多个值(权重):
/** ListMultimap of reqID (K) and weights (V) */
private ListMultimap<Integer, Double> weights;
我使用简单的地图分数:
/** Map of reqID (K) and weightFreq (V) */
private Map<Integer, Double> weightFreqs;
这是getter方法,我计算并返回所请求项目的分数:
/**
* Getter for weighted frequency of the requested item
* @param request The requested item
* @param reqIndex The index of the request
* @return this.weightFreqs.get(request.reqID) weightFreq of the req. item
*/
public double getWeightFreq(Request request, int reqIndex) {
// initialize weightFreq
initWeightFreqs(request);
// calculate weight
weight = Math.pow(1/p, reqIndex);
// put request along with its weight to the weights ListMultimap
weights.put(request.reqID, weight);
// scan keys of weights list-multimap
for(Integer key : this.weights.keySet()) {
// if the key is the requested item
if (key == request.reqID) {
// list of all weights for this key (reqID)
List<Double> tempWeights = weights.get(key);
// test
logger.info("List of weights for request with ID: " +
request.reqID + " is: " + tempWeights);
// sum of those weights
int sum = 0;
// scan the list
for(int i = 0; i < tempWeights.size(); i++) {
// sum the weights
sum += tempWeights.get(i);
}
// assign the sum to the weightFreq value
weightFreq = sum;
// put reqID along with its weightFreq into weightFreqs map
weightFreqs.put(request.reqID, weightFreq);
}
}
// return weightFreq of requested item
return this.weightFreqs.get(request.reqID);
}
如您所见,我包含了测试打印(每个reqID的权重列表)以检查代码。现在看看运行代码时会发生什么。同样的例子,第一个请求是reqID 7,第二个请求是reqID 3.第一个请求后我得到:
请求:7,权重:[1.0]
没关系。但在第二次请求后我得到了:
需求:7,重量:[1.0] 请求:3,权重:[1.0,2.0]
哪个错了!正确的应该是:
需求:7,重量:[1.0] 请求:3,权重:[2.0]
因此,我得到reqID 3的得分(weightFreq)等于3(1 + 2)而不是2,这是正确的。
请注意,我仅在过去7个月左右的时间内学习编程,这是我第一次使用multimap(因为我需要为单个键分配多个值)。我从这里得到了这样做的想法和相关信息:
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Multimap.html
它描述了多图的几种不同实现(ListMultimap,SetMultimap等),可以选择使用集合图或asMap通过Google Guava等来做同样的事情。
我不确定我是否理解了有关多重映射的错误,或者我的逻辑中有关于之前的getter方法的错误。任何指导将不胜感激。
答案 0 :(得分:1)
不知道这里发生了什么,但是评论太多了。你可以肯定地修复它,只是先简化它。测试
key == request.reqID
很可能是错误的,因为您处理的是Integer
而不是int
。在这种情况下,永远不要依赖自动(联合)拳击并使用equals
或intValue
。
您的代码过于复杂。你想处理request.reqID
的条目,所以得到它们:
List<Double> tempWeights = weights.get(request.reqID);
删除外部循环和if
。
简化更多,例如,使用foreach循环
for (double d : tempWeights) sum += d;
当所有不必要的东西都消失了,你可能会立即看到问题。
答案 1 :(得分:0)
您可能在多线程环境中工作。看起来你可以简化代码,节省内存,并通过引入:
使你的计算成为原子ConcurrentHashMap<Integer, RequestInfo> map = new ConcurrentHashMap<>();
class RequestInfo{
double weight;
List<Double> frequencies; // consider using TDoubleArrayList from Trove4j
// for efficiency
public synchronized addFrequency(double freq){
...
}
}
然后使用map.putIfAbsent
进行空RequestInfo
的原子插入。