【问题标题】:Speeding up my implementation of HyperLogLog algorithm加快我对 HyperLogLog 算法的实现
【发布时间】:2014-07-04 09:31:48
【问题描述】:

我自己实现了HyperLogLog algorithm。它运行良好,但有时我必须获取大量(大约 10k-100k)的 HLL 结构并将它们合并。

我将它们中的每一个都存储为一个位串,因此首先我必须将每个位串转换为存储桶。由于有很多 HLL,它需要的时间比我想要的要多。

目前大约 80% 的运行时需要为每个 HLL 调用一次这行代码:

my @buckets = map { oct '0b'.$_ } unpack('(a5)1024', $bitstring);

有什么方法可以更快?

如果我们留下 HyperLogLog 的定义,任务可以这样解释:假设 $bitstring 由 1024 个 5 位计数器组成(因此每个计数器的值最多为 32),我们必须将其转换为 1024 的数组整数。

【问题讨论】:

  • 你能提供几个 $bitstring 的例子吗?还有运行需要多长时间,什么是可以接受的?
  • @michael,它是一个字符串,简单如“101011...”等。它的长度是5120个符号。
  • 请注意,这里有一个 cpan 模块:Algorithm::HyperLogLog
  • @Miller 谢谢,不知道。有趣的是,它确实通过文件导出和导入,与 Bloom::Faster 相同。因此,我也不得不制作自己的布隆过滤器。他们到底在想什么?为什么不给我一个可以存储在任何我想要的地方的字符串?我的blooms和hlls都使用Redis而不是文件,考虑到Redis位操作和Lua脚本,这非常方便(我知道Redis有内置的HLL,但它们对我来说太大了)。

标签: perl pack unpack hyperloglog


【解决方案1】:

a 表示任意的零填充二进制数据。在这里,您将该数据视为 ASCII 文本,但它只能包含 10!这是低效的,因为a5 最终使用了五个字节。最简单、最有效的解决方案是为每个计数器存储一个 8 位数字,然后:my @buckets = unpack 'C1024', $bitstring

如果您只想为每个计数器存储 5 位,那么您最终会节省很少的内存,非常麻烦。您必须使用像这样疯狂的东西来进行往返转换:

my $bitstring = pack "(b5)1024", map { sprintf "%b", $_ } @buckets;
@buckets = map { oct "0b$_" } unpack "(b5)1024", $bitstring;

【讨论】:

  • “最简单和最有效的解决方案是为每个计数器存储一个 8 位数字” - 这是有道理的。我是说我最多可以有 36k HLL,这不算太多,所以我可以再增加 40% 的内存;但后来我意识到这是一个错误,实际上在当前的实现中我可能拥有多达数亿个 :) 我应该回到绘图板... %)
  • 所以,在画板之前多花一分钱 - “解压'C1024'”实际上至少快了 4 倍。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-10-28
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多