У меня есть такая структура данных в базе данных в таблице функций с именем token_vector
(хэш):
Feature.find(1).token_vector = { "a" => 0.1, "b" => 0.2, "c" => 0.3 }
Таких функций 25. Сначала я ввел данные в Redis с помощью этого в script/console
:
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. 25 хэшей JSON, хранящихся в Redis, занимают около 8 МБ.
У меня есть метод под названием Analysis#locate
. Этот метод берет скалярное произведение двух векторов token_vector. Скалярный продукт для хэшей работает следующим образом:
hash1 = { "a" => 1, "b" => 2, "c" => 3 }
hash2 = { "a" => 4, "b" => 5, "c" => 6, "d" => 7 }
Значения каждого перекрывающегося ключа в хеше (в данном случае a, b и c, а не d) попарно перемножаются, а затем суммируются.
Значение для a
в hash1
равно 1, значение для a
в hash2
равно 4. Умножьте их, чтобы получить 1*4 = 4
.
Значение для b
в hash1
равно 2, значение для b
в hash2
равно 5. Умножьте их, чтобы получить 2*5 = 10
.
Значение для c
в hash1
равно 3, значение для c
в hash2
равно 6. Умножьте их, чтобы получить 3*6 = 18
.
Значение для d
в hash1
не существует, значение для d
в hash2
равно 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_vector
. feature_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
Как видите, он берет скалярное произведение token_vector
и token_vector
каждой функции, которые я ввел в Redis выше, и помещает значение в массив.
Моя проблема в том, что это занимает около 18 секунд каждый раз, когда я вызываю метод. Я неправильно использую Redis? Я думаю, проблема может заключаться в том, что я не должен загружать данные Redis в Ruby. Должен ли я отправить Redis данные (token_vector
) и написать функцию Redis, чтобы она выполняла функцию dot_product
, а не писать ее с помощью кода Ruby?