[英]Java - Google Guava Multimap Issue
我已經實現了一種類似於LFU的Web緩存替換算法,該算法的工作原理如下:在每個請求中,我分配的權重為1 /(p ^ reqIndex)給定,其中p是權重因子,reqIndex是請求(第一個請求)的索引,第二個請求等)。 例如,對於p = 0.5,對於第一個請求,權重為1;對於第二個請求,權重為2;對於第三個請求,權重為4,等等。然后,為了計算每個請求項的得分(我將其稱為加權頻率,weightFreq),我簡單地對相應的權重求和。 被請求的項目僅通過數字ID(整數)來區分,我將其稱為請求ID(reqID)。 例如,如果第一個請求是針對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,第二個是reqID3。在第一個請求之后,我得到:
ReqID:7,權重:[1.0]
沒關系 但是在第二個請求之后,我得到:
ReqID:7,權重:[1.0] ReqID:3,權重:[1.0,2.0]
錯了! 正確的應該是:
ReqID:7,權重:[1.0] ReqID: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方法的錯誤。 任何指導將不勝感激。
沒有真正的想法,這是怎么回事,但有太多話要說。 您一定可以修復它,只需先對其進行簡化即可。 考試
key == request.reqID
這很可能是錯誤的,因為您正在處理Integer
而不是int
。 在這種情況下,切勿依賴自動裝箱並使用equals
或intValue
。
您的代碼過於復雜。 您要處理request.reqID
的條目,因此請獲取它們:
List<Double> tempWeights = weights.get(request.reqID);
刪除外部循環和if
。
簡化更多操作,例如,使用foreach循環
for (double d : tempWeights) sum += d;
當所有不必要的東西都消失了時,您可能會立即看到問題所在。
您可能正在多線程環境中工作。 似乎可以通過引入以下內容來簡化代碼,節省內存並使計算原子化:
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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.