jedis使用scan替换keys

keys命令和scan命令区别

KEYS命令是将redis中所有的key与KEYS参数一一匹配,时间复杂度是O(N),耗费时间很少,使用也非常简单,一次性返回所有匹配的key,会阻塞服务,对服务器的性能影响较大,一般产线会禁止使用,该命令的使用方式是:KEYS PATTERN
SCAN命令是将所有的key分页处理,每次处理的条数通过参数传入,只返回少量元素处理后返回一个游标,下次请求时再携带该游标,该命令初始被设置为0时,标识服务器将开始一次新的迭代,当服务器向用户返回值为0的游标时,代表迭代已结束,该命令的使用方式:SCAN cursor [MATCH pattern] [COUNT count]

命令演示

 初始化数据

set key:1 a
set key:2 b
set key:3 c
set key:4 d
set key:5 e
set key:6 f
set key:7 g
set key:8 h
set key:9 i
set key:10 j
set key:11 k
set key:12 l
set key:13 m
set test test

 keys *匹配,可以看到会匹配返回所有满足条件的数据

LOCAL:4>keys "key:*"
 1)  "key:13"
 2)  "key:12"
 3)  "key:11"
 4)  "key:6"
 5)  "key:5"
 6)  "key:9"
 7)  "key:8"
 8)  "key:7"
 9)  "key:1"
 10)  "key:2"
 11)  "key:4"
 12)  "key:10"
 13)  "key:3"
LOCAL:4>

scan 匹配所有,先是初始化游标为0,然后依次返回,返回的第一个游标为7,下次再次从scan 7开始返回游标0代表匹配完毕,默认COUNT为10

LOCAL:4>scan 0
 1)  "7"
 2)    1)   "key:12"
  2)   "test"
  3)   "key:5"
  4)   "key:6"
  5)   "key:11"
  6)   "key:8"
  7)   "key:13"
  8)   "key:9"
  9)   "key:3"
  10)   "key:10"

LOCAL:4>scan 7
 1)  "0"
 2)    1)   "key:4"
  2)   "key:2"
  3)   "key:1"
  4)   "key:7"

LOCAL:4>

scan 匹配满足条件的元素:scan 0 MATCH *key:*,先是初始化游标为0,然后依次返回,返回的第一个游标为7,下次再次从scan 7开始返回游标0代表匹配完毕

LOCAL:4>scan 0 MATCH *key:*
 1)  "7"
 2)    1)   "key:12"
  2)   "key:5"
  3)   "key:6"
  4)   "key:11"
  5)   "key:8"
  6)   "key:13"
  7)   "key:9"
  8)   "key:3"
  9)   "key:10"

LOCAL:4>scan 7 MATCH *key:*
 1)  "0"
 2)    1)   "key:4"
  2)   "key:2"
  3)   "key:1"
  4)   "key:7"

LOCAL:4>

Scan命令的保证

SCAN命令以及其他增量式迭代命令, 在进行完整遍历的情况下可以为用户带来以下保证 :

从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的所有元素都会被完整遍历返回; 这意味着, 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。
同样,如果一个元素在开始遍历之前被移出集合,并且在遍历开始直到遍历结束期间都没有再加入,那么在遍历返回的元素集中就不会出现该元素。
然而因为增量式命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点:

同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会。

SCAN命令每次执行返回的元素数量

SCAN增量式迭代命令并不保证每次执行都返回某个给定数量的元素,甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。

不过命令返回的元素数量总是符合一定规则的, 对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;而对于一个足够小的数据集来说, 如果这个数据集的底层表示为编码数据结构(小的sets, hashes and sorted sets), 那么增量迭代命令将在一次调用中返回数据集中的所有元素。

如果需要的话,用户可以通过增量式迭代命令提供的COUNT选项来指定每次迭代返回元素的最大值。

COUNT选项

对于增量式迭代命令不保证每次迭代所返回的元素数量,我们可以使用COUNT选项, 对命令的行为进行一定程度上的调整。COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。使用COUNT 选项对于对增量式迭代命令相当于一种提示, 大多数情况下这种提示都比较有效的控制了返回值的数量。

COUNT 参数的默认值为 10 。
数据集比较大时,如果没有使用MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。
注意: **并非每次迭代都要使用相同的 COUNT 值 **,用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。

MATCH 选项

类似于KEYS 命令,增量式迭代命令通过给定 MATCH 参数的方式实现了通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素

返回值

SCAN, SSCAN, HSCAN 和 ZSCAN 命令都返回一个包含两个元素的 multi-bulk 回复: 回复的第一个元素是字符串表示的无符号 64 位整数(游标), 回复的第二个元素是另一个 multi-bulk 回复, 包含了本次被迭代的元素。

SCAN 命令返回的每个元素都是一个key。
SSCAN 命令返回的每个元素都是一个集合成员。
HSCAN 命令返回的每个元素都是一个键值对,一个键值对由一个键和一个值组成。
ZSCAN命令返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。

scala测试代码

object JedisTest {
  @throws[Exception]
  def main(args: Array[String]): Unit = {

    var jedis:Jedis = null
    try {
      val jedisPool = new JedisPool("127.0.0.1")
      jedis =jedisPool.getResource
      val key = "aos:prod:survey:signup:"
//      val key = "aos:prod:survey:signup:6:1079029543"
      val scanParams = new ScanParams().count(100).`match`("\\*")
      var cur = redis.clients.jedis.ScanParams.SCAN_POINTER_START
      var cycleIsFinished = false
      while ( !cycleIsFinished) {
        val scanResult = jedis.hscan(key, cur, scanParams)
        cur = scanResult.getCursor
        val result = scanResult.getResult
        println(result)
        //do whatever with the key-value pairs in result
//        cur = scanResult.getCursor
        if (cur == "0") cycleIsFinished = true
      }
    } catch {
      case e: Exception =>
        e.printStackTrace()
    } finally if (null != jedis) jedis.close()
  }
}

ref: http://www.redis.cn/commands/scan.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章