gpt4 book ai didi

ruby-on-rails - 在 Redis 中进行高效的数学计算

转载 作者:IT王子 更新时间:2023-10-29 06:03:28 37 4
gpt4 key购买 nike

在网上寻找有关在 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 倍,所以这并不可怕。如果我们使用一百万左右的样本量会怎样?

$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)

选项

  1. 在列表上使用SORT方法,然后你可以在Redis中即时获取min/max/length。不幸的是,您似乎仍然需要在应用程序中获取诸如中位数、均值、std_dev 之类的东西。除非我们可以在 Redis 中计算这些。
  2. 使用 Lua 脚本进行计算。 (我还没有学过任何 Lua,所以不能说我知道这会是什么样子。如果它可能更快,我想知道所以我可以试试。)
  3. 使用 Ruby 的一些更有效的方法,这似乎有点不太可能,因为使用看起来相当不错的 stats gem 有类似的结果
  4. 使用不同的数据库。

使用 StatsSample gem 的示例

使用 gem 似乎对我没有任何好处。在 Python 中,我可能会编写一个 C 模块,不确定 C 中是否有很多 ruby​​ stats gems。

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 内部,而不是数据库中,我想我可能还有其他选择。

最佳答案

我想保持这个开放状态,以防任何人有任何意见可以帮助其他人做同样的事情。然而,对我来说,我刚刚意识到我花了太多时间试图强制 Redis 做一些 SQL 做得很好的事情。如果我只是将其转储到 Postgres 中,我就可以直接在数据库中进行非常高效的聚合和数学运算。我想我只是坚持使用 Redis 做一些事情,当它开始时,这是个好主意,但扩展到一些不好的地方。

关于ruby-on-rails - 在 Redis 中进行高效的数学计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12375926/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com