Согласованный String # хэш, основанный только на содержимом строки - PullRequest
25 голосов
/ 30 июня 2011

ЦЕЛЬ: Сопоставить каждый URL, обрабатываемый сервером, с 0, 1, 2 или 3, распределяя его как можно более равномерно.

В то время как документация дляХеш-метод ruby's String # говорит, что он «вернет хеш на основе длины и содержимого строки», это явно не вся история.Хэш данной строки не согласован при вызовах интерпретатора:

$ 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-адреса с одним из четырех хостов активов (если ресурс_хоста приложения настроен ), но эта функция намного менее эффективна, чем могла бы быть из-за перекрестногомашинные несоответствия;разные серверы могут отображать один и тот же URL-адрес на разные хосты ресурсов, снижая эффективность кэшей, облачного неба, преждевременного охлаждения чашек чая, портя репутацию хороших программистов.

Можете ли вы предложить альтернативную хеш-функцию, которая можетэффективно и быстро распределять хеши по типичному URL-пространству приложения, предпочтительно, которое производит Fixnum, так как, в конце концов, я хочу отобразить его на одном из четырех хостов активов?

Ответы [ 4 ]

31 голосов
/ 30 июня 2011

Есть много таких функций в дайджест-модуле ruby: http://ruby -doc.org / stdlib / libdoc / digest / rdoc / index.html

простой пример:

require 'digest/sha1'
Digest::SHA1.hexdigest("some string")
2 голосов
/ 16 февраля 2016

Есть небольшая библиотека xxHash :

XXhash.xxh32('qwe') #=> 2396643526
XXhash.xxh64('qwe') #=> 9343136760830690622

Возможно, в ней будет больше коллизий, но она в 10 раз быстрее, чем SHA1:

Benchmark.bm do |x|
  n = 100_000
  str = 'qweqweqwe'
  x.report('xxhash32') { n.times { XXhash.xxh32(str) } }
  x.report('xxhash64') { n.times { XXhash.xxh64(str) } }
  x.report('hexadigest') { n.times { Digest::SHA1.hexdigest(str) } }
end;1

#       user     system      total        real
# xxhash32  0.020000   0.000000   0.020000 (  0.021948)
# xxhash64  0.040000   0.000000   0.040000 (  0.036340)
# hexadigest  0.240000   0.030000   0.270000 (  0.276443)
1 голос
/ 29 августа 2018

Самый простой (и последовательный) способ может быть таким (и быстрым):

"https://www.example.com/abc/def/123?hij=345".sum % 4

Это всегда будет давать целое число 0 - 3, довольно быстро и должно быть достаточно хорошо распределено (хотя на самом деле я не запускал тесты по распространению).

1 голос
/ 30 июня 2011

Вы можете попробовать to_i (36) .

"Hash me please :(".to_i(36)
=> 807137
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...