【问题标题】:Redis (PHP-Redis) SCAN and KEYS show different results with same patternRedis (PHP-Redis) SCAN 和 KEYS 以相同的模式显示不同的结果
【发布时间】:2023-12-22 10:27:01
【问题描述】:

我正在使用带有 Redis 版本 3.1.6 的 PHP-Redis

$result = $redis->keys('source_1234_[a-zA-Z]*_[0-9]*');

生产

{array} [6]
 0 = "source_1234_test_1"
 1 = "source_1234_test_2"
 2 = "source_1234_test_3"
 3 = "source_1234_test_4"
 4 = "source_1234_test_5"
 5 = "source_1234_test_6"

然而

$iterator = 0;
$result = $redis->scan($iterator, 'source_1234_[a-zA-Z]*_[0-9]*');

返回

FALSE

我正在阅读 KEYSSCAN 的文档,但它只说支持 glob 样式的模式。

所以检查http://www.globtester.com/ 我可以确认该模式是有效的并且应该返回正确的结果。为什么会有差异,为什么 SCAN 在这种情况下返回 FALSE?

【问题讨论】:

  • 使用redis-cli检查这些命令的输出,可能与phpredis有关。

标签: redis glob phpredis


【解决方案1】:

你的代码有两个问题:

(a) 您需要将迭代器设置为NULL,而不是0

0 从对SCAN 的调用中返回,表示已扫描所有密钥。因此它将停止并返回false

(b)SCAN 迭代所有键的集合,为每次调用返回每个集合的匹配项。你只调用一次扫描。它将扫描第一个 COUNT 键,如果它们都不匹配,则返回 false。

https://redis.io/commands/scan#number-of-elements-returned-at-every-scan-call:

SCAN 系列函数不保证每次调用返回的元素数量在给定范围内。命令也允许返回零元素,只要返回的游标不为零,客户端不应认为迭代完成。[...]

要获得与KEYS 相同的结果,您需要遍历所有键集:

$iterator = NULL
while($iterator != 0) {
    $arr_keys = $redis->scan($iterator, 'source_1234_[a-zA-Z]*_[0-9]*')
    foreach($arr_keys as $str_key) {
        echo $str_key;
    }
}

【讨论】:

  • 感谢您的回答,当我使用代码时,$arr_keys 返回一个空数组,所以永远不要进入foreach
  • 我稍微改了一下,再试一次。 14 年没做 PHP 了 :)
【解决方案2】:

试试这样的:

$redisClient = new Redis();
$redisClient->connect($config['devices']['redis_ip']);
$redisClient->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
$start_time = microtime(TRUE);
$it = NULL;
while ($keys = $redisClient->scan($it, "useragent:*")) {
    foreach ($keys as $key){
        // Do something with the key
        usleep(1000);
    }
}
$end_time = microtime(TRUE);
$time = $end_time - $start_time;
echo "\t[done]: Total time: {$time} seconds\n";
$redisClient->close();

【讨论】:

    【解决方案3】:

    因为我一直在寻找这个,所以我发布了对我有用的东西

    $iterator = null;
    while(false !== ($keys = $redis->scan($iterator, $pattern))) {
        foreach($keys as $key) {
            echo $key . PHP_EOL;
          }
     }
    

    我从scanphp-redis 的文档中获取了这个。 这应该打印与$pattern 匹配的每个键。

    【讨论】:

    • 这不会改变迭代器并且会导致无限循环,并且scan命令的返回值是一个包含2个元素的数组,第一个是下一个光标,第二个是keys ,如果没有找到键且光标为0,则返回false。
    最近更新 更多