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% |