簡體   English   中英

Java-Google Guava Multimap問題

[英]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 在這種情況下,切勿依賴自動裝箱並使用equalsintValue

您的代碼過於復雜。 您要處理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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM