美文网首页程序员
简化布隆过滤器——bitmap

简化布隆过滤器——bitmap

作者: Cauhnay乃东 | 来源:发表于2017-10-25 20:07 被阅读0次

前言

前段开发项目试就发现,一部分的代码实现存在着一些性能上的隐患。但当时忙于赶进度和由于卡发中的不稳定因素,想了许多解决方案也没有机会实施。最近,正好趁个机会进行一系列的改进。

我在团队开发中负责开发服务器端。所以在编写业务逻辑层时,常常遇到以下这样的业务逻辑:
1. 判断一个用户是否为在自己的好友列表中
2. 判断一条动态是否已被用户翻阅
3. 判断两个用户的标签的匹配度
4. .....等等
这些情况,我之前的方案是采用数据库来解决,为每条记录添加标记,需要查询时则遍历返回相应的集合

但是随着用户量的不断增多、各个用户之间的关系不断地增加、以及用户使用软件的一系列行为中这些情况是非常频繁的,这样频繁遍历大量的记录的读操作会给数据库带来难以承受的压力。

那么如何需找一种更好的解决方案?
既能减少数据库需要遍历的记录数量且快速索引,又能用少量的内存表示大量的数据。
其实如果我们对这一类型的业务逻辑进行抽象,可以得到:本质上就是判断一个元素是否存在于集合中
所以我们可以采用位数组,通过数组的下标能快速地定位某个元素,用bit表示相应的内容能够节省大量的空间。

但是这样结构依旧不够完美,如果数据量相对较少,数组中会存在大量的无用数据, 如长度为1024的byte数组中的只有少量位被表示为1,大量位依然是0。
此时我们可以采用游程编码压缩byte数组。如上图的游程编码后的结果可以表示为[3, 0, 2, 0, 2, 0, 1, 0 ]

bitmap介绍

bitmap:被设计为一种用bit数组来储存表示2种状态紧凑、快速索引的数据结构(当然Java的util包中也实现这类型的数据结构—BitSet(不过并不是Set))

bitmap主要原理

其实说开来,bitmap就是一个位数组而已,有着快速访问优势(下标访问),以及极小占用(用1bit来表示)

bitmap的主要设计

有点美中不足的是,Java中并没有提供bit这样的数据类型,即便是最小的数据类型byte也要占用8bit。这样就需要进行一些位运算来完成相应的操作,使得代码变得稍微复杂。
1. bitmap的内部通过byte数组实现
2. bitmap的基本操作:增删改查

    void  Set(int  position);       /* 将某位置"1" */
    boolean  Get(int  position);    /* 判断某位的值 */
    void  Clear(int  postion);      /* 将某位置"0" */

Set()的实现原理

废话不多说,直接看图



主要分为两个步骤:

  1. 先将一个byte类型的"1"左移4位,得到结果
  2. 再进行简单的或运算,得到结果并覆盖原来的值

Get()的实现原理


理解了上面的例子,相信这个应该就很简单了
同样是两步:

  1. 先将一个byte类型的"1"左移3位,得到结果
  2. 再进行与操作,得到结果并覆盖原来的值

或许这里会有些疑问,为什么不考虑用boolean?
首先,Java规范中没有强制规定boolean所占内存的大小。而且大部分计算机允许分配的最小内存单元为8bit

可以用运用bitmap解决问题的实用场景

大多可以运用的场景主要是两个方面:
这里以标签匹配为例子,开发中一个用户与各个用户之间的标签匹配度是令人头疼的问题,通过匹配标签字符串或者标签ID,这样的效果都不能太让人满意,在数据库中的保存也颇为麻烦。

一、快速索引

假如,每个用户都有一个这样小小的长度为40的byte数组,那么用户就可以用它来表示320种标签。而且能够快速的查询,通过bitarray[tag_id]这样的访问方式可以极快查到,用户是否选取了这个标签,能够快速地计算与各个用户之间的标签匹配度

二、数据压缩

那么像第一点说的那样,长度为40的byte数据便可以保存320种标签信息,但它内存大小只有40B。而且这还是没有进行游程编码压缩之前的大小

Java实现

/**
 * Created by 某拆迁大队的二哈 on 17-6-7.
 */
public class BitMap {

    public static final int DEFAULT_SIZE = 1024;

    public static final boolean EXIST = true;

    public static final boolean NULL = false;

    public static final short bits = 8;

    private byte[] bitArray;

    private int size;

    public BitMap(){
        this(DEFAULT_SIZE);
    }

    public BitMap(byte[] bitArray){
        this.size = bitArray.length * bits;
        this.bitArray = bitArray;
    }

    public BitMap(int defaultSize) {
        this.size = defaultSize * bits;
        this.bitArray = new byte[defaultSize];
    }

    public BitMap(int size, boolean elem){
        this(size);

        if(EXIST == elem) {
            for (int i = 0; i < bitArray.length; i++)
                bitArray[i] = (byte) ~bitArray[i];
        }
    }

    public int size(){
        return size;
    }

    public int index(int position){
        int idx = (position + bits - 1) / bits; 
        return idx - 1;
    }

    public int offset(int position){
        int ofs = position % 8;
        return (ofs == 0 ? ofs : 8 - ofs);
    }

    public void setBit(int position){
        if(position > size)
            return ;

        int idx = index(position);
        int ofs = offset(position);
        bitArray[idx] |= (byte)(1 << ofs);
    }

    public boolean getBit(int position){
        if(position > size)
            return false;

        int idx = index(position);
        int ofs = offset(position);
        byte tmp = (byte)(bitArray[idx] & (1 << ofs));

        return tmp != 0;
    }

    public void setBitArray(byte[] bitArray){
        this.bitArray = bitArray;
    }

    public byte[] getBitArray(){
        return bitArray;
    }

    public String byteToStr(int position){
        byte b = bitArray[index(position)];

        StringBuffer sb = new StringBuffer("");
        for(int i=bits-1; i>-1; i--)
            sb.append((byte)((b >> i) & 0x1));
        return sb.toString();
    }
}

相关文章

  • 布隆过滤器

    什么是布隆过滤器 布隆过滤器(Bloom Filter) 是一种以Bitmap为基础的排重算法。由Bitmap和一...

  • 简化布隆过滤器——bitmap

    前言 前段开发项目试就发现,一部分的代码实现存在着一些性能上的隐患。但当时忙于赶进度和由于卡发中的不稳定因素,想了...

  • BitMap工具类

    BitMap 该工具类算是布隆过滤器在数据为int时候的简化和优化版,内存可以更小,主要思路就是每个int数据对应...

  • 布隆过滤器

    布隆过滤器 布隆过滤器的原理非常简单,将要过滤的东西通过k个hash函数计算,映射到bitmap数组上(bitma...

  • Guava - 布隆过滤器的使用

    布隆过滤器简单介绍 布隆过滤器介绍 maven引入 布隆过滤器的使用 参考及拓展 Guava的布隆过滤器 布隆过滤...

  • 布隆过滤器 & BitMap

    布隆过滤器究竟是什么,这一篇给讲的明明白白的https://stor.51cto.com/art/202006/6...

  • 【布隆过滤器】

    布隆过滤器详解:以bitmap的方式,再加上多个hash函数,允许误差。https://www.jianshu.c...

  • kata05:布隆过滤器

    这次kata的内容:实现一个布隆过滤器 布隆过滤器 (Bloom Filter) 什么是布隆过滤器呢?简单来说, ...

  • SpringBoot2.x—使用Redis的bitmap实现布隆

    1. 布隆过滤器 1.1 布隆过滤器设计思想 布隆过滤器(Bloom Filter,下文简称BF)是专门用来检测集...

  • redis插件安装-bloom模块

    布隆过滤器 Redis 官方提供的布隆过滤器到了 Redis 4.0 提供了插件功能之后才正式登场。布隆过滤器作为...

网友评论

    本文标题:简化布隆过滤器——bitmap

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