Lucene随笔-BoomFilter布隆过滤器

lucene:6.5.1

简介

在luncene中布隆过滤器主要保存在.blm文件中,主要是用来判断特定的内容是否存在,比如在写入时判断文档id是否存在。此外,布隆过滤器只能判断特定内容肯定不存在,而不能得出肯定存在的结论。

实现

在luncene中不BloomFilter的具体实现主要是在FuzzySet。其入口为DefaultBloomFilterFactory,这里可以通过getSetForField函数获取一个布隆过滤器。这里的两个参数分别为

maxNumUniqueValues:可能存在的最大不同值的数量
desiredMaxSaturation: 包和度,接下来会具体介绍,默认为0.1


public FuzzySet getSetForField(SegmentWriteState state,FieldInfo info) {
    //Assume all of the docs have a unique term (e.g. a primary key) and we hope to maintain a set with 10% of bits set
    return FuzzySet.createSetBasedOnQuality(state.segmentInfo.maxDoc(), 0.10f);
  }

在FuzzySet.java中首先会根据输入的segment中的文档个数以及饱和度估算出一个set的容量。

 public static FuzzySet createSetBasedOnQuality(int maxNumUniqueValues, float desiredMaxSaturation)
  {
      int setSize=getNearestSetSize(maxNumUniqueValues,desiredMaxSaturation);
      return new FuzzySet(new FixedBitSet(setSize+1),setSize, hashFunctionForVersion(VERSION_CURRENT));
  }

这里的FixBitSet是一个在lucene中非常重要的数据结构。它的其中一个用途用来存储文档号,用一个bit位来描述(存储)一个文档号。该类特别适合存储连续并且没有重复的int类型的数值。最好情况可以用8个字节来描述64个int类型的值。其结构如下,我们首先探究以下FixBitset的实现原理

在这里插入图片描述

  private final long[] bits; // Array of longs holding the bits 
  private final int numBits; // The number of bits in use
  private final int numWords; // The exact number of longs needed to hold numBits (<= bits.length)

bit:存储bit的数组
numBits:参数numBits用来确定需要多少bit位来存储我们的int数值。如果我们另numBits的值为300,实际会分配一个64的整数倍的bit位。因为比300大的第一个64的倍数是 320 (64 * 5),所以实际上我们可以存储 [0 ~319]范围的数值。
numWords:表示bit数组的容量,即需要numWords的long值存储numsBit的数组

在FixBit中给我们提供了两个基本的操作函数:读取与写入

 public boolean get(int index) {
    assert index >= 0 && index < numBits: "index=" + index + ", numBits=" + numBits;
    int i = index >> 6;               // div 64
    // signed shift will keep a negative index and force an
    // array-index-out-of-bounds-exception, removing the need for an explicit check.
    long bitmask = 1L << index;
    return (bits[i] & bitmask) != 0;
  }

  public void set(int index) {
    assert index >= 0 && index < numBits: "index=" + index + ", numBits=" + numBits;
    int wordNum = index >> 6;      // div 64
    long bitmask = 1L << index;
    bits[wordNum] |= bitmask;
  }

此外BitSet还提供了用户不同BitSet之间的交并集操作。

然后我们接下来看一下FuzzySet中的插入和查询操作。

public void addValue(BytesRef value) throws IOException {    
      int hash = hashFunction.hash(value);
      if (hash < 0) {
        hash = hash * -1;
      }
      // Bitmasking using bloomSize is effectively a modulo operation.
      // 取模 (正数与取余一样,负数)
      int bloomPos = hash & bloomSize;
      filter.set(bloomPos);
  } 
  • 通过MurMurHash2生成一个int的Hash编码
  • 对BloomSize(预设的文档的数量)进行取余操作
  • filter调用add方法添加value
    整体的数据流转如下:
    在这里插入图片描述

存在的问题

生命周期

目前es主要在uid上字段上维护布隆过滤器,主要用于判定文档是否存在:

  • 数据写入时:判断是否存在
  • 数据查询时:判断id文档是否存在

创建时期:构建IndexReader时,从b1m文件中加载bit数组到内存
回收时期:在IndexReader.close内存的bit数组进行gc回收
merge:因为每个seg的bit信息时独立的因此在merge时,会读取bit信息并进行merge

对GC的影响

实验表明1亿的文档通常情况下会占用120mb左右的内存,同时会对GC产生如下影响:

  1. 小文件产生的内存碎片
  2. 大文件触发GC
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值