0.1, "b" => 0.2, "-6ren">
gpt4 book ai didi

ruby-on-rails - 我如何在 Ruby on Rails 中使用 Redis 来有效地获取两个哈希的点积

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

我在名为token_vector(哈希)的功能表中的数据库中有一个这样的数据结构:

Feature.find(1).token_vector = { "a" => 0.1, "b" => 0.2, "c" => 0.3 }

这些功能中有 25 个。首先,我在 script/console 中将数据输入到 Redis 中:

REDIS.set(  "feature1",
"#{ TokenVector.to_json Feature.find(1).token_vector }"
)
# ...
REDIS.set( "feature25",
"#{ TokenVector.to_json Feature.find(25).token_vector }"
)

TokenVector.to_json 首先将哈希值转换为 JSON 格式。存储在 Redis 中的 25 个 JSON 哈希大约占用 8 MB。

我有一个方法,叫做Analysis#locate。此方法采用两个 token_vectors 之间的点积。哈希的点积是这样工作的:

hash1 = { "a" => 1, "b" => 2, "c" => 3 }
hash2 = { "a" => 4, "b" => 5, "c" => 6, "d" => 7 }

散列中的每个重叠键(在本例中为 a、b 和 c,而不是 d)将它们的值成对相乘,然后相加。

hash1a的值为1,hash2a的值为4。这些得到 1*4 = 4

hash1b的值为2,hash2b的值为5。这些得到 2*5 = 10

hash1c的值为3,hash2c的值为6。这些得到 3*6 = 18

hash1d的值不存在,hash2d的值为7。在这种情况下,为第一个散列设置 d = 0。将这些相乘得到 0*7 = 0

现在将相乘的值相加。 4 + 10 + 18 + 0 = 32。这是 hash1 和 hash2 的点积。

Analysis.locate( hash1, hash2 ) # => 32

我有一个经常使用的方法,Analysis#topicize。这个方法接受一个参数,token_vector,它只是一个散列,类似于上面。 Analysis#topicize 获取 token_vector 和 25 个特征的 token_vectors 中的每一个的点积,并创建这 25 个点积的新向量,称为 feature_vectorfeature_vector 只是一个数组。代码如下所示:

def self.topicize token_vector

feature_vector = FeatureVector.new

feature_vector.push(
locate( token_vector, TokenVector.from_json( REDIS.get "feature1" ) )
)
# ...
feature_vector.push(
locate( token_vector, TokenVector.from_json( REDIS.get "feature25" ) )
)

feature_vector

end

如您所见,它采用我在上面输入到 Redis 中的 token_vector 和每个特征的 token_vector 的点积,并将值压入数组。

我的问题是,每次调用该方法都需要大约 18 秒。我在滥用 Redis 吗?我认为问题可能是我不应该将 Redis 数据加载到 Ruby 中。我是否应该向 Redis 发送数据 (token_vector) 并编写一个 Redis 函数让它执行 dot_product 函数,而不是用 Ruby 代码编写它?

最佳答案

您必须分析它才能确定,但​​我怀疑您在序列化/反序列化 JSON 对象上浪费了很多时间。与其将token_vector转成JSON字符串,不如直接放到Redis中,因为Redis有its own hash type

REDIS.hmset "feature1",   *Feature.find(1).token_vector.flatten
# ...
REDIS.hmset "feature25", *Feature.find(25).token_vector.flatten

Hash#flatten 所做的是将像 { 'a' => 1, 'b' => 2 } 这样的散列转换成像 [ 'a', 1, 'b', 2 ],然后我们使用 splat (*) 将数组的每个元素作为参数发送给 Redis#hmset(“hmset”中的“m”表示“多个”,如“一次设置多个哈希值”)。

然后当你想取回它时使用 Redis#hgetall,它会自动返回一个 Ruby 哈希:

def self.topicize token_vector
feature_vector = FeatureVector.new

feature_vector.push locate( token_vector, REDIS.hgetall "feature1" )
# ...
feature_vector.push locate( token_vector, REDIS.hgetall "feature25" )

feature_vector
end

但是!由于您只关心散列中的值,而不关心键,因此您可以使用 Redis#hvals 来简化事情,它只返回值的数组,而不是 hgetall.

您可能花费大量周期的第二个地方是 locate,您没有提供源代码,但是有很多方法可以在 Ruby 中编写点积方法其中一些比其他的性能更高。 This ruby-talk thread涵盖了一些有值(value)的领域。其中一张海报指向NArray ,一个用 C 语言实现数值数组和向量的库。

如果我正确理解你的代码,它可以像这样重新实现(前提条件:gem install narray):

require 'narray'

def self.topicize token_vector
# Make sure token_vector is an NVector
token_vector = NVector.to_na token_vector unless token_vector.is_a? NVector
num_feats = 25

# Use Redis#multi to bundle every operation into one call.
# It will return an array of all 25 features' token_vectors.
feat_token_vecs = REDIS.multi do
num_feats.times do |feat_idx|
REDIS.hvals "feature#{feat_idx + 1}"
end
end

pad_to_len = token_vector.length

# Get the dot product of each of those arrays with token_vector
feat_token_vecs.map do |feat_vec|
# Make sure the array is long enough by padding it out with zeroes (using
# pad_arr, defined below). (Since Redis only returns strings we have to
# convert each value with String#to_f first.)
feat_vec = pad_arr feat_vec.map(&:to_f), pad_to_len

# Then convert it to an NVector and do the dot product
token_vector * NVector.to_na(feat_vec)

# If we need to get a Ruby Array out instead of an NVector use #to_a, e.g.:
# ( token_vector * NVector.to_na(feat_vec) ).to_a
end
end

# Utility to pad out array with zeroes to desired size
def pad_arr arr, size
arr.length < size ?
arr + Array.new(size - arr.length, 0) : arr
end

希望对您有所帮助!

关于ruby-on-rails - 我如何在 Ruby on Rails 中使用 Redis 来有效地获取两个哈希的点积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7544207/

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