ir.store¶
Persistence for ir — the repository layer over dol key-value views.
A CorpusStore bundles three MutableMapping views, so where and
how data is persisted is swappable without touching the rest of ir:
meta:record_id -> dict(text + metadata + filter fields), JSON.vectors:record_id -> ndarray(the embedding), numpy bytes.ledger:artifact_id -> dict(version, embedder id, record ids) — drives incremental maintenance.config:key -> dict(one entry: the corpus build settings).calibration:mode -> dict(a per-ranking-mode calibrated record, today the abstentionmin_scorefloor fromir.eval.calibrate_min_score()). Kept apart fromconfigon purpose — a calibration is regenerable, derived from an eval run, and not part of the corpus’s build identity, so it must never clobber (or be clobbered by) the build settings.links:artifact_id -> {edge_type: [target, ...]}(the semantic link graph — typed directed edges between artifacts; seeir.graph). Likecalibrationit is regenerable derived state, kept out of build identity; a target is a bareartifact_id(intra-corpus) or a[source, artifact_id]pair (cross-corpus). Optional — an absent view is simply “no edges”.
The default factory CorpusStore.local() roots all six under
~/.local/share/ir/corpora/<name> via dol file stores;
CorpusStore.memory() gives a dependency-free in-memory store for tests.
Brute-force search reads vectors into a single normalized matrix
(matrix()), cached in-process and invalidated on writes.
Classes
|
Repository bundling the meta/vectors/ledger/config views of one corpus. |
- class ir.store.CorpusStore(meta, vectors, ledger, config, calibration=None, links=None, *, packed_dir=None)[source]¶
Bases:
objectRepository bundling the meta/vectors/ledger/config views of one corpus.
- delete_links(artifact_id)[source]¶
Remove an artifact’s edges; a missing entry is tolerated.
- Return type:
- delete_record(record_id)[source]¶
Remove a record’s metadata + vector; a missing id is tolerated.
The meta goes first, so the id stops being listed before its vector disappears. Each removal tolerates the file being gone already (another process may be deleting the same record).
- Return type:
- get_calibration(mode)[source]¶
The stored calibration record for ranking
mode(Noneif absent).A deep copy, so a caller cannot mutate the nested
gridback into the stored record (in-memory stores share their objects by reference).
- get_config()[source]¶
The persisted corpus build settings (empty dict if never written).
- Return type:
- get_links(artifact_id)[source]¶
The outgoing edges of artifact_id —
{edge_type: [target, ...]}.Empty dict when the artifact has no stored edges (or no links view). A copy, so a caller cannot mutate the persisted adjacency in place.
- Return type:
- get_maintenance_state()[source]¶
Background-work bookkeeping (e.g.
last_maintained);{}if unset.Kept under a separate
config-view key from the build settings: it is regenerable scheduler state (whenir maintainlast ran), not part of the corpus’s build identity, so it must never clobber it.- Return type:
- get_record(record_id)[source]¶
Reassemble the
Recordfor record_id (KeyErrorif absent).- Return type:
- ledger_items()[source]¶
Iterate
(key, entry)ledger pairs (the ledger may be mutated while iterating).
- classmethod local(name)[source]¶
File-backed store under
~/.local/share/ir/corpora/<name>.- Return type:
- matrix()[source]¶
Return
(record_ids, normalized_matrix, metas)for brute force.Rows are L2-normalized so cosine similarity is a dot product. Empty corpora return a
(0, 0)matrix.Caching is two-tier: an in-process cache (invalidated on the next write) backed, for file-rooted stores, by an on-disk packed cache — one normalized-matrix
.npyplus its ids/metas, written once and reloaded with a single memory-mapped read. The packed cache turns a cold reopen from a per-record vector-file storm (thousands of tiny reads) into three file reads; it is cleared by a writer’s first record write, and every record write replaces a write stamp that a packed set must match to be published or loaded, so a set built before any later write – by this process or another – is never served (i2mint/ir#86).Another process may be writing or deleting records while this one rebuilds. A record that vanishes or is only half-written when read is left out of the result (it is “not yet written”), with a warning; such a partial result is cached in-process but never published as the packed set, so a fresh process reads the records again.
- metas()[source]¶
Return
(record_ids, metas)without loading any vectors.The vector-free counterpart of
matrix(), for ranking modes that score on text alone (mode="lexical"): they need candidate metadata (text + filter fields) but never the embedding matrix, so they must not pay its I/O. Reuses the in-process or packed cache when present; else reads only themetaview (notvectors), skipping a record that vanishes or is half-written mid-read (asmatrix()does).
- put_record(record)[source]¶
Persist record’s metadata + vector, invalidating the search matrix.
The vector is written before the meta: record ids are listed from the meta view, so a reader in another process that lists an id always finds its vector (
delete_recordremoves in the reverse order).- Return type:
- set_calibration(mode, record)[source]¶
Persist a calibration
recordfor rankingmode(one per mode).modekeys a file in the calibration store, so it must be a non-empty string with no path separator (the real modes —dense/lexical/hybrid— already satisfy this).- Return type:
- set_config(settings)[source]¶
Persist the corpus build settings (name / embedder spec + id).
- Return type:
- set_ledger_entry(key, entry)[source]¶
Write the ledger entry (version / embedder id / record ids) for key.
- Return type: