zoukankan      html  css  js  c++  java
  • BitMap算法应用:Redis队列滤重优化

    工作中有用到Redis滤重队列。

    原来的方法如下:

    方法一

    • 为了保证操作原子性,使用Redis执行Lua脚本。
    • 在脚本中的逻辑是,如果队列不超过某个数值,进行一次lrem操作(队列使用list结构),然后将新元素入列。

    优点:
    简单,直观。

    缺陷:

    1. lrem的时间复杂度为O(N),N为队列中的元素个数;所以,性能一般。
    2. 因为防止队列内容过多,防止发生N级别的删除操作,限制了一个滤重的阀值,如果超过这个阀值就不能使用滤重功能。

    方法二
    为了解决以上痛点,新玩法为:

    • 为了保证操作原子性,使用Redis执行Lua脚本。
    • 同样使用Lua脚本,排重分为两步,使用了Redis自带的二进制数组进行维护是否存在重复的状态:
      1. 在入队之前,先从二进制数组中查询下这个key是否存在,即getbit key offset。如果存在说明队列中存在一个这个offset的值,就不需要进行入队操作,直接中断执行就好。
      2. 在出队的时候,将出队的元素在二进制数组中设置为不存在,即,setbit key offset 0。

    优点:

    1. 因为是bitmap算法,在查询是否存在执行的offset的时候,时间复杂度是O(1),并且与队列中元素个数无关。
    2. 优雅,如果算是优点的话,哈哈。

    缺点:

    1. 最重要的一点是redis bitmap的offset必须是int,比如,long范围的offset是不存在的,这是一个很重要的点,一定要注意(都是血泪史)。
    2. 因为入队和出队都进行了bitmap的数据维护,所以需要确保在编码的时候一定谨慎,足够健壮。

    总结
    从上面的分析来看,感觉方法二完胜方法一。其实不尽然,只能说各有不同的场景。
    方法一比较通用,不论入队的内容是什么,都可能滤重,方法二依赖与Bitmap算法,意味key只能是数值型的元素。
    在实际应用中,以上两种滤重方式一般是可以联合使用的。如果key是数值类型,没有超出int的取值范围,那么就直接使用方法二,如果超出了int的取值范围的数值就使用方法一。

    扩展
    还有一种滤重的算法叫:布隆过滤器,感兴趣的同学可以了解下:Bloom filter。如果不需要删除,不在乎误判率的话那应该是很合适的一个算法,空间和时间都很高效。


    另外如果有人遇到过其他的一些坑或者有更好的建议,欢迎指点。

  • 相关阅读:
    windows phone 7 开发工具合集
    Windows Phone中文开发资源集中营
    Windows Phone 7 输入法升起时,保持页面不被推起
    winXP控制面板TTS语音打不开卡顿SDK开发无法播放中文解决方法MFC调用代码
    c#winform不要通过文件右键属性去复制文件路径,会复制到隐藏的字符,打印路径会看见问号,导致无法打开指定文件
    密钥读yao还是yue?
    office access accdb驱动目录注册表路径
    c#winform判断是否为数字型字符串
    c#序列化json文件为字符串更改json对象内容
    在C#HttpWebRequest 设置超时方法
  • 原文地址:https://www.cnblogs.com/liushijie/p/5450859.html
Copyright © 2011-2022 走看看