Techioz Blog

文字列の内容のみに基づく一貫した String#hash

概要

目標: サーバーによって処理されるすべての URL を 0、1、2、または 3 にマップし、できるだけ均一に分散します。

Ruby の String#hash メソッドのドキュメントには、「文字列の長さと内容に基づいてハッシュを返す」と書かれていますが、これがすべてではないことは明らかです。指定された文字列のハッシュは、インタープリタの呼び出し間で一貫性がありません。

$ irb
ruby-1.9.2-p180 :001 > "foo".hash
 => 360517580588231756 
ruby-1.9.2-p180 :002 > ^D

$ irb
ruby-1.9.2-p180 :001 > "foo".hash
 => -2716152678666510148 

これは、特定の文字列のハッシュ値が、たとえばサーバー間で異なる可能性があることを意味します。 Rails は内部で String#hash を使用して、URL パスを 4 つのアセット ホストの 1 つにマッピングします (アプリのasset_host がそのように構成されている場合)。ただし、この機能は、マシン間の不整合のため、通常よりもはるかに効率が低くなります。異なるサーバーが同じ URL を異なるアセット ホストにマップする可能性があり、キャッシュの有効性が低下し、空が曇り、途中でお茶が冷めてしまい、優秀なプログラマーの評判が傷つきます。

一般的なアプリの URL 空間全体に効果的かつ迅速にハッシュを分散できる代替ハッシュ関数を提案していただけますか。最終的には 4 つのアセット ホストの 1 つにマッピングする必要があるため、できれば Fixnum を生成するハッシュ関数を提案していただけますか?

解決策

Ruby のダイジェスト モジュールにはそのような機能がたくさんあります: http://ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html

簡単な例:

require 'digest/sha1'
Digest::SHA1.hexdigest("some string")