2011-10-12 23 views
7

Tôi đang xử lý một loạt dữ liệu và tôi chưa mã hóa một trình kiểm tra trùng lặp vào bộ xử lý dữ liệu, vì vậy tôi dự kiến ​​các bản sao sẽ xảy ra. Tôi chạy truy vấn SQL sau:Tôi có hiểu lầm về chuỗi # băm trong Ruby không?

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

Và lấy lại danh sách các bản sao. Nhìn vào điều này tôi thấy rằng những bản sao này có nhiều băm. Chuỗi nhận xét ngắn nhất là "[deleted]". Vì vậy, hãy sử dụng nó như một ví dụ. Trong cơ sở dữ liệu của tôi có chín trường hợp của một bình luận là "[deleted]" và trong cơ sở dữ liệu của tôi điều này tạo ra một băm của cả hai 1169143752200809218 và 1738115474508091027. 116 được tìm thấy 6 lần và 173 được tìm thấy 3 lần. Tuy nhiên, khi tôi chạy nó trong IRB, tôi nhận được như sau:

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

Đây là mã tôi đang sử dụng để sản xuất các hash:

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

Tôi xác nhận rằng tôi không chạm vào bình luận ở bất kỳ nơi nào khác trong mã của tôi. Đây là lớp datamapper của tôi.

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 

Am I correct trong giả định rằng .hash trên một chuỗi sẽ trả về giá trị giống nhau mỗi lần nó được gọi là trên chuỗi giống nhau không?

Giá trị nào là giá trị chính xác giả sử chuỗi của tôi bao gồm "[deleted]"?

Có cách nào tôi có thể có các chuỗi khác nhau bên trong ruby ​​không, nhưng SQL sẽ xem chúng là chuỗi giống nhau không? Đó có vẻ là lời giải thích hợp lý nhất cho việc này, nhưng tôi thực sự đang quay trong bóng tối.

Trả lời

9

Nếu bạn chạy

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

nhiều lần, bạn sẽ thấy rằng giá trị là khác nhau. Trong thực tế, giá trị băm chỉ duy trì không đổi miễn là quá trình Ruby của bạn còn sống. Lý do cho điều này là String#hash được gieo với một giá trị ngẫu nhiên. rb_str_hash (chức năng thực hiện C) sử dụng rb_hash_start sử dụng hạt giống ngẫu nhiên này được khởi tạo mỗi khi Ruby được sinh ra. Bạn có thể sử dụng một CRC như Zlib#crc32 cho mục đích của mình hoặc bạn có thể muốn sử dụng một trong các thông báo tiêu hóa OpenSSL::Digest, mặc dù sau này là quá mức cần thiết để phát hiện các bản sao có thể bạn sẽ không cần các thuộc tính bảo mật.

6

tôi sử dụng sau đây để tạo ra chuỗi lựa chọn thay thế # băm được nhất quán theo thời gian và xử lý

require 'zlib' 

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

Tôi chạy này có và không có "% (2 ** 30-1)" phần trên đó và tôi có cùng kết quả. Chăm sóc để giải thích lý do tại sao bạn có nó trên đó và những gì nó làm gì? –

+1

Tôi muốn giới hạn giá trị băm của tôi cho một số nhỏ hơn 2 ** 30. Nếu bạn đặt nhãn thành một chuỗi rất dài, bạn sẽ thấy các giá trị khác nhau được trả về từ generate_id. –

Các vấn đề liên quan