我們一起聊聊如何精確查找重復數據?
先說一下大前提
所有的判重題目一定要有一個大前提,數據是什么類型的?
如果是字符串,快速高效判重的方式都是模糊判重。想要精確判重需要記住分而治之的方式。
如果是數字,使用Roaring Bitmap可以實現(xiàn)精確判重。
一般的Roaring Bitmap是基于32位數字實現(xiàn)的,還有64位的升級版,邏輯相似。
如果對Roaring Bitmap算法不了解的,可以看下什么是Roaring Bitmap?。
直接上代碼
我們先引入依賴:
<dependency>
<groupId>org.roaringbitmap</groupId>
<artifactId>RoaringBitmap</artifactId>
<version>1.3.0</version>
</dependency>
我們這里就先使用數字實現(xiàn)了:
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類創(chuàng)建Roaring Bitmap對象,然后循環(huán)向其中加入int類型數字。
然后借助RoaringBitmap.and計算交集,交集就是重復數據。
代碼是不是很簡單。
有時候,我們站在前人的肩膀上,就可以快速實現(xiàn)一些高效的邏輯。
如果數據是字符串呢?
前面提到,如果基礎數據是字符串,比如url鏈接判重,上面的邏輯就只能是模糊判重了。
但是如何實現(xiàn)呢?
其實邏輯和布隆過濾器類似,借助離散hash算法,將字符串轉換為數字,然后再將數字放入到Roaring Bitmap中。
因為這種方式一定會有hash碰撞,所以結果是模糊判重。
但是在實際場景中,我們其實是可以避免出現(xiàn)字符串判重情況的。
比如,我們想要判斷兩個人看的視頻或者文章的重復內容時,我們可以記錄視頻或文章的ID。一般來說,為了更好的DB查找,ID我們會設置成數字。
這個時候,字符串的場景直接轉變?yōu)閿底謭鼍傲恕?/p>
所以說,有的時候,路就在那,有石頭堵住了前路,就迂回過去。
“曲成萬物而不遺。”這世間萬物,向來都是迂回曲折、無往不復的。水能直至大海,就是因為它巧妙地避開了各種障礙,不斷拐彎前行;人能走向成功,就是因為能夠靈活變通,及時拐彎調頭。
曲成萬物而不遺
文末總結
本文借助Roaring Bitmap實現(xiàn)10億數據的精確判重。
假設我們需要對10億URL精確判重如何實現(xiàn)呢?我們下回接著聊。