Skip to main content

Compact a DuckDB database (ChunkHound index or otherwise) by rebuilding it into a fresh file

Project description

ChunkHound Index Compactor

Compact a DuckDB database by rebuilding it into a fresh file. The motivating use case was shrinking a bloated ChunkHound index (whose per-batch HNSW re-serialization leaves large amounts of orphaned-but-counted blocks), but the implementation is fully generic; it works on any single-schema DuckDB file.

⚡ Quick Start

uvx chunkhound-index-compactor path/to/db.duckdb
# writes path/to/db.duckdb.compacted

uvx chunkhound-index-compactor path/to/db.duckdb --replace
# swaps in the compacted copy and keeps the original at path/to/db.duckdb.bak

uvx chunkhound-index-compactor path/to/db.duckdb --skip-hnsw
# skips rebuilding vector indexes (RAM-flat, smallest output); restore them later
uvx chunkhound-index-compactor restore path/to/db.duckdb.compacted

The source is opened read-only, but an active writer holds the file lock. Close any process writing to the database before running.

🖥️ CLI Usage

$ chunkhound-index-compactor --help
Usage: chunkhound-index-compactor [OPTIONS] COMMAND [ARGS]...

Commands:
  compact  Compact a DuckDB database by rebuilding it into a fresh file. (default)
  restore  Rebuild HNSW vector indexes in a --skip-hnsw artifact, in place.

A bare invocation routes to compact, so chunkhound-index-compactor SOURCE still works:

chunkhound-index-compactor SOURCE [TARGET] [--replace] [--skip-hnsw]
chunkhound-index-compactor restore DATABASE
Argument / Option Meaning
SOURCE Path to the existing DuckDB file (required)
TARGET Path for the compacted output [default: <source>.compacted]
--replace After success, replace source with the compacted file (original → <source>.bak)
--skip-hnsw Do not rebuild vector indexes; write a recipe table for later restore

With --skip-hnsw, the output has no vector index and falls back to a brute-force scan (correct, just unaccelerated) until you run restore. Rebuilding the HNSW is the memory-dominant step, so --skip-hnsw lets you compact on a small machine and restore on a RAM-capable one. See docs/benchmarks.md for peak-RAM numbers and docs/architecture.md §RAM cost asymmetry for why.

🐍 Library Usage

from pathlib import Path
from chunkhound_index_compactor import compact_database, restore_indexes, replace_with_compacted

result = compact_database(Path("big.duckdb"), Path("small.duckdb"))
print(f"{result.source_size} -> {result.target_size} ({result.delta_pct:+.1f}%)")

# Small-RAM path: skip the vector index, restore it later on a bigger machine.
compact_database(Path("big.duckdb"), Path("small.duckdb"), skip_hnsw=True)
restored = restore_indexes(Path("small.duckdb"))
print(f"restored: {restored.restored}")

# Optional: swap in place with .bak backup
backup = replace_with_compacted(result.source, result.target)

compact_database() raises:

  • ValueError: target resolves to the same path as source, the source has a non-main schema or a view, or the FK graph has a cycle.
  • FileNotFoundError: source does not exist.
  • FileExistsError: target already exists.

restore_indexes() raises:

  • FileNotFoundError: database does not exist.
  • ValueError: database has no _compactor_hnsw_recipe table (not a --skip-hnsw artifact).

replace_with_compacted() raises FileExistsError if <source>.bak already exists. It refuses to overwrite an existing backup.

🚫 Not Supported

The tool fails hard rather than silently dropping anything it cannot reproduce:

  • Non-main schemas and views (raise ValueError).
  • Foreign-key cycles among tables (raise ValueError).
  • HNSW tuning parameters other than metric (M, M0, ef_construction, ef_search); they are not recoverable from a built index and are rebuilt at the vss defaults.

See docs/architecture.md for the reasoning, and docs/out-of-scope.md for approaches considered and not pursued.

🏗️ Development

Setup, local checks, CI, and release process: CONTRIBUTING.md.

⚖️ License

MIT


[!NOTE] Yes, an AI wrote this README. And the code, the docs, the tests, and the .claude/skills it now uses to write the next round. Yes, a human told it to keep the emojis. The human has ADHD, which, as it turns out, means his brain was already doing attention re-routing and context-window thrashing before LLMs made it cool. They call him ... LLMartin. The emojis are a feature.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chunkhound_index_compactor-0.1.1.tar.gz (54.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chunkhound_index_compactor-0.1.1-py3-none-any.whl (11.7 kB view details)

Uploaded Python 3

File details

Details for the file chunkhound_index_compactor-0.1.1.tar.gz.

File metadata

File hashes

Hashes for chunkhound_index_compactor-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e52a837ae792c973e460b4732663acd9b373046f170c9be76889f02017800873
MD5 0be2c3f52c2731f18189c71c0eed9764
BLAKE2b-256 33cf531f8a369a3d8b4400ba6270ca78bbc4fdc32aba808fc0fd883a1dbd9340

See more details on using hashes here.

Provenance

The following attestation bundles were made for chunkhound_index_compactor-0.1.1.tar.gz:

Publisher: release.yml on it-bens/chunkhound-index-compactor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chunkhound_index_compactor-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for chunkhound_index_compactor-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 48ea1414a1d28b69f8ef6c8248ea7903031382c615a8c711168af7035b8ab779
MD5 cc09cec491b01a34bffa759eed34cdc2
BLAKE2b-256 42e192fa9270689e11d7145668eee8b93fda705767698df2d59a1658bcac1387

See more details on using hashes here.

Provenance

The following attestation bundles were made for chunkhound_index_compactor-0.1.1-py3-none-any.whl:

Publisher: release.yml on it-bens/chunkhound-index-compactor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page