2014-12-23 3 views
1

Для слоя кеширования мне нужно создать уникальный ша для хэша. Он должен быть уникальным для содержимого этого хэша. Два хэша с одинаковой конфигурацией должны иметь один и тот же шаг.Как сгенерировать уникальный идентификатор хэша с определенным контентом?

in_2014 = { scopes: [1, 2, 3], year: 2014 } 
not_in_2104 = { scopes: [1, 2, 3], year: 2015 } 
also_in_2014 = { year: 2014, scopes: [1, 2, 3] } 

in_2014 == also_in_2014 #=> true 
not_in_2104 == in_2014 #=> false 

Теперь для того, чтобы сохранить его и быстро посмотреть эту игру, он должен быть включен в нечто shasum. Просто преобразования в строку не работает, так генерируя hexdigest от него не работает либо:

require 'digest' 
in_2014.to_s == also_in_2014.to_s #=> false 
Digest::SHA2.hexdigest(in_2014.to_s) == Digest::SHA2.hexdigest(also_in_2014.to_s) #=> false 

То, что я хочу, это shasum или какой-либо другой идентификатор, который позволит мне сравнить хэши друг с другом. Я хочу что-то вроде последнего теста, который вернет true, если содержимое хэшей будет соответствовать.

Я мог бы сортировать хэши до to_s, но это кажется неуклюжим для меня. I am, для одного, боюсь, что я что-то пропускаю (sort возвращает массив, уже не хэш, для одного). Есть ли что-то простое, что я пропускаю? Или это вообще невозможно?

FWIW, нам нужно это в сценарии, как показано ниже:

Analysis.find_by_config({scopes: [1,2], year: 2014}).datasets 
Analysis.find_by_config({account_id: 1337}).datasets 

class Analysis < ActiveRecord::Base 
    def self.find_by_config(config) 
    self.find_by(config_digest: shasum_of(config)) 
    end 

    def self.shasum_of(config) 
    #WAT? 
    end 

    def before_saving 
    self.config_digest = Analysis.shasum_of(config) 
    end 
end 

Обратите внимание, что здесь, анализ делает не есть столбцы «области» или «год» или « ACCOUNT_ID». Это произвольные конфиги, которые нам нужны только для просмотра наборов данных.

+0

Если это кеш, действительно ли имеет значение, если вы периодически повторяете записи? –

+0

Повторяющиеся записи будут иметь значение в некоторых случаях. Кэш существует, потому что генерация «наборов данных» на самом деле (как и в течение десяти минут вычислительного времени для каждого конфигурационного файла) является дорогостоящей.Следовательно, мы хотим сохранить конфигурацию, попросите фонового рабочего рассчитать набор данных и с этого момента, сразу же передайте наборы данных для определенной конфигурации. – berkes

ответ

4

Я бы не рекомендовал метод hash, так как он ненадежен. Вы можете быстро подтвердить это, выполнив {one: 1}.hash в своем IRB, ту же команду в консоли Rails, а затем в консоли IRB и/или Rails на другом компьютере. Выходы будут отличаться.

Приклеивание с помощью Digest::SHA2.hexdigest(string) было бы мудрее.

Вам нужно будет отсортировать хэш и подстроить его, конечно. Это то, что я хотел бы сделать:

hash.sort.to_s 

Если массив не нужен, по какой-либо причине, превратить его обратно в хэш.

Hash[hash.sort].to_s #=> will return hash 

И, по какой причине, если вы не хотите, чтобы включить хэш в массив, а затем обратно в хэш, выполните следующие действия для хэш-на-отсортированный-хэш:

def prepare_for_sum(hash) 
    hash.keys.sort.each_with_object({}) do |key, return_hash| 
    return_hash[key] = hash[key] 
    end.to_s 
end 

Используя некоторые модификации вышеописанного метода, вы также можете сортировать значения; это может быть полезно в случае значений Array или Hash.

+0

'Hash [hash.sort] .to_s' выдает ошибку,' не может преобразовать массив в hash'. – berkes

+0

@berkes, отлично работает для хэша, который я представил в своем ответе. – Humza

+0

мы расследуем, потому что наша база кода получила разные результаты. Отправляюсь обратно, когда у меня будет больше деталей. – berkes

0

Оказалось, у Ruby есть метод для этого точного случая: Hash.hash.

in_2014.hash == also_in_2014.hash 
+0

'hash' имеет свои недостатки. Проверьте мой ответ. – Humza

+0

@ Хумза прав, это ужасная идея для кеша, значения 'hash' не будут постоянными в процессах. –

Смежные вопросы