从基于字符串的密钥路径快速访问值

时间:2014-09-02 15:47:49

标签: java performance coldfusion hashmap

我目前正在ColdFusion 9中实现类似于数据透视的数据可视化的通用模型。

我对支持多个度量并不感兴趣,并且该模型公开了一个numeric valueAt(string colKey, string rowKey)函数,该函数可以被视图调用,以便根据列和行维度检索度量的结果聚合。

例如,对于下面的数据集,如果度量为AVG(Age)且列维度为Rank,那么model.valueOf('3', '')将返回2.33

Wine  Age Rank
WineA 3    3
WineB 4    2
WineC 2    3
WineD 2    3

现在,我自然想到的数据结构是使用java.util.HashMap来存储计算数据,使用转换为字符串作为键的列和行值的组合。这意味着根据数据集的不同,我可能会有很多以相同前缀开头的密钥。

我故意创建了一个包含多个具有相同前缀的字符串的大型数据集(100万个条目),并使用默认的java String.hashCode()算法和MurmurHash3检查了我将获得的桶冲突的百分比。 / p>

以下是我构建数据集样本的方法:

<cfset maxItemsCount = 1000000>
<cfset tokens = ['test', 'one', 'two', 'tree', 'four', 'five']>
<cfset tokensLen = arrayLen(tokens)>
<cfset items = []>
<cfset loopCount = 1>

<cfloop condition="arrayLen(items) lt maxItemsCount">
    <cfset item = ''>

    <cfloop from="1" to="#tokensLen#" index="i">
        <cfset item = listAppend(item, tokens[i] & loopCount, '_')>
        <cfset arrayAppend(items, item)>
    </cfloop>

    <cfset ++loopCount>
</cfloop>

将数组初始化为 2 * entries count ,我与 String.hashCode() 发生 27%冲突22% Murmur java.util.HashMap只花了2580毫秒来存储和检索密钥一次。

我正在寻找有关如何提高性能的想法,无论是使用不同的数据结构(可能是嵌套的哈希映射?)还是找到一种方法来减少冲突次数而不会影响API签名

谢谢!

1 个答案:

答案 0 :(得分:1)

有一百万个条目,总会有一些冲突(除非你的数组比1e12条目长得多:D)。我猜MurmurHash在这里做得很完美,但你可以尝试用MD5进行比较(这有点保证完美的工作)。

  

现在,我脑海中浮现的数据结构是使用java.util.HashMap来存储计算数据,使用转换为字符串作为键的列和行值的组合。这意味着根据数据集的不同,我可能会有很多以相同前缀开头的密钥。

你正在连接字符串,因此产生了相当多的垃圾。创建

可能更好
@Value static class Key {
    private final String row;
    private final String column;
}

作为HashMap的密钥,其中@ValueLombok注释,生成所有无聊的内容,例如equalshashCode和构造函数。< / p>

你可以轻松地在没有龙目岛的情况下轻松实现,甚至更好:

static class Key {
    Key(String row, String column) {
         // Do NOT use 31 as a multiplier as it increases the number of collisions!
         // Try Murmur, too.
         hashCode = row.hashCode() + 113 * column.hashCode();
         this.row = row;
         this.column = column;
    }

    public int hashCode() {
        return hashCode;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key that = (Key) o;
        // Check hashCode first.
        if (this.hashCode != that.hashCode) return false;
        if (!this.row.equals(that.row)) return false;
        if (!this.column.equals(that.column)) return false;
        return true;
    }

    private final int hashCode;
    private final String row;
    private final String column;
}