我误解了 Ruby 中的 String#hash 吗?

Posted

技术标签:

【中文标题】我误解了 Ruby 中的 String#hash 吗?【英文标题】:Am I misunderstanding String#hash in Ruby? 【发布时间】:2011-12-05 18:36:50 【问题描述】:

我正在处理一堆数据,但我还没有将重复检查器编码到数据处理器中,所以我预计会发生重复。我运行了以下 SQL 查询:

SELECT     body, COUNT(body) AS dup_count 
FROM         comments
GROUP BY body
HAVING     (COUNT(body) > 1) 

然后返回一个重复列表。调查这个我发现这些重复有多个哈希。评论的最短字符串是"[deleted]"。所以让我们以此为例。在我的数据库中,有九个评论实例为"[deleted]",在我的数据库中,这会产生 1169143752200809218 和 1738115474508091027 的哈希值。116 被找到 6 次,173 被找到 3 次。但是,当我在 IRB 中运行它时,我得到以下信息:

a = '[deleted]'.hash # => 811866697208321010

这是我用来生成哈希的代码:

def comment_and_hash(chunk)     
  comment = chunk.at_xpath('*/span[@class="comment"]').text ##Get Comment##
  hash = comment.hash
  return comment,hash
end

我已经确认我不会在我的代码中的其他任何地方触碰评论。这是我的数据映射器类。

class Comment

    include DataMapper::Resource

    property :uid       , Serial
    property :author    , String
    property :date      , Date
    property :body      , Text
    property :arank     , Float 
    property :srank     , Float 
    property :parent    , Integer #Should Be UID of another comment or blank if parent
    property :value     , Integer #Hash to prevent duplicates from occurring

end

我是否正确假设字符串上的.hash 每次在同一字符串上调用时都会返回相同的值?

假设我的字符串由"[deleted]" 组成,哪个值是正确的?

有没有办法可以在 ruby​​ 中使用不同的字符串,但 SQL 会将它们视为相同的字符串?对于为什么会发生这种情况,这似乎是最合理的解释,但我真的是在黑暗中拍摄。

【问题讨论】:

【参考方案1】:

如果你运行

ruby -e "puts '[deleted]'.hash"

多次,您会注意到值不同。事实上,只要 Ruby 进程还活着,哈希值就会保持不变。这样做的原因是 String#hash 是用随机值播种的。 rb_str_hash(C 实现函数)使用 rb_hash_start,它使用这个随机种子,每次生成 Ruby 时都会初始化。

您可以出于您的目的使用诸如Zlib#crc32 之类的CRC,或者您可能想要使用OpenSSL::Digest 的消息摘要之一,尽管后者过于矫枉过正,因为您可能不需要安全性检测重复属性。

【讨论】:

【参考方案2】:

我使用以下内容创建跨时间和流程一致的 String#hash 替代项

require 'zlib'

def generate_id(label)
  Zlib.crc32(label.to_s) % (2 ** 30 - 1)
end

【讨论】:

我在有和没有“% (2 ** 30 - 1)” 部分的情况下运行了这个,我得到了相同的结果。愿意解释一下为什么要在上面放它以及它的作用吗? 我想将我的哈希值限制为小于 2 ** 30 的数字。如果将标签设置为很长的字符串,您应该会看到从 generate_id 返回的不同值。【参考方案3】:

Ruby 故意让String.hash 在不同的会话中产生不同的值:Why is Ruby String.hash inconsistent across machines?

【讨论】:

以上是关于我误解了 Ruby 中的 String#hash 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Consistent String#hash仅基于字符串的内容

Ruby将Object转换为Hash

Ruby基本语法

Ruby 中的关键字参数解包(splat)

Ruby 维护 Hash 插入顺序

Ruby 中的 to_s 与 to_str(以及 to_i/to_a/to_h 与 to_int/to_ary/to_hash)