我有一个哈希,例如:
filers = {query: 'nice post', sort: 'time_desc', post_type: 'blog'...limit: 100}
用于过滤响应数据。我需要为此哈希创建一个唯一键来缓存响应。我可以考虑获取其键和值并将它们转换为单个字符串。寻找一些简单而有效的有趣答案。
答案 0 :(得分:3)
请考虑以下两个步骤:
在基于键排序输出写入顺序后,将哈希值转换为字符串(或其他序列化格式)。
在此转换期间按值对键进行排序非常重要,因此具有相同键/值对(但具有不同键顺序)的哈希将产生相同的输出。更复杂/嵌套的结构需要额外的处理,并应确保等效对象的一致输出。
要开始使用该流程,请考虑:
sorted_kv_pairs = hash.to_a.sort_by {|k,v| k.to_s}
使用散列函数(如SHA-1或SHA-256/160)从先前序列化的对象生成40字节的唯一ID。
这些函数的巨大的输出空间(以及加密质量)使得有目的的碰撞变得不可行,从而导致“唯一ID”。
答案 1 :(得分:2)
一个简单的解决方案是使用Marshal类来转储和读取内容。对于较大的比例,您可以使用memcached,其中有多个Ruby包装器,或者一些键值数据库,如redis,neo4j。
答案 2 :(得分:0)
以下是基于this answer
的解决方案# Return a cache key based on params hash
def params_cache_key(params)
# Normalize parameter hash, change keys to a string, normalize key order, sort array values
normalized = params.transform_keys(&:to_s)
.transform_values { |v| v.is_a?(Array) ? v.sort : v }
.sort_by { |k, _| k }.each_with_object('') do |(k, v), cache_key|
cache_key << "#{k}:#{v}"
end
Digest::SHA1.hexdigest(normalized)
end
以下是一些测试用例
describe '#params_cache_key' do
def cache_key(params)
controller.send :params_cache_key, params
end
it 'should produce a sha1' do
expect(cache_key(foo: 'bar', bar: 'baz')).to match /^\h{40}$/
end
it 'should produce same hash for different key order' do
expect(cache_key(foo: 'bar', bar: 'baz')).to eq cache_key(bar: 'baz', foo: 'bar')
end
it 'should produce same hash for stringified keys' do
expect(cache_key(foo: 'bar', bar: 'baz')).to eq cache_key(foo: 'bar', 'bar' => 'baz')
end
it 'should work with nested parameters in different order' do
expect(cache_key(category: %w(foo bar))).to eq cache_key(category: %w(bar foo))
end
end