nchash — Non-cryptographic hash functions¶
Non-cryptographic hash functions, on pl.Expr as .nchash.
These expressions are fast and their output is stable. Each one accepts Utf8
or Binary. A digest reads bytes, so the data type of the input does not
change the result, and a Utf8 column gives the digest of its UTF-8 bytes.
A null input gives a null output. Any other input type raises
ComputeError: expected `String` or `Binary` input.
Every expression with a UInt128 output also takes return_binary=True,
which writes the same hash as 16 Binary bytes.
Warning
Polars encodes UInt128 as a private Arrow type, so to_arrow() and
to_pandas() raise ArrowInvalid on such a column, and to_numpy()
fails. write_parquet, write_ipc, joins, group_by and sorting all
work. Set return_binary=True if the column has to leave Polars:
Binary travels everywhere. A cast to pl.Binary is not the same thing.
It writes the decimal digits of the integer, not its 16 bytes.
wyhash
¶
wyhash with 64-bit output.
This expression is very fast. You cannot set the seed. It is always 0.
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Examples:
>>> df = pl.DataFrame({"foo": ["hello_world"]})
>>> df.select(plh.col("foo").nchash.wyhash()).item()
16737367591072095403
Each expression in this namespace also hashes the bytes of a Binary column:
sha1
¶
md5
¶
murmur32
¶
MurmurHash3, x86 32-bit variant.
Many systems have an implementation of this algorithm, for example Spark, Kafka and bloom filter libraries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32. |
Note
With the default seed, an empty string gives 0. With a different seed, an empty string gives a value that is not 0. This is the correct MurmurHash3 result. It is not a null value in the output.
Examples:
murmur128
¶
MurmurHash3, x64 128-bit variant.
The integer matches mmh3.hash128(..., signed=False).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
return_binary
|
bool
|
Write the hash as the 16 digest bytes. MurmurHash3
writes its digest as two little-endian halves, so these are the
bytes |
False
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt128, or Binary with |
Warning
Releases up to 0.7.0 returned the 16 digest bytes, and 0.8.0 changed
the output to UInt128. Only the container changed.
int.from_bytes(old, "little") converts a stored value. From 0.9.1,
return_binary=True gives the 0.7.0 bytes again, byte for byte.
Examples:
>>> df = pl.DataFrame({"foo": ["hello_world"]})
>>> df.select(plh.col("foo").nchash.murmur128()).item()
134986332493155497415370161450594282648
>>> df.select(plh.col("foo").nchash.murmur128(seed=42)).item()
128378975539535818103252123378652633995
>>> df.select(
... plh.col("foo").nchash.murmur128(return_binary=True).bin.encode("hex")
... ).item()
'982cf39e1c1aa55d1b079716076c8d65'
xxhash32
¶
XXH32, the original 32-bit xxHash.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32. |
Examples:
xxhash64
¶
XXH64, the 64-bit xxHash.
xxh3_64() is
faster. Use xxhash64() when you must get the same values as a different
system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Examples:
xxh3_64
¶
XXH3 with 64-bit output.
For usual string lengths, this is the fastest expression in the namespace.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Examples:
xxh3_128
¶
xxh3_128(*, seed: int = 0, return_binary: bool = False, byte_order: Literal['little', 'big'] | None = None) -> Expr
XXH3 with 128-bit output.
The integer matches xxhash.xxh128_intdigest(). Formatted as 32
hexadecimal digits with f"{value:032x}", it is the canonical XXH128
digest, the string xxh128_hexdigest() gives.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
return_binary
|
bool
|
Write the hash as 16 Binary bytes. Use this where the target of a write has no 128-bit integer. |
False
|
byte_order
|
Literal['little', 'big'] | None
|
How those bytes read, with |
None
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt128, or Binary with |
Warning
0.8.0 changed this output from Binary to UInt128. Up to 0.7.0 the
16 bytes held the value in the reverse of the canonical order. The
integer now agrees with the reference. To read data hashed by an
older release, reverse the old bytes:
int.from_bytes(old, "little").
Examples:
>>> df = pl.DataFrame({"foo": ["hello_world"]})
>>> df.select(plh.col("foo").nchash.xxh3_128()).item()
253649469245435599925940275794906345219
>>> f"{253649469245435599925940275794906345219:032x}"
'bed31c5eaf3dc62267fb185e21fe6f03'
>>> df.select(plh.col("foo").nchash.xxh3_128(seed=42)).item()
314735830047873782861649874643137875266
The canonical digest bytes, and the bytes of releases up to 0.7.0:
>>> df.select(
... plh.col("foo")
... .nchash.xxh3_128(return_binary=True, byte_order="big")
... .bin.encode("hex")
... ).item()
'bed31c5eaf3dc62267fb185e21fe6f03'
>>> df.select(
... plh.col("foo")
... .nchash.xxh3_128(return_binary=True, byte_order="little")
... .bin.encode("hex")
... ).item()
'036ffe215e18fb6722c63daf5e1cd3be'
farmhash32
¶
Google FarmHash fingerprint32.
The fingerprint functions give the same value on all platforms. BigQuery
uses them for its FARM_FINGERPRINT function. This expression has no
seed.
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32. |
Examples:
farmhash64
¶
Google FarmHash fingerprint64, the 64-bit fingerprint.
This expression has no seed.
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Note
The FARM_FINGERPRINT function in BigQuery gives the same 64 bits as
a signed INT64. To compare the two results, use .cast(pl.Int64)
on the polars-hash output.
Examples:
cityhash32
¶
Google CityHash CityHash32, from CityHash v1.1.1.
FarmHash replaced CityHash, so use
farmhash32()
for new work. Use cityhash32() when you must get the same values as a
different system. This expression has no seed. CityHash32 takes none.
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32. |
Warning
Every CityHash expression here gives the values of v1.1.1, the last
release Google published. CityHash64 changed during the v1.0 series
and CityHash128 changed after v1.0.3, so a system built on an
earlier release gives a different value for the same input. Check
which release the other system uses before you compare.
Note
FarmHash reuses CityHash for short input, so cityhash32() and
farmhash32() give the same value for input up to 12 bytes, as do
cityhash64() and farmhash64() up to 32 bytes. They part above
those lengths. The equal values are not a defect.
Examples:
cityhash64
¶
Google CityHash CityHash64, from CityHash v1.1.1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int | None
|
A value in the range of a |
None
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Warning
A seed of 0 is not the same as no seed. Without a seed this
expression is CityHash64. With one it is CityHash64WithSeed, a
separate function that gives a different value for every seed, 0
included. This is why the seed defaults to None.
Examples:
cityhash128
¶
Google CityHash CityHash128, from CityHash v1.1.1.
CityHash128WithSeed is not wrapped, so this expression has no seed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_binary
|
bool
|
Write the hash as 16 Binary bytes, least significant byte first. The bytes and the integer hold the same hash. |
False
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt128, or Binary with |
Note
C++ returns CityHash128 as a pair. This expression packs it the way
python-cityhash does, Uint128Low64(h) << 64 | Uint128High64(h),
so the C++ low word is the high half of the integer. A system
that composes the halves the other way round, or that stores the raw
16 bytes, needs a word swap before the values compare equal.
Examples:
crc32c
¶
CRC-32C (Castagnoli), the variant iSCSI, SCTP and libcsp use.
This is a checksum, not a general-purpose hash. It is fast to compute and it detects the usual transmission and storage errors, but it does not resist a deliberate collision.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_binary
|
bool
|
Write the checksum as 4 Binary bytes. |
False
|
byte_order
|
Literal['little', 'big']
|
The order of those bytes. |
'little'
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32, or Binary with |
Examples:
gxhash32
¶
GxHash with 32-bit output.
GxHash reaches its speed through the AES block cipher, which the CPU runs
as a single instruction. It is the fastest expression in the namespace
for input above about a hundred bytes. Below that,
xxh3_64() is
the one to beat.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32. |
Warning
GxHash needs a CPU with AES instructions. The algorithm has no software fallback. The published wheels cover x86, x86-64 and aarch64, and every one of them is built with the instructions enabled, so a CPU without them stops the process the moment a GxHash expression runs. On x86 the instructions arrived with Westmere in 2010 and every processor since has them. On ARM they are an optional extension: Apple silicon and server parts have them, and some small boards, such as the Raspberry Pi 4, do not.
The instructions are enabled for the whole build and not for GxHash
alone, so on x86 ahash, which the h3 namespace
pulls in, switches to its AES-NI implementation as well, and the
h3 expressions come to need them too. On aarch64 ahash keeps its portable path, so there GxHash
is the only namespace affected. There are no linux-armv7 or
linux-ppc64le wheels from 0.8.0 on, because GxHash cannot be built
for either.
Examples:
gxhash64
¶
GxHash with 64-bit output.
gxhash32()
gives the requirements of the algorithm and the meaning of the seed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt64. |
Warning
GxHash holds its output stable across platforms, but only within a major version. polars-hash pins GxHash 3 exactly, so the values here do not change without a release that says so. A system on GxHash 2 gives different values for the same input and seed.
Examples:
gxhash128
¶
GxHash with 128-bit output.
gxhash32()
gives the requirements of the algorithm.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
A value in the range of a |
0
|
return_binary
|
bool
|
Write the hash as 16 Binary bytes, least significant byte first. The bytes and the integer hold the same hash. |
False
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt128, or Binary with |
Note
GxHash builds a single 128-bit state and each width reads the low
part of it, so gxhash32() is the low 32 bits of gxhash64(), which
is the low 64 bits of gxhash128(). Ask for the width you need. The
narrow ones cost no less than the wide one.
Examples: