Java - Google Guava Multimap 问题

标签 java guava multimap

我已经实现了一个类似 LFU 的网络缓存替换算法,其工作原理如下:在每个请求中,我分配一个由 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 (第一个请求的权重 + 第三个请求的权重)而 ID 为 3 的项目应该有一个分数 2(第二个请求的权重)。

我使用 ListMultimap(通过 Google Guava 库)作为权重,因为我应该能够为单个键 (reqID) 设置多个值(权重):

/** ListMultimap of reqID (K) and weights (V) */
private ListMultimap<Integer, Double> weights;

我为分数使用了一个简单的 map :

/** 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。在第一个请求之后,我得到:

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 个月左右才开始学习编程,这是我第一次不得不使用多重映射(因为我需要为单个键分配多个值)。我从这里得到了这样做的想法和相关信息:

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;

当所有不需要的东西都消失后,您可能会立即发现问题。

关于Java - Google Guava Multimap 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20512718/

相关文章:

java - Guava EventBus 中的注解与接口(interface)

java - 处理中的多图

java - 使用任务更新javafx UI而不使用Platform.RunLater

java - Spring Integration DSL - 可访问 header 的出站网关

java - 如何将函数应用于每个集合元素以便在 Guava 中对其进行变异?

java - 如何获取嵌套 `ArrayListMultimap`中的值

c++ - std::multimap<key, value> 和 std::map<key, std::set<value>> 有什么区别

java - 序列化一个java对象

java - Jodd可以提供像apachetiles框架这样的功能吗?

java - 如何模拟多参数副作用函数