Edited at

Redisのsrandmemberがおかしい

More than 3 years have passed since last update.


Redisのsrandmemberのバラつきがおかしい


現象

Redisのセット型の関数にsrandmemberがありますが、この関数のバラつき型がおかしい事に気付いたので、備忘録代わりに。


どういう時におかしくなるのか


  • キーが数値の場合には問題が無い。

  • キーが文字列に確率がおかしくなる。

  • キーが文字列でも確率がおかしくならない場合がある。

  • 文字列のときの条件はわからない。(そこまで調べる気もあまりない

  • キーは数値を使った方がいいよ


再現コード


sample.pl

#!/usr/bin/env perl

use 5.16.2;
use strict;
use warnings;
use utf8;

use Redis::Fast;

my $redis = Redis::Fast->new;

my $elements_count = 5;
my $try_count = 1000;
my $result;

$redis->del("test");
$result = {};

say "### 要素数 $elements_count 数値の場合";
say "|キー名|取得数|確率|";
say "| ---- | ---- | ---- |";
$redis->sadd("test" , $_) for 1..$elements_count;
$result->{$redis->srandmember("test")}++ for 1..$try_count;
for(1..$elements_count){
say "|" . (join " | " , sprintf("%-4s", $_) , sprintf("%-3s" , $result->{$_}) , (100 * $result->{$_} / $try_count) . "%") . "|";
}

$redis->del("test");
$result = {};

say "";
say "### 要素数 $elements_count 文字列の場合";
say "キー名|取得数|確率";
$redis->sadd("test" , "test$_") for 1..$elements_count;
$result->{$redis->srandmember("test")}++ for 1..$try_count;
for(1..$elements_count){
say "|" . (join " | " , sprintf("%-8s", "test$_") , sprintf("%-3s" , $result->{"test$_"}) , (100 * $result->{"test$_"} / $try_count) . "%") . "|";
}



結果


  • 要素数5個,試行回数は1000回の時、文字列の場合の取得確率が均等になっていない

  • 要素数10個,試行回数は1000回の時、文字列の取得が均等になっている

  • 要素数20個,試行回数10万回の時、均等になっていない


要素数 5 数値の場合

キー名
取得数
確率

1
195
19.5%

2
209
20.9%

3
209
20.9%

4
195
19.5%

5
192
19.2%


要素数 5 文字列の場合

キー名
取得数
確率

test1
125
12.5%

test2
128
12.8%

test3
249
24.9%

test4
231
23.1%

test5
267
26.7%


要素数 10 数値の場合

キー名
取得数
確率

1
107
10.7%

2
91
9.1%

3
103
10.3%

4
82
8.2%

5
103
10.3%

6
93
9.3%

7
103
10.3%

8
127
12.7%

9
94
9.4%

10
97
9.7%


要素数 10 文字列の場合

キー名
取得数
確率

test1
106
10.6%

test2
103
10.3%

test3
107
10.7%

test4
96
9.6%

test5
89
8.9%

test6
99
9.9%

test7
103
10.3%

test8
78
7.8%

test9
95
9.5%

test10
124
12.4%


要素数 20 数値の場合

キー名
取得数
確率

1
5035
5.035%

2
5051
5.051%

3
5050
5.05%

4
4951
4.951%

5
5148
5.148%

6
5082
5.082%

7
5073
5.073%

8
5022
5.022%

9
4922
4.922%

10
4983
4.983%

11
4870
4.87%

12
4929
4.929%

13
4897
4.897%

14
4924
4.924%

15
4993
4.993%

16
4951
4.951%

17
5056
5.056%

18
5024
5.024%

19
4965
4.965%

20
5074
5.074%


要素数 20 文字列の場合

キー名
取得数
確率

test1
6699
6.699%

test2
6560
6.56%

test3
3384
3.384%

test4
3383
3.383%

test5
6593
6.593%

test6
6684
6.684%

test7
6565
6.565%

test8
3331
3.331%

test9
6644
6.644%

test10
6785
6.785%

test11
2255
2.255%

test12
3359
3.359%

test13
6690
6.69%

test14
6740
6.74%

test15
3380
3.38%

test16
2193
2.193%

test17
6681
6.681%

test18
6640
6.64%

test19
3232
3.232%

test20
2202
2.202%