Database Refactoring Design
jhj
2026년 06월 28일
Spec: SQLite-based Database Refactoring & Batch Registration
- Date: 2026-06-28
- Author: Antigravity (AI Coding Assistant)
- Status: Draft (Pending User Review)
1. Overview & Goals
The current Lumipet Re-ID system stores embeddings and labels in a single compressed NumPy .npz file. While simple, it has several limitations:
- Inefficient Feature Extraction: The
registerprocess handles images sequentially one by one, failing to utilize batch inference (predict_batch), which causes significant latency in bulk registration. - Missing Metadata: Image file paths and MD5 hashes are not saved, which prevents deduplication, selective editing/deletions, and model-based feature migrations.
- No Concurrency Safety:
.npzfiles are read and rewritten entirely, leading to race conditions if accessed by concurrent web requests. - Messy State Management: Loaded features inside
EmbeddingStoreare in a mixed list-of-arrays state, making internal APIs brittle.
This design transitions the storage to a SQLite database, introduces MD5-based deduplication, implements high-performance batch registration, and adds DB management utilities (listing, deleting specific labels, and migrating features when model weights/backbones change).
2. Database Schema (SQLite)
We will use Python’s built-in sqlite3 engine. The database file will default to embeddings/db.db (and automatically map *.npz paths to *.db to preserve config backward compatibility).
2.1 Table: embeddings
CREATE TABLE IF NOT EXISTS embeddings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL, -- Name of the individual cat
embedding BLOB NOT NULL, -- Serialized float32 NumPy array of shape (D,)
image_path TEXT, -- Relative path of the registered original image
image_hash TEXT UNIQUE, -- MD5 hash of the original image to prevent duplication
model_name TEXT NOT NULL, -- Backbone/extraction model name used (e.g. 'hf-hub:BVRA/MegaDescriptor-L-384')
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_embeddings_label ON embeddings(label);
CREATE INDEX IF NOT EXISTS idx_embeddings_hash ON embeddings(image_hash);
3. Component Interfaces
3.1 EmbeddingStore (reid/models/extractor/embedding.py)
We will rewrite EmbeddingStore to match SQLite backend while preserving standard methods to ensure zero breakage of existing pipeline components.
class EmbeddingStore:
def __init__(self, db_path: str = "embeddings/db.db"):
# Resolves db_path. Suffix is changed to '.db' if '.npz' is specified.
...
def add(self, embedding: np.ndarray, label: str, image_path: Optional[str] = None, image_hash: Optional[str] = None, model_name: str = "") -> None:
"""Add a single embedding and label to SQLite."""
...
def add_batch(self, embeddings: np.ndarray, labels: List[str], image_paths: List[str], image_hashes: List[str], model_name: str) -> None:
"""Insert multiple embeddings in a single transaction (high performance)."""
...
def get_all(self, model_name: Optional[str] = None) -> Tuple[np.ndarray, List[str]]:
"""
Return all embeddings and labels matching the current model_name.
Raises warning or error if database contains embeddings from a different model.
"""
...
def list_labels(self) -> Dict[str, int]:
"""Return unique labels and count of their registered embeddings."""
...
def delete_label(self, label: str) -> int:
"""Delete all database rows matching the specified label. Returns number of rows deleted."""
...
def clear(self) -> None:
"""Truncate the table."""
...
4. Pipeline Flows
4.1 Batch Registration Flow
The registration method in ExtractorModel will be refactored to perform batch inference and deduplication:
- Scan and Check:
- MD5 hashes of all images in the source directory are computed.
- We query existing hashes in SQLite using
SELECT image_hash FROM embeddingsand filter out any images that are already registered.
- Batch Extraction:
- Remaining new images are chunked into batches of size
cfg.batch_size(default 16). - For each batch,
predict_batchis called to perform GPU/CPU inference in a single forward pass.
- Remaining new images are chunked into batches of size
- Database Write:
- Extracted embeddings, labels, file paths, and hashes are committed in bulk using
add_batch().
- Extracted embeddings, labels, file paths, and hashes are committed in bulk using
5. CLI commands
We will introduce new commands in reid/cli.py:
reid list:
QueriesEmbeddingStorefor registered individuals and outputs a clean count summary.reid delete label=<cat_name>:
Cleans out all rows related to<cat_name>from the SQLite database.reid migrate:
Queries all registered image paths from the database. Re-runs batch extraction using the active model/weights, and updates database records with the new model name and new embeddings.
6. Testing & Verification
- Unit Tests:
- We will write new tests in
tests/test_database.pyverifying SQLite schema initialization, serialization/deserialization, transaction speed, deduplication constraints, listing, and label deletions.
- We will write new tests in
- Integration Tests:
- Verify that
predictpipeline initializes correctly withget_all()from the SQLite DB. - Run a mock
registercommand and verify that batching works and database grows correctly.
- Verify that
C
Contents
