先说一下大前提
所有的判重题目一定要有一个大前提,数据是什么类型的?
如果是字符串,快速高效判重的方式都是模糊判重。想要精确判重需要记住分而治之的方式。
如果是数字,使用Roaring Bitmap可以实现精确判重。
一般的Roaring Bitmap是基于32位数字实现的,还有64位的升级版,逻辑相似。
如果对Roaring Bitmap算法不了解的,可以看下什么是Roaring Bitmap?。
直接上代码
我们先引入依赖:
<dependency>
<groupId>org.roaringbitmap</groupId>
<artifactId>RoaringBitmap</artifactId>
<version>1.3.0</version>
</dependency>
我们这里就先使用数字实现了:
final RoaringBitmap a = new RoaringBitmap();
final RoaringBitmap b = new RoaringBitmap();
final Random random = new Random(Integer.MAX_VALUE);
final int nums = 1_000_000_000;
for (int i = 0; i < nums; i++) {
a.add(random.nextInt());
b.add(random.nextInt());
}
final RoaringBitmap intersection = RoaringBitmap.and(a, b);
System.out.println("重复数量:" + intersection.getLongCardinality());
我们使用sdk中的RoaringBitmap类创建Roaring Bitmap对象,然后循环向其中加入int类型数字。
然后借助RoaringBitmap.and计算交集,交集就是重复数据。
代码是不是很简单。
有时候,我们站在前人的肩膀上,就可以快速实现一些高效的逻辑。
如果数据是字符串呢?
前面提到,如果基础数据是字符串,比如url链接判重,上面的逻辑就只能是模糊判重了。
但是如何实现呢?
其实逻辑和布隆过滤器类似,借助离散hash算法,将字符串转换为数字,然后再将数字放入到Roaring Bitmap中。
因为这种方式一定会有hash碰撞,所以结果是模糊判重。
但是在实际场景中,我们其实是可以避免出现字符串判重情况的。
比如,我们想要判断两个人看的视频或者文章的重复内容时,我们可以记录视频或文章的ID。一般来说,为了更好的DB查找,ID我们会设置成数字。
这个时候,字符串的场景直接转变为数字场景了。
所以说,有的时候,路就在那,有石头堵住了前路,就迂回过去。
“曲成万物而不遗。”这世间万物,向来都是迂回曲折、无往不复的。水能直至大海,就是因为它巧妙地避开了各种障碍,不断拐弯前行;人能走向成功,就是因为能够灵活变通,及时拐弯调头。
曲成万物而不遗
文末总结
本文借助Roaring Bitmap实现10亿数据的精确判重。
假设我们需要对10亿URL精确判重如何实现呢?我们下回接着聊。