| Crates.io | minimal_perfect_hash |
| lib.rs | minimal_perfect_hash |
| version | 0.1.0 |
| created_at | 2025-08-14 15:04:22.97252+00 |
| updated_at | 2025-08-14 15:04:22.97252+00 |
| description | Fast minimal perfect hashing (PT-style): per-bucket seeds, deterministic build, O(1) lookups. |
| homepage | https://github.com/ARyaskov/minimal_perfect_hash |
| repository | https://github.com/ARyaskov/minimal_perfect_hash |
| max_upload_size | |
| id | 1794960 |
| size | 64,285 |
A blazing-fast BDZ minimal perfect hash function implementation in Rust.
Designed for production-scale workloads with millions of keys, minimal memory footprint, and predictableO(1)lookups.
mmap on startup for instant cold starts.Add to your Cargo.toml:
[dependencies]
minimal_perfect_hash = "0.1"
use minimal_perfect_hash::Builder;
fn main() {
// Example: build an MPH from a set of string keys
let keys = vec![
"apple", "banana", "orange", "grape", "melon",
"peach", "mango", "kiwi", "lemon", "plum",
];
let mphf = Builder::new()
.keys(&keys)
.build()
.expect("failed to build MPH");
// Lookups are O(1), no collisions
for k in &keys {
let idx = mphf.lookup(k).unwrap();
println!("'{}' β {}", k, idx);
}
}
Output:
'apple' β 0
'banana' β 1
'orange' β 2
'grape' β 3
'melon' β 4
'peach' β 5
'mango' β 6
'kiwi' β 7
'lemon' β 8
'plum' β 9
Benchmarks (1,000,000 random 32-byte keys, Intel Core i7 12700, Rust 1.88):
| Operation | BDZ MPH | HashMap (hashbrown + AHash) |
|---|---|---|
| Build time | 0.75 s (1.3 M keys/s) | 0.03 s (33 M keys/s) |
| Lookup throughput | 39 M/s (~25.7 ns) | 32 M/s (~30.9 ns) |
| Memory usage | ~5 B/key (~50 MB) | ~80-150 B/key (~1 GB) |
| Collisions | 0 | handled internally |
mmap 50 MB vs pre-allocating and populating a 1 GB hash table.region, service, host) into integers once.BDZ is a minimal perfect hash algorithm:
n slots for n keys.Compared to other MPH algorithms:
use minimal_perfect_hash::Builder;
use std::time::Instant;
fn main() {
let n = 10_000_000;
println!("Generating {n} random keys...");
let keys: Vec<String> = (0..n)
.map(|i| format!("key_{i}"))
.collect();
let start = Instant::now();
let mphf = Builder::new().keys(&keys).build().unwrap();
println!("Build took: {:.3} s", start.elapsed().as_secs_f64());
// Test lookups
let look_start = Instant::now();
let mut sum = 0;
for k in &keys {
sum += mphf.lookup(k).unwrap();
}
println!(
"Lookups took: {:.3} s ({} lookups/s)",
look_start.elapsed().as_secs_f64(),
(n as f64) / look_start.elapsed().as_secs_f64()
);
}
Possible output:
Generating 10000000 random keys...
Build took: 13.012 s
Lookups took: 0.257 s (38.9 M lookups/s)
The builder supports parameters:
let mphf = Builder::new()
.gamma(1.27) // trade memory vs build retries
.max_retries(16) // limit build attempts
.keys(&keys)
.build()
.unwrap();
For 100M+ keys:
gamma β 1.27."rayon").MIT