最小计数草图是一种概率数据结构。最小计数草图是一种汇总大量频率数据的简单技术。最小计数草图算法讨论有关跟踪事物计数的问题。即元素在集合中存在多少次。使用HashTable或Map在Java可以很容易地找到项目的数量。
尝试使用MultiSet替代Count-min草图
让我们尝试使用带有以下源代码的MultiSet来实现此数据结构,并尝试找出这种方法的问题。
// Java program to try MultiSet as an
// alternative to Count-min sketch
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
public class MultiSetDemo {
public static void main(String[] args)
{
Multiset blackListedIPs
= HashMultiset.create();
blackListedIPs.add("192.170.0.1");
blackListedIPs.add("75.245.10.1");
blackListedIPs.add("10.125.22.20");
blackListedIPs.add("192.170.0.1");
System.out.println(blackListedIPs
.count("192.170.0.1"));
System.out.println(blackListedIPs
.count("10.125.22.20"));
}
}
输出:
了解使用MultiSet的问题
现在,让我们看一下这种方法消耗的时间和空间。
----------------------------------------------
|Number of UUIDs Insertion Time(ms) |
----------------------------------------------
|10 <25 |
|100 <25 |
|1, 000 30 |
|10, 000 257 |
|100, 000 1200 |
|1, 000, 000 4244 |
----------------------------------------------
让我们看一下所消耗的内存(空间):
----------------------------------------------
|Number of UUIDs JVM heap used(MB) |
----------------------------------------------
|10 <2 |
|100 <2 |
|1, 000 3 |
|10, 000 9 |
|100, 000 39 |
|1, 000, 000 234 |
-----------------------------------------------
我们可以很容易地理解,随着数据的增长,上述方法正在消耗大量内存和时间来处理数据。如果我们使用最小计数草图算法,可以对此进行优化。
什么是最小计数草图,它是如何工作的?
Count-min草图方法由Graham Cormode和S.Muthukrishnan提出。用2011/12年发布的最小计数草图近似数据。最小计数草图用于计数流数据上事件的频率。像Bloom过滤器一样,Count-min草绘算法也可以与哈希码一起使用。它使用多个哈希函数将这些频率映射到矩阵(此处为二维数组或矩阵的草图)。
让我们逐步看下面的示例。
- 考虑下面具有4行16列的2D数组,行数也等于哈希函数的数量。这意味着我们将以四个哈希函数为例。用零初始化/标记矩阵中的每个单元。
注意:所需的结果越准确,使用的哈希函数越多。 - 现在让我们添加一些元素。为此,我们必须将该元素与所有四个哈希函数一起传递,这可能会导致如下结果。
Input : 192.170.0.1
hashFunction1(192.170.0.1): 1 hashFunction2(192.170.0.1): 6 hashFunction3(192.170.0.1): 3 hashFunction4(192.170.0.1): 1
现在访问由所有四个哈希函数检索到的索引,并将它们标记为1。
- 类似地,通过将第二个输入传递给所有四个哈希函数来处理第二个输入。
Input : 75.245.10.1
hashFunction1(75.245.10.1): 1 hashFunction2(75.245.10.1): 2 hashFunction3(75.245.10.1): 4 hashFunction4(75.245.10.1): 6
现在,如果已将给定索引标记为1,则获取这些索引并访问矩阵。这称为碰撞,这意味着该行的索引已被先前的某些输入标记,在这种情况下,索引值没有影响在本例中,由于我们已经将第1行的索引1(即hashFunction1())由先前的输入标记为1,所以这次它将被减1,现在此单元格条目将为2,但对于其余部分其余行的索引将为0,因为没有冲突。
- 让我们处理下一个输入
Input : 10.125.22.20
hashFunction1(10.125.22.20): 3 hashFunction2(10.125.22.20): 4 hashFunction3(10.125.22.20): 1 hashFunction4(10.125.22.20): 6
让我们将其表示在矩阵上,如果已经存在某些条目,请记住将计数加1。
- 类似地处理下一个输入。
Input : 192.170.0.1
hashFunction1(192.170.0.1): 1 hashFunction2(192.170.0.1): 6 hashFunction3(192.170.0.1): 3 hashFunction4(192.170.0.1): 1
让我们看一下矩阵表示。
现在让我们测试一些元素并检查它们存在多少时间。
-
Test Input #1: 192.170.0.1
将上面的输入传递给所有四个哈希函数,并获取由哈希函数生成的索引号。
hashFunction1(192.170.0.1): 1 hashFunction2(192.170.0.1): 6 hashFunction3(192.170.0.1): 3 hashFunction4(192.170.0.1): 1
现在访问每个索引并记下该索引上存在的条目
因此,每个索引的最终条目是3,2,2,2 。现在,将这些条目中的最小数量作为结果。所以min(3,2,2,2)为2,这意味着上面的测试输入在上面的列表中被处理了两次。 -
Test Input #1: 10.125.22.20
将上面的输入传递给所有四个哈希函数,并获取由哈希函数生成的索引号。
hashFunction1(10.125.22.20): 3 hashFunction2(10.125.22.20): 4 hashFunction3(10.125.22.20): 1 hashFunction4(10.125.22.20): 6
现在访问每个索引并记下该索引上存在的条目
因此,每个索引的最终条目是1,1,1,2 。现在,将这些条目中的最小数量作为结果。所以min(1,1,1,2)为1,这意味着上面的测试输入仅在上面的列表中处理一次。
Count-min草图及其解决方案的问题:
如果一个或多个元素具有相同的哈希值,然后它们都增加,该怎么办?因此,在那种情况下,该值将由于哈希冲突而增加。因此,有时(在极少数情况下)由于哈希函数的原因,最小计数草图会高估频率。因此,我们采用的哈希函数越多,冲突就越少。我们采用的哈希函数越少,发生冲突的可能性就越大。因此,它总是建议采用更多数量的哈希函数。
数分钟草图的应用:
- 压缩感测
- 联网
- 自然语言处理
- 流处理
- 频率追踪
- 扩展:重击者
- 扩展:范围查询
使用Java的Guava库实现Count-min草图的实现:
我们可以使用Guava提供的Java库来实现Count-min草图。以下是分步实施:
- 使用以下Maven依赖项。
com.clearspring.analytics stream 2.9.5 - 详细的Java代码如下:
import com.clearspring.analytics .stream.frequency.CountMinSketch; public class CountMinSketchDemo { public static void main(String[] args) { CountMinSketch countMinSketch = new CountMinSketch( // epsilon 0.001, // delta 0.99, // seed 1); countMinSketch.add("75.245.10.1", 1); countMinSketch.add("10.125.22.20", 1); countMinSketch.add("192.170.0.1", 2); System.out.println( countMinSketch .estimateCount( "192.170.0.1")); System.out.println( countMinSketch .estimateCount( "999.999.99.99")); } }
- 上面的示例在构造函数中使用了三个参数,分别是
- 0.001 = the epsilon i.e., error rate - 0.99 = the delta i.e., confidence or accuracy rate - 1 = the seed
- 现在,让我们看一下这种方法消耗的时间和空间。
----------------------------------------------------------------------------- |Number of UUIDs | Multiset Insertion Time(ms) | CMS Insertion Time(ms) | ----------------------------------------------------------------------------- |10 <25 35 | |100 <25 30 | |1, 000 30 69 | |10, 000 257 246 | |100, 000 1200 970 | |1, 000, 000 4244 4419 | -----------------------------------------------------------------------------
- 现在,让我们看一下所消耗的内存:
-------------------------------------------------------------------------- |Number of UUIDs | Multiset JVM heap used(MB) | CMS JVM heap used(MB) | -------------------------------------------------------------------------- |10 <2 N/A | |100 <2 N/A | |1, 000 3 N/A | |10, 000 9 N/A | |100, 000 39 N/A | |1, 000, 000 234 N/A | ---------------------------------------------------------------------------
- 意见建议:
------------------------------------------------------------------------------------- |Epsilon | Delta | width/Row (hash functions)| Depth/column| CMS JVM heap used(MB) | ------------------------------------------------------------------------------------- |0.1 |0.99 | 7 | 20 | 0.009 | |0.01 |0.999 | 10 | 100 | 0.02 | |0.001 |0.9999 | 14 | 2000 | 0.2 | |0.0001 |0.99999 | 17 | 20000 | 2 | --------------------------------------------------------------------------------------
结论:
我们已经观察到,在必须以低内存消耗处理大量数据的情况下,Count-min草图是一个不错的选择。我们还看到,更精确的结果是我们需要增加哈希函数(行/宽度)的数量。