2011-10-12 12 views
7

Estoy procesando una gran cantidad de datos y aún no he codificado un duplicador de comprobación en el procesador de datos, por lo que esperaba que se produjeran duplicados. Ejecuté la siguiente consulta SQL:¿Entiendo mal String # hash en Ruby?

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

Y acepto una lista de duplicados. Al analizar esto, encuentro que estos duplicados tienen múltiples valores hash. La cadena más corta de un comentario es "[deleted]". Entonces usemos eso como un ejemplo. En mi base de datos hay nueve instancias de un comentario que es "[deleted]" y en mi base de datos esto produce un hash de ambos 1169143752200809218 y 1738115474508091027. El 116 se encuentra 6 veces y 173 se encuentra 3 veces. Pero, cuando lo ejecuto en el IRB, me sale el siguiente:

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

Aquí está el código que estoy usando para producir el hash:

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

He confirmado que no lo hago Toca comentar en otro lugar en mi código. Aquí está mi clase de mapeo de datos.

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 

Estoy en lo cierto al suponer que .hash en una cadena devolverá el mismo valor cada vez que se llama en la misma cadena?

¿Cuál es el valor correcto suponiendo que mi cadena se compone de "[deleted]"?

¿Hay alguna manera de tener diferentes cadenas dentro de ruby, pero SQL las vería como la misma cadena? Esa parece ser la explicación más plausible de por qué ocurre esto, pero realmente estoy disparando en la oscuridad.

Respuesta

9

Si ejecuta

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

varias veces, se dará cuenta de que el valor es diferente. De hecho, el valor hash solo se mantiene constante mientras su proceso Ruby esté activo. La razón para esto es que String#hash está sembrado con un valor aleatorio. rb_str_hash (la función de implementación C) usa rb_hash_start que usa esta semilla aleatoria que se inicializa cada vez que se genera Ruby.

Puede utilizar un CRC como Zlib#crc32 para sus propósitos o puede utilizar uno de los resúmenes de mensaje de OpenSSL::Digest, aunque este último es excesivo ya que para la detección de duplicados probablemente no necesitará las propiedades de seguridad.

6

utilizo el siguiente para crear alternativas de Cuerda # hash que son constante a través del tiempo y los procesos

require 'zlib' 

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

me corrieron esto con y sin el "% (2 ** 30 - 1)" parte de allí y yo obtuvo el mismo resultado. ¿Te importa explicar por qué lo tienes allí y qué hace? –

+1

Quería limitar mi valor de hash a un número inferior a 2 ** 30. Si establece la etiqueta en una cadena muy larga, debería ver diferentes valores devueltos desde generate_id. –