Skip to content

polars-hash

Stable non-cryptographic and cryptographic hash functions for Polars.

polars-hash is a Polars plugin written in Rust. It adds six expression namespaces: chash, nchash, geohash, h3, timehash, and uuidhash. These namespaces give the same output on every Polars version. The hash() function in Polars does not give this guarantee. Its output can change when you install a new Polars release.

Install

pip install polars-hash

Quick example

import polars as pl
import polars_hash as plh

df = pl.DataFrame({"foo": ["hello_world"]})

df.select(plh.col("foo").chash.sha2_256())
┌──────────────────────────────────────────────────────────────────┐
│ foo                                                              │
│ ---                                                              │
│ str                                                              │
╞══════════════════════════════════════════════════════════════════╡
│ 35072c1ae546350e0bfa7ab11d49dc6f129e72ccd57ec7eb671225bbd197c8f1 │
└──────────────────────────────────────────────────────────────────┘

Key features

  • Stable output. The same input and the same arguments always give the same hash. This is true for every polars-hash release, except that GxHash holds its values within one major version of the algorithm, which polars-hash pins.
  • Cryptographic hash functions. SHA-2, SHA-3, SHAKE128, BLAKE3, and HMAC-SHA256 in chash.
  • Non-cryptographic hash functions. wyhash, xxHash, XXH3, MurmurHash3, FarmHash, CityHash, GxHash, MD5, and SHA-1 in nchash. Most of them accept a seed.
  • Geospatial indexes. The geohash namespace encodes coordinates, decodes geohashes, and finds neighbor cells. The h3 namespace encodes H3 cell indexes.
  • Time buckets. The timehash namespace encodes an instant to the window that holds it, decodes it back, and finds adjacent windows.
  • Deterministic UUIDs. The uuidhash namespace makes UUID v5 values from one or two columns.
  • Type checker support. plh.col and plh.concat_str declare the namespaces. You do not need # type: ignore.
  • Rust speed. Each expression runs elementwise in compiled Rust and reads the Arrow buffers directly. There is no Python callback for each row.

Next steps