Generate a Deterministic Hash for Deduplication in Python
Create a stable SHA-256 fingerprint from nested data and file contents to deduplicate records in a data pipeline.
Python code
41 linesimport hashlib
import json
from pathlib import Path
def natural_key_hash(data, salt=""):
"""
Generate a deterministic fingerprint from raw data (dict/list/str).
Uses JSON canonical-ish serialization with sorted keys and SHA-256.
"""
canonical = json.dumps(data, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
return hashlib.sha256((salt + canonical).encode("utf-8")).hexdigest()
def file_fingerprint(filepath, chunk_size=65536):
"""Compute a deduplication fingerprint for a file's content."""
hasher = hashlib.sha256()
with Path(filepath).open("rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
hasher.update(chunk)
return hasher.hexdigest()
if __name__ == "__main__":
# Deduplicate identical records with different field order
records = [
{"name": "Alice", "age": 30, "city": "NYC"},
{"city": "NYC", "age": 30, "name": "Alice"},
{"name": "Bob", "age": 25, "city": "LA"},
]
seen = set()
unique = []
for rec in records:
fp = natural_key_hash(rec)
if fp not in seen:
seen.add(fp)
unique.append(rec)
print("Unique records:", unique)
# Example file fingerprint (temporary file)
p = Path("/tmp/dedup_test.txt")
p.write_text("hello world")
print("File fingerprint:", file_fingerprint(p))
p.unlink()
Output
Unique records: [{'name': 'Alice', 'age': 30, 'city': 'NYC'}, {'name': 'Bob', 'age': 25, 'city': 'LA'}]
File fingerprint: 2ef7bde608ce5404e97d5f042f95f89f1c232871
How it works
The natural_key_hash function serializes data with json.dumps using sort_keys=True to ensure the same logical data regardless of key order produces the same canonical string. SHA-256 is then applied to produce a fixed-length, deterministic fingerprint. For files, the content is hashed chunk-by-chunk to avoid loading large files into memory, which is essential for deduplication at scale. The salt parameter allows domain-specific separation (e.g., per dataset or environment), making fingerprints unique across contexts. This pattern guarantees that identical data—even with different field ordering—collides to the same hash, enabling efficient deduplication with a set.
Common mistakes
- Forgetting `sort_keys=True` in `json.dumps`, causing different key orders to produce different hashes.
- Using `hash()` on strings or dicts, which is randomized per Python process and not suitable for deduplication.
- Not handling non-string data such as floats or bytes during serialization, leading to serialization errors.
- Hashing entire files without chunking, which can exhaust memory for large data files.
Variations
- Use `hashlib.blake2b` for faster hashing with a custom digest size.
- Add a version prefix to the salt to handle schema changes without breaking existing fingerprints.
Real-world use cases
- Deduplicate event records in an ETL pipeline where the same event may appear with different JSON key order.
- Identify duplicate files in cloud storage by hashing file content and comparing fingerprints across buckets.
- Generate idempotency keys for API writes by hashing the request payload, preventing duplicate submissions.
Sponsored
More from Data pipelines & processing
- Add a UUID Surrogate Key to Each Row in a CSV with Python easy
- Attach Source File Metadata to Records in Python easy
- Build a Python Utility That Detects Duplicate Records Across Multiple Excel Sheets medium
- Check Null Rate Threshold in PySpark DataFrame medium
- Count Records Processed per Category in Python easy
- Create Data Helper Functions in Python for Beginners easy
Keep learning
Related tutorials and quizzes for this topic.