1
votes

I am using PHP-Redis with Redis Version 3.1.6

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

produces

{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"

However

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

returns

FALSE

I am reading the docs for KEYS and SCAN but all it says it that supports glob-style patterns.

So checking http://www.globtester.com/ I can confirm that the pattern is valid and should return the correct results. Why is there a difference and why does SCAN return FALSE in this case?

3
check the output of those commands using redis-cli, it's probably related to the phpredis. - Evhz

3 Answers

2
votes

Two problems with your code:

(a) You need to set the iterator to NULL, not 0.

0 is returned from the call to SCAN to indicate that all keys have been scanned. It will therefore stop and return false.

(b) SCAN iterates over sets of all keys, returning the matches from each set for each call. You're only calling scan once. It will scan the first COUNT keys and return false if none of those happen to match.

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

SCAN family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero.[...]

To get identical results to KEYS you need to iterate over all sets of 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;
    }
}
2
votes

Try something like that:

$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();
1
votes

Since I was looking for this, I'm posting what worked for me

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

I took this from the documentation of scan of php-redis. This should print every key matching the $pattern.