浏览网页以获取有关在Redis中进行数学操作的信息,但实际上并没有找到太多信息。我在Rails中使用Redis-RB gem,并缓存结果列表:
e = [1738738.0, 2019461.0, 1488842.0, 2272588.0, 1506046.0, 2448701.0, 3554207.0, 1659395.0, ...]
$redis.lpush "analytics:math_test", e
目前,我们的每个列表中的数字列表最多可达数千到数万,每天可能有数千个列表。 (实际上并没有这么多;但是,我们正在增长,并且很快会期待更大的样本量。)
对于这些列表中的每一个,我希望能够运行统计数据。我目前在应用程序中执行此操作
def basic_stats(arr)
return nil if arr.nil? or arr.empty?
min = arr.min.to_f
max = arr.max.to_f
total = arr.inject(:+)
len = arr.length
mean = total.to_f / len # to_f so we don't get an integer result
sorted = arr.sort
median = len % 2 == 1 ? sorted[len/2] : (sorted[len/2 - 1] + sorted[len/2]).to_f / 2
sum = arr.inject(0){|accum, i| accum +(i-mean)**2 }
variance = sum/(arr.length - 1).to_f
std_dev = Math.sqrt(variance).nan? ? 0 : Math.sqrt(variance)
{min: min, max: max, mean: mean, median: median, std_dev: std_dev, size: len}
end
并且,虽然我可以简单地存储统计数据,但我经常需要将列表聚合在一起以在聚合列表上运行统计数据。因此,存储原始数字而不是每个可能的聚合集合是有意义的。因此,我需要快速的数学,并一直在探索如何做到这一点。最简单的方法是在应用程序中进行,在列表中有150k项,这实际上并不太可怕:
$redis_analytics.llen "analytics:math_test", 0, -1
=> 156954
Benchmark.measure do
basic_stats $redis_analytics.lrange("analytics:math_test", 0, -1).map(&:to_f)
end
=> 2.650000 0.060000 2.710000 ( 2.732993)
虽然我不想在一次计算中按3秒钟,但鉴于这可能超出了我目前的用例大约10倍的样本量,这并不可怕。如果我们的样本量大约为100万左右怎么办?
$redis_analytics.llen("analytics:math_test")
=> 1063454
Benchmark.measure do
basic_stats $redis_analytics.lrange("analytics:math_test", 0, -1).map(&:to_f)
end
=> 21.360000 0.340000 21.700000 ( 21.847734)
使用宝石似乎对我没有任何好处。在Python中,我可能会编写一个C模块,不确定是否有许多ruby stats gems在C中。
require 'statsample'
def basic_stats(stats)
return nil if stats.nil? or stats.empty?
arr = stats.to_scale
{min: arr.min, max: arr.max, mean: arr.mean, median: arr.median, std_dev: arr.sd, size: stats.length}
end
Benchmark.measure do
basic_stats $redis_analytics.lrange("analytics:math_test", 0, -1).map(&:to_f)
end
=> 20.860000 0.440000 21.300000 ( 21.436437)
当然,很可能这样大的统计数据计算只需要很长时间,我应该将它们卸载到队列中。但是,鉴于大部分数学实际上是在Ruby / Rails中发生,而不是在数据库中,我想我可能还有其他选择。
答案 0 :(得分:4)
我希望保持这种状态,以防任何人有任何可以帮助其他人做同样事情的输入。然而,对我来说,我刚刚意识到我花了太多时间试图强迫Redis做一些SQL做得很好的事情。如果我只是将其转储到Postgres中,我可以直接在数据库中进行高效的聚合和数学运算。我想我只是坚持使用Redis的东西,当它开始时,是一个好主意,但扩展到一些不好的东西。
答案 1 :(得分:2)
你可以做的另一件事是使用Lua来设置数据,并确保它还会为每个列表更新相关的哈希类型以直接保留最小/最大/平均值,所以你不必每次都计算这些统计数据,因为它们会逐步更新。并不总是可能btw,取决于您的具体用例。
答案 2 :(得分:0)