【问题标题】:Fast value access from string-based key path从基于字符串的键路径快速访问值
【发布时间】:2014-09-02 15:47:48
【问题描述】:

我目前正在为 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 会得到的桶冲突的百分比。

这是我构建数据集示例的方式:

<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()22% 发生了 27% 次冲突strong> 表示 杂音java.util.HashMap 仅存储和检索一次密钥就需要大约 2580 毫秒。

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

谢谢!

【问题讨论】:

  • 这不就是使用数据库的本质吗?你为什么要重新发明轮子?
  • @ControlAltDel 如果HashMap 太慢,数据库会更慢。这没有任何意义。
  • @ControlAltDel 处理每个聚合数据,同时降低灵活性肯定会提高性能,但我描述的问题仍然存在。一旦你在内存中拥有你的立方体,你将如何尊重 API?对于模型被问到的每一个问题,你都不能点击数据库。您可以按照视图显示它的确切顺序来订购您的立方体,但是很难容纳其他类型的视图。

标签: java performance coldfusion hashmap


【解决方案1】:

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

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

您正在连接字符串,因此产生了相当多的垃圾。最好创建一个

@Value static class Key {
    private final String row;
    private final String column;
}

作为HashMap 的键,其中@ValueLombok 注释,生成所有无聊的东西,如equalshashCode 和构造函数。

没有 Lombok 也可以轻松完成,甚至更好:

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;
}

【讨论】:

    猜你喜欢
    • 2010-09-17
    • 2019-10-16
    • 2022-10-17
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    相关资源
    最近更新 更多