scan指定match参数,数据中确实存在匹配的key,为什么返回的是空
问题描述
如下图所示,数据库中存在key为test的数据,用scan match的方式却没有返回这个数据。
139.9.177.148:8635> scan 1 match tes* 1) "21" 2) (empty list or set) 139.9.177.148:8635> get test "abc" 139.9.177.148:8635>scan 0 match tes* 1) "21" 2) (empty list or set) 139.9.177.148:8635>
问题分析
MATCH选项让命令只返回和给定模式相匹配的元素, 对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 如果取出的元素都和模式不匹配,则不会返回任何元素。
解决方案
多次scan,以返回的游标值是否为0作为全遍历结束的标记,每次scan时使用上次scan返回的游标值。
相关知识
- SCAN命令的基本用法
SCAN cursor [MATCH pattern] [COUNT count]
SCAN命令是一个基于游标的迭代器(cursor based iterator)。SCAN命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN命令的游标参数, 以此来延续之前的迭代过程。
当SCAN命令的游标参数被设置为0时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为0的游标时, 表示迭代已结束。
redis 127.0.0.1:6379> scan 0 1) "17" 2) 1) "key:12" 2) "key:8" 3) "key:4" 4) "key:14" 5) "key:16" 6) "key:17" 7) "key:15" 8) "key:10" 9) "key:3" 10) "key:7" 11) "key:1" redis 127.0.0.1:6379> scan 17 1) "0" 2) 1) "key:5" 2) "key:18" 3) "key:0" 4) "key:2" 5) "key:19" 6) "key:13" 7) "key:6" 8) "key:9" 9) "key:11"
在上面这个例子中, 第一次迭代使用0作为游标, 表示开始一次新的迭代。
第二次迭代使用的是第一次迭代时返回的游标, 即命令回复第一个元素的值 :17 。
从上面的示例可以看到, SCAN命令的回复是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素。
在第二次调用SCAN命令时, 命令返回了游标0 , 这表示迭代已经结束, 整个数据集(collection)已经被完整遍历过了。
以0作为游标开始一次新的迭代, 一直调用SCAN命令, 直到命令返回游标0, 我们称这个过程为一次完整遍历(full iteration)。
- COUNT选项
虽然增量式迭代命令不保证每次迭代所返回的元素数量, 但我们可以使用COUNT选项, 对命令的行为进行一定程度上的调整。
基本上,COUNT选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。 COUNT参数的默认值为10。
并非每次迭代都要使用相同的COUNT值。
用户可以在每次迭代中按自己的需要随意改变COUNT值, 只要记得将上次迭代返回的游标用到下次迭代里面。
- MATCH选项
MATCH选项让命令只返回和给定模式相匹配的元素,以下是一个使用MATCH选项进行迭代的示例。
redis 127.0.0.1:6379> mset foo a foobar b feelsgood c bar d (integer) 4 redis 127.0.0.1:6379> scan 0 match f* 1) "0" 2) 1) "foo" 2) "feelsgood" 3) "foobar"
需要注意的是, 对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。
以下是这种情况的一个例子。
redis 127.0.0.1:6379> scan 0 MATCH *11* 1) "288" 2) 1) "key:911" redis 127.0.0.1:6379> scan 288 MATCH *11* 1) "224" 2) (empty list or set) redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 1) "0" 2) 1) "key:611" 2) "key:711" 3) "key:118" 4) "key:117" 5) "key:311" 6) "key:112" 7) "key:111" 8) "key:110" 9) "key:113" 10) "key:211" 11) "key:411" 12) "key:115" 13) "key:116" 14) "key:114" 15) "key:119" 16) "key:811" 17) "key:511" 18) "key:11"
以上的大部分迭代都不返回任何元素。 在最后一次迭代, 我们通过将COUNT选项的参数设置为1000 , 强制命令为本次迭代扫描更多元素, 从而使得命令返回的元素也变多了。