J'ai besoin d'une fonction de hachage de chaîne haute performance en python qui produise des entiers avec au moins 34 bits de sortie (64 bits auraient un sens, mais 32, c'est trop peu). Il y a plusieurs autres questions comme celle-ci sur Stack Overflow, mais parmi celles que j'ai trouvées, toutes les réponses acceptées/votées ont été classées dans l'une des catégories suivantes, qui ne s'appliquent pas (pour la raison indiquée).
hash()
intégrée. Cette fonction, au moins sur la machine pour laquelle je développe (avec Python 2.7 et un processeur 64 bits), produit un entier qui correspond à 32 bits - pas assez grand pour mes besoins.string.__hash__()
comme prototype pour écrire votre propre fonction. Je pense que ce sera la bonne façon de faire, sauf que l'efficacité de cette fonction réside dans l'utilisation de la fonction c_mul, qui englobe environ 32 bits - encore une fois, trop petit pour mon utilisation! Très frustrant, c'est si proche de la perfection!Une solution idéale aurait les propriétés suivantes, dans un ordre d'importance relativement lâche.
Exemple de hachage 'Perturbed', où la valeur de hachage est modifiée radicalement par un petit nombre entier n
def perturb_hash(key,n):
return hash((key,n))
Enfin, si vous êtes curieux de savoir ce que je fais comme si j'avais besoin d'une telle fonction de hachage, je suis en train de réécrire complètement le module pybloom pour améliorer considérablement ses performances. J'ai réussi à cela (il tourne maintenant environ 4x plus vite et utilise environ 50% de l'espace), mais j'ai remarqué que parfois, si le filtre devenait suffisamment grand, il atteignait soudainement des taux de faux positifs. J'ai réalisé que c'était parce que la fonction de hachage ne traitait pas assez de bits. 32 bits ne peuvent traiter que 4 milliards de bits (attention, les adresses de filtre sont des bits et non des octets) et certains des filtres que j'utilise pour les données génomiques sont au moins deux ou plus (donc au moins 34 bits).
Merci!
Examinez la variante 128 bits de MurmurHash3 . La page de l'algorithme inclut certains numéros de performance. Il devrait être possible de porter cela en Python, pur ou en extension C. ( Updated l'auteur recommande d'utiliser la variante 128 bits et de jeter les bits dont vous n'avez pas besoin).
Si MurmurHash2 64 bits fonctionne pour vous, il existe une implémentation Python (extension C) dans le package pyfasthash , qui inclut quelques autres variantes de hachage non cryptographiques, bien que certaines d'entre elles n'offrent qu'une sortie 32 bits.
Update J'ai réalisé un wrapper Python rapide pour la fonction de hachage Murmur3. Le projet Github est ici et vous pouvez le trouver également dans Python Package Index ; il faut juste un compilateur C++ pour construire; pas de boost nécessaire.
Exemple d'utilisation et comparaison temporelle:
import murmur3
import timeit
# without seed
print murmur3.murmur3_x86_64('samplebias')
# with seed value
print murmur3.murmur3_x86_64('samplebias', 123)
# timing comparison with str __hash__
t = timeit.Timer("murmur3.murmur3_x86_64('hello')", "import murmur3")
print 'murmur3:', t.timeit()
t = timeit.Timer("str.__hash__('hello')")
print 'str.__hash__:', t.timeit()
Sortie:
15662901497824584782
7997834649920664675
murmur3: 0.264422178268
str.__hash__: 0.219163894653
Utilisez la fonction hash () intégrée. Cette fonction, du moins sur la machine pour laquelle je développe (avec Python 2.7 et un processeur 64 bits) produit un entier qui tient dans les 32 bits - pas assez grand pour Mes objectifs. .
Ce n'est pas vrai. La fonction de hachage intégrée générera un hachage 64 bits sur un système 64 bits.
Voici la fonction de hachage str de python de Objects/stringobject.c
(version 2.7 de Python):
static long
string_hash(PyStringObject *a)
{
register Py_ssize_t len;
register unsigned char *p;
register long x; /* Notice the 64-bit hash, at least on a 64-bit system */
if (a->ob_shash != -1)
return a->ob_shash;
len = Py_SIZE(a);
p = (unsigned char *) a->ob_sval;
x = *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= Py_SIZE(a);
if (x == -1)
x = -2;
a->ob_shash = x;
return x;
}
"chaînes": je suppose que vous souhaitez hacher les objets Python 2.x str
et/ou Python3.x bytes
et/ou bytearray
.
Cela peut violer votre première contrainte, mais: envisagez d'utiliser quelque chose comme
(zlib.adler32(strg, perturber) << N) ^ hash(strg)
pour obtenir un hachage de (32 + N) bits.
Si vous pouvez utiliser Python 3.2, le résultat de hachage sous Windows 64 bits est désormais une valeur 64 bits.