美文网首页架构师JAVA
海量数据下的去重和查重(一):BitMap位图法

海量数据下的去重和查重(一):BitMap位图法

作者: 雪飘千里 | 来源:发表于2020-01-06 12:13 被阅读0次

在一些海量数据的场景中,做一些查重、去重、排序,一般的方法难以实现,因为内存占用太大了,比如以下问题:

问题一:10亿个正整数,给定一个数值,如何快速判定该数值是否在10亿个正整数当中?假如机器只有1G内存?

问题二:比如说是一组数字,它是保存在一个很大的文件中。它总体的个数为400亿个,里面有大量重复的数据,如果去除重复的元素之后,大概的数据有40个亿,那么,假定我们有一台内存为2GB的机器。我们该如何来消除其中重复的元素呢?再进一步考虑,如果我们消除了重复的元素之后,怎么统计里面元素的个数并将去重后的元素保存到另外的一个结果文件里呢?

我们来估计一下上面所需要用到的内存,1G 约等于 10^9(10的9次方)个字节,上面的数字都是int型,一个int 占用4字节,所以问题一可能需要占用4G内存,而问题二中,需要占用16G内存,显然需要的内存太大了,传统的方法是不能用了,这时候就需要引出今天的主角了——BitMap位图法。

1、思想

位图法的思想类似于hash寻址,首先初始化一个int数组,每个元素对应32位比特(一个int 占用4字节,1字节8个比特位),将10亿个元素分别读入内存,对int数组中的元素比特位进行标记,如果存在,标记为1即可。标记完之后,即可快速判定某个元素是否在10亿个正整数当中,时间复杂度为O(1)。

image.png

原先一个int类型只能表示一个整数,现在一个int能表示32个整数,相当于是节省了32倍的内存。

那么具体我们是怎么操作??

  • 寻址
    比如元素 119,如何确定其对应的数组比特位 index ?
    1)确定数组 arrayIndex :119/32 = 3,也就是第 4 个数组元素,a[3] 的位置。——num >> 5(num右移5位,相当于是除以2的5次方);
    2)确定比特位 bitIndex:119%32 = 23,第23个比特位。—— num & 31
  • 设置比特位
    • 将比特位设置为1
      bigArray[arrayIndex] |= 1 << bitIndex(1左移到目标位置,然后进行或运算);
    • 将比特位设置为0
      bigArray[arrayIndex] &= ~(1 << bitIndex);(1左移到目标位置,然后取反,然后再进行与运算);
  • 判断某一元素是否存在
    只需将 1 左移bitIndex位数,然后与原来的值进行与运算。只要与运算结果中有1,即表示元素存在。所以可以用运行结果是不为0作为元素是否存在依据。

2、实现

2.1 自定义实现
import java.util.BitSet;

public class bitMap {
        private int[] bigArray;

        public bitMap(long  size){
            bigArray = new int[(int) (size/ 32 + 1)];
        }

        public void set1(int  num){
            //确定数组 index
            int arrayIndex = num >> 5;
            //确定bit index
            int bitIndex = num & 31;
            //设置0
            bigArray[arrayIndex] |= 1 << bitIndex;
        }

        public void set0(int  num){
            //确定数组 index
            int arrayIndex = num >> 5;
            //确定bit index
            int bitIndex = num & 31;
            //设置0
            bigArray[arrayIndex] &= ~(1 << bitIndex);
            System.out.println(get32BitBinString(bigArray[arrayIndex]));
        }

        public boolean isExist(int  num){
            //确定数组 index
            int arrayIndex = num >> 5;
            //确定bit index
            int bitIndex = num & 31;

            //判断是否存在
            return (bigArray[arrayIndex] & (1 << bitIndex))!=0 ? true : false;
        }

        /**
         * 将整型数字转换为二进制字符串,一共32位,不舍弃前面的0
         * @param number 整型数字
         * @return 二进制字符串
         */




    private static String get32BitBinString(int number) {
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < 32; i++){
            sBuilder.append(number & 1);
            number = number >>> 1;
        }
        return sBuilder.reverse().toString();
    }

    public static void main(String[] args) {

        int[] arrays = new int[]{1, 2, 35, 22, 56, 334, 245, 2234, 54};

        bitMap bigMapTest = new bitMap(2234-1);

        for (int i : arrays) {
            bigMapTest.set1(i);
        }
        System.out.println(bigMapTest.isExist(36));
    }

}
2.1 jdk实现

在java.util包中有个BitSet类也是用同样的思想实现的,不过BitSet的底层实现是long数组(long是64位,占用8个字节)。

public class BitSetTest {

    public static void main(String[] args) {
        int [] array = new int [] {1,2,3,22,0,3,63};
        BitSet bitSet  = new BitSet(1);
        System.out.println(bitSet.size());   //64
        bitSet  = new BitSet(65);
        System.out.println(bitSet.size());   //128
        bitSet  = new BitSet(23);
        System.out.println(bitSet.size());   //64

        //将数组内容组bitmap
        for(int i=0;i<array.length;i++)
        {
            bitSet.set(array[i], true);
        }

        System.out.println(bitSet.get(22));
        System.out.println(bitSet.get(60));

        System.out.println("下面开始遍历BitSet:");
        for ( int i = 0; i < bitSet.size(); i++ ){
            System.out.println(bitSet.get(i));
        }
    }

}

3、优缺点

  • 优点:是海量数据下去重时,用这种数据结构可以大量的节省空间;
  • 缺点:
      1. 空间占用大小是根据最大值来的,如果数据量本身不多,但是最大值特别大,那不但不会节省空间,反而会浪费空间
      1. 功能有限,由于bit位只能是0和1,所以只能用于去重和查重,如果要统计每个元素出现的个数,就不能实现了。

相关文章

  • 海量数据下的去重和查重(二):布隆过滤器

    在上篇文章海量数据下的去重和查重(一):BitMap位图法的最后,我们说到位图法缺点,是其所占空间随集合内最大元素...

  • 海量数据下的去重和查重(一):BitMap位图法

    在一些海量数据的场景中,做一些查重、去重、排序,一般的方法难以实现,因为内存占用太大了,比如以下问题: 问题一:1...

  • 海量数据去重-精确去重[Bitmap]

    假如我们使用Bitmap(或称BitSet)储存,定义一个很大的bitmap数组,每个元素对应Bitmap中的1位...

  • 位图索引&布隆过滤器

    位图索引 位图法就是Bitmap的缩写。所谓Bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态...

  • 精确去重和Roaring BitMap (咆哮位图)

    基本概念 Roaring BitMap 以下简称 RBM,中文翻译为咆哮位图,它本质上是定义了一个很大的 bit ...

  • 海量数据去重

    一个文件中有40亿条数据,每条数据是一个32位的数字串,设计算法对其去重,相同的数字串仅保留一个,内存限制1G. ...

  • T1.3 Excel-Data Cleansing

    数据清洗 查重去重 缺失值定位与处理 检测数据逻辑 3.1 查询重复数据 A 函数法: COUNTIF(range...

  • BitMap位图使用

    原理介绍: 位图(BitMap), 可以使用极少的空间来标记海量的数据。底层是一个bit数组,使用0和1来标记数据...

  • 常用的算法和数据结构

    常用数据结构 bitmap 通过位图结构存储是否类型的海量数据,非常节约内存,同时查询、维护性能极高。 常用算法 ...

  • 【直通BAT】海量数据面试总结

    目录 海量数据计算总结 海量数据去重总结 1. 计算容量 在解决问题之前,要先计算一下海量数据需要占多大的容量。常...

网友评论

    本文标题:海量数据下的去重和查重(一):BitMap位图法

    本文链接:https://www.haomeiwen.com/subject/vpthoctx.html