Я неправильно понимаю String # hash в Ruby? - PullRequest
7 голосов
/ 12 октября 2011

Я обрабатываю кучу данных, и я еще не закодировал проверку дубликатов в процессор данных, поэтому я ожидал появления дубликатов.Я запустил следующий 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

Я подтвердил, чтоЯ не касаюсь комментариев где-либо еще в моем коде.Вот мой класс datamapper.

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 увидит их как одну и ту же строку?Кажется, это наиболее правдоподобное объяснение того, почему это происходит, но я действительно стреляю в темноте.

Ответы [ 3 ]

9 голосов
/ 12 октября 2011

Если вы выполните

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

несколько раз, вы заметите, что значение отличается.На самом деле, значение хеша остается постоянным, пока ваш процесс Ruby жив.Причина этого в том, что String#hash засеян со случайным значением.rb_str_hash (функция реализации C) использует rb_hash_start , который использует это случайное начальное число, которое инициализируется каждый раз, когда появляется Ruby.

Вы можете использовать CRC, например Zlib # crc32 для ваших целей или вы можете захотеть использовать один из дайджестов сообщений OpenSSL::Digest, хотя последний излишний, поскольку для обнаружения дубликатов вам, вероятно, не понадобятся свойства безопасности.

6 голосов
/ 12 октября 2011

Я использую следующее для создания альтернативных хеш-строк String #, устойчивых во времени и процессах

require 'zlib'

def generate_id(label)
  Zlib.crc32(label.to_s) % (2 ** 30 - 1)
end
2 голосов
/ 12 октября 2011

Ruby намеренно заставляет String.hash выдавать разные значения в разных сеансах: Почему Ruby String.hash несовместим на разных машинах?

...