Corpus y persistencia¶
El corazón del modelo de datos: el Corpus (una tabla canónica Arrow con
semántica de valor), su Manifest de procedencia, los snapshots sellados y los
backends que lo respaldan —puro en memoria para tests, o DuckDB para la
biblioteca viva—.
Corpus
¶
Wrapper de semántica de valor sobre un TabularBackend + un Manifest.
Lo que circula por el pipeline: Source lo siembra, el Forager lo expande,
el humano lo cura, el Preprocessor lo normaliza, el Store lo persiste
(biblioteca viva), los Projectors lo consumen. NO envuelve una base de
datos directamente; delega en el TabularBackend inyectado.
Todos los métodos que modifican el contenido devuelven un Corpus
nuevo; la instancia original no muta nunca (semántica de valor).
Methods:
| Name | Description |
|---|---|
from_arrow |
Valida la tabla con el schema canónico y construye el Corpus. |
to_arrow |
Devuelve la tabla Arrow del contenido actual. |
seeds |
Vista de los papers semilla ( |
candidates |
Vista de los candidatos ( |
accepted |
Vista de los papers aceptados ( |
scoped |
Devuelve un Corpus nuevo con el subconjunto de filas según el scope. |
add_paper |
Agrega un paper validando la fila con |
with_manifest |
Devuelve un |
merge |
Combina dos Corpus deduplicando por |
accept |
Marca los papers con los ids dados como 'accepted'. |
reject |
Marca los papers con los ids dados como 'rejected'. |
materialize |
Materializa una vista explodida por entidad (author/keyword/institution). |
snapshot |
Exporta una foto sellada del estado actual (parquet + manifest.json). |
Attributes:
| Name | Type | Description |
|---|---|---|
table |
Table
|
Tabla Arrow del contenido actual (delegada al backend). |
manifest |
Manifest
|
Metadatos del Corpus (solo lectura). |
from_arrow
classmethod
¶
from_arrow(
table: Table, *, backend: TabularBackend | None = None
) -> Corpus
Valida la tabla con el schema canónico y construye el Corpus.
Falla ruidoso con SchemaError si el schema no coincide (columna
faltante, tipo incorrecto o nulo en columna no-nullable).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table
|
Table
|
Tabla Arrow a envolver. |
required |
backend
|
TabularBackend | None
|
Backend a usar. Si es |
None
|
Returns:
| Type | Description |
|---|---|
Corpus
|
Instancia de |
Raises:
| Type | Description |
|---|---|
SchemaError
|
Si la tabla no cumple el schema canónico. |
to_arrow
¶
Devuelve la tabla Arrow del contenido actual.
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow con el schema canónico. |
seeds
¶
Vista de los papers semilla (is_seed == True).
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
candidates
¶
Vista de los candidatos (curation_status == 'candidate').
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
accepted
¶
Vista de los papers aceptados (curation_status == 'accepted').
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
scoped
¶
scoped(scope: str) -> Corpus
Devuelve un Corpus nuevo con el subconjunto de filas según el scope.
Vista pura: no muta el original; dos llamadas con el mismo scope
devuelven corpora con el mismo corpus_hash.
Valores de scope:
- 'all': corpus completo (sin filtrar).
- 'accepted': is_seed == True OR curation_status == 'accepted'.
- 'seeds_only': is_seed == True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scope
|
str
|
Uno de |
required |
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
Raises:
| Type | Description |
|---|---|
ValueError
|
Si el scope no es reconocido. |
add_paper
¶
add_paper(row: dict[str, object]) -> Corpus
Agrega un paper validando la fila con PaperRow.
Si el id no está presente en el dict, lo calcula automáticamente
con la lógica de D1' (doi > source_id > título+año, ADR 0036).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
row
|
dict[str, object]
|
Diccionario con los datos del paper. Debe incluir al menos
|
required |
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
Raises:
| Type | Description |
|---|---|
SchemaError
|
Si los datos no pasan la validación de |
with_manifest
¶
Devuelve un Corpus nuevo con el mismo contenido y un Manifest distinto.
Semántica de valor: la instancia original no muta nunca. El
corpus_hash del resultado es idéntico al del original porque el
hash es sobre el contenido (tabla), no sobre el manifest.
Uso típico: actualizar openalex_version, equations,
chaining, filters o enrichers en el manifest sin tocar
los datos del backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manifest
|
Manifest
|
Nuevo Manifest a asociar al corpus. |
required |
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
merge
¶
Combina dos Corpus deduplicando por id (idempotente).
Cuando dos filas comparten id, las fusiona campo a campo según D3:
- Escalares: el no-nulo gana; si ambos no-nulos, gana other.
- Listas: unión de sets, ordenada y estable.
- curation_status: decisión humana más reciente (por decided_at
en provenance); si empatan → prioridad accepted > rejected > candidate.
- provenance: log append-only (unión de eventos únicos).
merge es idempotente: c.merge(c) produce un Corpus equivalente.
El orden de filas resultante es determinista: primero las filas de
self en su orden original, luego las filas nuevas de other
(las que no estaban en self) en el orden en que aparecen en other.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Corpus
|
Corpus a fusionar con este. |
required |
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
accept
¶
accept(
ids: list[str],
*,
by: str = "human",
decided_at: datetime | None = None,
) -> Corpus
Marca los papers con los ids dados como 'accepted'.
Agrega un evento al log de provenance con action='accepted',
decided_by y decided_at (ISO8601 UTC). El Corpus original
no muta (semántica de valor).
R2 (ADR 0017 enmendado): decided_at se inyecta desde la frontera
(CLI) para que el núcleo no llame al reloj. Si es None, el
backend usa datetime.now(UTC) como conveniencia para uso como
librería.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
Lista de |
required |
by
|
str
|
Identificador de quien toma la decisión (default |
'human'
|
decided_at
|
datetime | None
|
Instante de la decisión. Si es |
None
|
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
reject
¶
reject(
ids: list[str],
*,
by: str = "human",
decided_at: datetime | None = None,
source: str | None = None,
) -> Corpus
Marca los papers con los ids dados como 'rejected'.
Agrega un evento al log de provenance con action='rejected',
decided_by, source y decided_at (ISO8601 UTC). El Corpus
original no muta (semántica de valor).
R2 (ADR 0017 enmendado): decided_at se inyecta desde la frontera
(CLI) para que el núcleo no llame al reloj. Si es None, el
backend usa datetime.now(UTC) como conveniencia para uso como
librería.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
Lista de |
required |
by
|
str
|
Identificador de quien toma la decisión (default |
'human'
|
decided_at
|
datetime | None
|
Instante de la decisión. Si es |
None
|
source
|
str | None
|
Origen del evento de rechazo (p. ej. criterio de filtro
PRISMA como |
None
|
Returns:
| Type | Description |
|---|---|
Corpus
|
Nuevo |
materialize
¶
Materializa una vista explodida por entidad (author/keyword/institution).
Devuelve una tabla Arrow con una fila por (paper_id, entidad), útil para análisis de co-autoría o co-ocurrencia sin salir de Arrow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
view
|
Literal['author', 'keyword', 'institution']
|
Nombre de la vista a materializar. |
required |
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow con columnas |
Raises:
| Type | Description |
|---|---|
ValueError
|
Si el nombre de vista no es reconocido. |
snapshot
¶
snapshot(path: Path) -> CorpusSnapshot
Exporta una foto sellada del estado actual (parquet + manifest.json).
Crea la carpeta path si no existe, escribe corpus.parquet y
manifest.json con el corpus_hash calculado (D2). NO es la
persistencia (eso es el Store DuckDB); es un export derivable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Directorio donde escribir el snapshot. |
required |
Returns:
| Type | Description |
|---|---|
CorpusSnapshot
|
|
Manifest
¶
Bases: BaseModel
Metadatos sellados del Corpus.
Se serializa a manifest.json junto al corpus.parquet del snapshot.
Los campos obligatorios no tienen default; los opcionales sí (D5).
CorpusSnapshot
¶
Carpeta con corpus.parquet + manifest.json: export sellado.
Reproducible y versionable. No es la biblioteca viva, es su foto.
El corpus se reconstruye en cada acceso desde el parquet (property
lazy).
Methods:
| Name | Description |
|---|---|
load |
Carga un snapshot desde un directorio. |
Attributes:
| Name | Type | Description |
|---|---|---|
path |
Path
|
Directorio del snapshot. |
manifest |
Manifest
|
Manifest del snapshot. |
corpus |
Corpus
|
Reconstruye el Corpus desde el parquet del snapshot. |
corpus
property
¶
corpus: Corpus
Reconstruye el Corpus desde el parquet del snapshot.
Returns:
| Type | Description |
|---|---|
Corpus
|
|
load
classmethod
¶
load(path: Path) -> CorpusSnapshot
Carga un snapshot desde un directorio.
Lee manifest.json y verifica que corpus.parquet exista.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Directorio del snapshot. |
required |
Returns:
| Type | Description |
|---|---|
CorpusSnapshot
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
Si faltan archivos requeridos en el directorio. |
SchemaError
|
Si el manifest.json no es válido. |
SchemaError
¶
Bases: Exception
Violación del schema canónico Arrow del Corpus.
Se lanza con el nombre de la columna y la descripción del problema para que el mensaje sea accionable (lección 7 de v0: fallar fuerte y ruidoso).
TabularBackend
¶
Bases: Protocol
Contrato de almacenamiento tabular para el Corpus.
Cualquier implementación que satisfaga este Protocol puede respaldar un
Corpus. Las reglas de identidad/hash/merge del ADR 0013 (D1/D2/D3)
son contrato de este Protocol: cada implementación debe cumplirlas.
Implementaciones actuales:
- InMemoryBackend (núcleo puro, sin I/O — Hito 1.5).
- DuckDBBackend (biblioteca viva persistida — Hito 3).
Invariantes que toda implementación debe garantizar¶
D1 id estable y determinista (_compute_id de schemas).
D2 corpus_hash order-independent: mismas filas en distinto orden →
mismo hash.
D3 merge idempotente: orden por primera aparición, dedup por id,
resolución de curation_status por decisión humana más reciente.
Methods:
| Name | Description |
|---|---|
to_arrow |
Exporta el contenido completo como tabla Arrow canónica. |
add_paper |
Agrega una fila ya validada y devuelve un backend nuevo. |
merge |
Fusiona |
apply_curation |
Aplica accept/reject a los papers indicados y devuelve backend nuevo. |
filter_view |
Devuelve una tabla Arrow filtrada por la vista pedida. |
corpus_hash |
Computa el hash order-independent del contenido (D2). |
add_referenced_refs |
Appendea IDs backward observados a |
referenced_refs_count |
Número de IDs en |
referenced_refs |
Lista de IDs en |
add_external_id |
Registra un ID externo para un paper dado un motor (ADR 0036 opción C). |
external_ids_for |
Devuelve todos los IDs externos registrados para un paper. |
all_external_ids |
Devuelve todas las entradas de la tabla |
to_arrow
¶
Exporta el contenido completo como tabla Arrow canónica.
Es el puente estable hacia los proyectores y analizadores puros.
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow con el schema canónico del Corpus. |
add_paper
¶
add_paper(row: dict[str, object]) -> TabularBackend
Agrega una fila ya validada y devuelve un backend nuevo.
El id debe estar calculado antes de llamar este método; la
validación PaperRow corre en Corpus.add_paper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
row
|
dict[str, object]
|
Diccionario con todos los campos del schema canónico. |
required |
Returns:
| Type | Description |
|---|---|
TabularBackend
|
Nueva instancia del backend con el paper agregado. |
merge
¶
merge(other_table: Table) -> TabularBackend
Fusiona other_table en este backend (D3).
Devuelve un backend nuevo con el resultado de la fusión. El orden
de filas resultante es determinista: primero las filas de self
en su orden original, luego las filas nuevas de other_table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other_table
|
Table
|
Tabla Arrow a fusionar. |
required |
Returns:
| Type | Description |
|---|---|
TabularBackend
|
Nueva instancia del backend con las filas fusionadas. |
apply_curation
¶
apply_curation(
ids: list[str],
*,
action: str,
by: str,
decided_at: str | None = None,
source: str | None = None,
) -> TabularBackend
Aplica accept/reject a los papers indicados y devuelve backend nuevo.
Agrega un evento al log provenance con action, decided_by,
source y decided_at (ISO8601 UTC). La instancia original no muta.
R2 (ADR 0017 enmendado): decided_at se inyecta desde la frontera
(CLI) para que el núcleo no llame al reloj. Si es None, la
implementación usa datetime.now(UTC) como fallback (ergonomía
para uso como librería sin frontera CLI).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
Lista de |
required |
action
|
str
|
|
required |
by
|
str
|
Identificador de quien toma la decisión. |
required |
decided_at
|
str | None
|
Timestamp ISO8601 UTC de la decisión. Si es |
None
|
source
|
str | None
|
Origen del evento (p. ej. criterio de filtro PRISMA).
Si es |
None
|
Returns:
| Type | Description |
|---|---|
TabularBackend
|
Nueva instancia del backend con la curación aplicada. |
filter_view
¶
Devuelve una tabla Arrow filtrada por la vista pedida.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
view
|
Literal['seeds', 'candidates', 'accepted']
|
|
required |
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
corpus_hash
¶
Computa el hash order-independent del contenido (D2).
Returns:
| Type | Description |
|---|---|
str
|
Hexdigest SHA-256 del contenido de la tabla. |
add_referenced_refs
¶
Appendea IDs backward observados a referenced_but_not_fetched (#54).
Solo inserta los IDs que aún no están en la tabla (idempotente).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref_ids
|
list[str]
|
IDs de OpenAlex observados en backward chaining. |
required |
cycle_round
|
int
|
Número de ronda del ciclo en curso. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Número de IDs nuevos insertados. |
referenced_refs_count
¶
Número de IDs en referenced_but_not_fetched.
Returns:
| Type | Description |
|---|---|
int
|
Conteo total de filas en la tabla auxiliar. |
referenced_refs
¶
Lista de IDs en referenced_but_not_fetched, en orden de inserción.
Returns:
| Type | Description |
|---|---|
list[str]
|
Lista de |
add_external_id
¶
Registra un ID externo para un paper dado un motor (ADR 0036 opción C).
Idempotente: si ya existe una entrada (paper_id, engine), el valor
se reemplaza (un ID por motor por paper).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
engine
|
str
|
Nombre del motor / fuente del ID (p. ej. |
required |
id
|
str
|
El ID externo correspondiente a ese motor. |
required |
external_ids_for
¶
Devuelve todos los IDs externos registrados para un paper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Diccionario |
dict[str, str]
|
ese paper. Vacío si el paper no tiene IDs externos registrados. |
all_external_ids
¶
Devuelve todas las entradas de la tabla external_ids.
Returns:
| Type | Description |
|---|---|
list[tuple[str, str, str]]
|
Lista de tuplas |
InMemoryBackend
¶
Backend puro en Python: almacena el corpus como pa.Table en memoria.
Preserva la lógica de mutación del Corpus del Hito 1 (to_pylist() →
mutar en Python → reconstruir la tabla Arrow). No tiene I/O ni
dependencias externas; es el backend de referencia para los tests.
Semántica de valor: todas las operaciones mutantes devuelven una nueva instancia; la original no cambia nunca.
Ref #54: almacena también los IDs backward observados en _referenced_refs
(lista en memoria, equivalente a la tabla referenced_but_not_fetched
de DuckDBBackend).
Methods:
| Name | Description |
|---|---|
to_arrow |
Devuelve la tabla Arrow interna. |
add_paper |
Agrega una fila al backend y devuelve una nueva instancia. |
merge |
Fusiona |
apply_curation |
Aplica accept/reject a los ids indicados y devuelve una nueva instancia. |
filter_view |
Devuelve la tabla filtrada según la vista pedida. |
corpus_hash |
Computa el hash order-independent del contenido (D2). |
add_referenced_refs |
Appendea IDs backward observados a la tabla auxiliar en memoria. |
referenced_refs_count |
Número de IDs en la tabla auxiliar. |
referenced_refs |
Lista de IDs en la tabla auxiliar, en orden de inserción. |
add_external_id |
Registra un ID externo para un paper dado un motor. |
external_ids_for |
Devuelve todos los IDs externos registrados para un paper. |
all_external_ids |
Devuelve todas las entradas de la tabla |
to_arrow
¶
Devuelve la tabla Arrow interna.
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow con el schema canónico. |
add_paper
¶
add_paper(row: dict[str, object]) -> InMemoryBackend
Agrega una fila al backend y devuelve una nueva instancia.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
row
|
dict[str, object]
|
Fila ya validada con todos los campos del schema. |
required |
Returns:
| Type | Description |
|---|---|
InMemoryBackend
|
Nueva instancia con el paper agregado. |
merge
¶
merge(other_table: Table) -> InMemoryBackend
Fusiona other_table respetando D3 y devuelve una nueva instancia.
Orden: filas de self primero, luego filas nuevas de other_table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other_table
|
Table
|
Tabla Arrow a fusionar. |
required |
Returns:
| Type | Description |
|---|---|
InMemoryBackend
|
Nueva instancia con las filas fusionadas. |
apply_curation
¶
apply_curation(
ids: list[str],
*,
action: str,
by: str,
decided_at: str | None = None,
source: str | None = None,
) -> InMemoryBackend
Aplica accept/reject a los ids indicados y devuelve una nueva instancia.
R2: decided_at se inyecta desde la frontera (CLI). Si es None,
_apply_curation_to_rows usa datetime.now(UTC) como fallback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
Lista de |
required |
action
|
str
|
|
required |
by
|
str
|
Identificador de quien decide. |
required |
decided_at
|
str | None
|
Timestamp ISO8601 UTC de la decisión (inyectado desde
la frontera CLI; |
None
|
source
|
str | None
|
Origen del evento (p. ej. criterio de filtro PRISMA).
Si es |
None
|
Returns:
| Type | Description |
|---|---|
InMemoryBackend
|
Nueva instancia con la curación aplicada. |
filter_view
¶
Devuelve la tabla filtrada según la vista pedida.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
view
|
Literal['seeds', 'candidates', 'accepted']
|
|
required |
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Si el nombre de vista no es reconocido. |
corpus_hash
¶
Computa el hash order-independent del contenido (D2).
Returns:
| Type | Description |
|---|---|
str
|
Hexdigest SHA-256 del contenido de la tabla. |
add_referenced_refs
¶
Appendea IDs backward observados a la tabla auxiliar en memoria.
Solo inserta los que aún no están (idempotente). cycle_round se
acepta por compatibilidad con el protocolo pero no se persiste en
memoria (el backend en memoria no necesita auditoría de ronda).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref_ids
|
list[str]
|
IDs de OpenAlex observados en backward chaining. |
required |
cycle_round
|
int
|
Número de ronda del ciclo en curso (ignorado en memoria). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Número de IDs nuevos insertados. |
referenced_refs_count
¶
Número de IDs en la tabla auxiliar.
Returns:
| Type | Description |
|---|---|
int
|
Conteo total. |
referenced_refs
¶
Lista de IDs en la tabla auxiliar, en orden de inserción.
Returns:
| Type | Description |
|---|---|
list[str]
|
Lista de |
add_external_id
¶
Registra un ID externo para un paper dado un motor.
Idempotente: si ya existe una entrada (paper_id, engine), el valor
se reemplaza (un ID por motor por paper).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
engine
|
str
|
Nombre del motor / fuente del ID (p. ej. |
required |
id
|
str
|
El ID externo correspondiente a ese motor. |
required |
external_ids_for
¶
Devuelve todos los IDs externos registrados para un paper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Diccionario |
dict[str, str]
|
ese paper. Vacío si el paper no tiene IDs externos registrados. |
all_external_ids
¶
Devuelve todas las entradas de la tabla external_ids.
Usado internamente para tests de paridad con DuckDBBackend.
Returns:
| Type | Description |
|---|---|
list[tuple[str, str, str]]
|
Lista de tuplas |
DuckDBStore
¶
Fachada de persistencia sobre DuckDBBackend (ADR 0009, 0015).
Implementa el Protocol Store: persist / load.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Ruta al archivo |
required |
Methods:
| Name | Description |
|---|---|
persist |
Persiste el corpus en la biblioteca viva (idempotente). |
persist_replace |
Reemplaza toda la tabla |
load |
Carga el corpus acumulado desde la biblioteca viva. |
close |
Cierra la conexión DuckDB y libera el lock de archivo. |
Attributes:
| Name | Type | Description |
|---|---|---|
backend |
DuckDBBackend
|
Acceso directo al |
backend
property
¶
backend: DuckDBBackend
Acceso directo al DuckDBBackend subyacente.
Permite usar extensiones propias como loop_state(),
set_loop_state() y query(sql).
Returns:
| Type | Description |
|---|---|
DuckDBBackend
|
El |
persist
¶
persist(corpus: Corpus) -> None
Persiste el corpus en la biblioteca viva (idempotente).
Hace un merge del corpus entrante en el backend persistido.
Idempotente: persistir el mismo corpus dos veces no duplica filas
(el upsert por id garantiza la idempotencia, D1/D3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corpus
|
Corpus
|
El |
required |
persist_replace
¶
persist_replace(corpus: Corpus) -> None
Reemplaza toda la tabla corpus con el contenido de corpus.
Equivale a TRUNCATE + INSERT: el estado en disco queda siendo
exactamente el corpus dado, sin residuos de variantes previas.
Preserva las tablas hermanas (loop_state_log,
referenced_but_not_fetched).
Úsalo en la ruta de ingesta (seed, restore, chain, thesaurus) donde
ya tenés el corpus completo y deduplcado en memoria. Para el caso
«acumular papers de una nueva fuente sin dedup cross-biblioteca»,
seguí usando persist (upsert-concat D3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corpus
|
Corpus
|
El |
required |
load
¶
load() -> Corpus
Carga el corpus acumulado desde la biblioteca viva.
Devuelve un Corpus respaldado por el DuckDBBackend del
archivo; las operaciones subsecuentes (accept, reject,
merge) mutarán el archivo en disco.
Ref #126: reconstruye manifest.filters desde filter_log para que
los pasos PRISMA persistan entre sesiones.
Ref #141: reconstruye manifest.enrichers desde enricher_log para
que los EnricherRef persistan entre sesiones.
Returns:
| Type | Description |
|---|---|
Corpus
|
El |
close
¶
Cierra la conexión DuckDB y libera el lock de archivo.
Delega en DuckDBBackend.close(). Idempotente: llamarlo varias
veces no lanza error. Debe llamarse explícitamente en comandos que
abren el store y terminan (run_seed_from_bib, run_seed, etc.)
para garantizar que el lock se libera antes de la siguiente apertura
en el mismo proceso, especialmente en Linux donde DuckDB no libera
el lock al hacer GC del objeto.
DuckDBBackend
¶
Backend de biblioteca viva persistida en DuckDB (ADR 0009, 0015).
Implementa el Protocol TabularBackend con mutaciones por SQL puro
(INSERT … ON CONFLICT DO UPDATE por id), cumpliendo D1/D2/D3
(ADR 0013).
Semántica de valor: todas las operaciones mutantes (add_paper,
merge, apply_curation) devuelven una nueva instancia que
comparte la misma ruta de archivo pero refleja el estado actualizado.
Internamente cada instancia tiene su propia conexión; la semántica de
valor se mantiene porque cada operación crea una nueva instancia.
CycleState (ADR 0016): extensión propia con loop_state() y
set_loop_state().
ADR 0024: el orden D3 se garantiza mediante la columna interna _seq
(número de secuencia de primera aparición). to_arrow() devuelve
exactamente CORPUS_SCHEMA (sin _seq) ordenado por _seq.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table
|
Table | None
|
Tabla Arrow inicial. Si se pasa, se hace upsert de sus filas
en la base de datos. Permite inicializar desde |
None
|
path
|
str | Path | None
|
Ruta al archivo |
None
|
Methods:
| Name | Description |
|---|---|
to_arrow |
Exporta el contenido completo como tabla Arrow canónica. |
add_paper |
Agrega (upsert) una fila al backend y devuelve una nueva instancia. |
merge |
Fusiona |
apply_curation |
Aplica accept/reject a los papers indicados y devuelve backend nuevo. |
filter_view |
Devuelve la tabla filtrada según la vista pedida. |
corpus_hash |
Computa el hash order-independent del contenido (D2). |
loop_state |
Estado actual del lazo de investigación. |
loop_round |
Número de ronda actual del lazo. |
set_loop_state |
Registra una transición de |
add_referenced_refs |
Appendea IDs backward observados a |
referenced_refs_count |
Número de IDs en |
referenced_refs |
Lista de IDs en |
add_external_id |
Registra un ID externo para un paper dado un motor. |
external_ids_for |
Devuelve todos los IDs externos registrados para un paper. |
all_external_ids |
Devuelve todas las entradas de la tabla |
persist_filter_steps |
Persiste los pasos de filtro PRISMA en |
load_filter_steps |
Carga los pasos de filtro PRISMA desde |
persist_enricher_refs |
Persiste las referencias de enriquecedor en |
load_enricher_refs |
Carga las referencias de enriquecedor desde |
close |
Cierra la conexión DuckDB subyacente y libera el lock de archivo. |
overwrite_corpus |
Reemplaza TODA la tabla |
query |
Ejecuta una consulta SQL sobre el backend y devuelve tabla Arrow. |
to_arrow
¶
Exporta el contenido completo como tabla Arrow canónica.
Impone el schema exacto de CORPUS_SCHEMA (orden y tipos).
Valida con validate_table antes de devolver.
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow con el schema canónico del Corpus (sin |
add_paper
¶
add_paper(row: dict[str, object]) -> DuckDBBackend
Agrega (upsert) una fila al backend y devuelve una nueva instancia.
ADR 0024: asigna _seq = COALESCE(MAX(_seq), 0) + 1 para que la
fila nueva quede al final del orden de primera aparición (D3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
row
|
dict[str, object]
|
Fila ya validada con todos los campos del schema. |
required |
Returns:
| Type | Description |
|---|---|
DuckDBBackend
|
Nueva instancia con el paper agregado. |
merge
¶
merge(other_table: Table) -> DuckDBBackend
Fusiona other_table respetando D3 y devuelve una nueva instancia.
ADR 0024: el orden D3 (filas de self primero en su orden original,
luego las nuevas filas de other_table en su orden de aparición) se
garantiza por la columna interna _seq:
- Filas de self ya tienen _seq asignado (se preservan en el
UPDATE, que no actualiza _seq).
- Filas nuevas de other_table reciben _seq mayor, calculado
con ROW_NUMBER() OVER (ORDER BY _row_idx) desde MAX(_seq)
en _upsert_table; la columna auxiliar _row_idx (índice
0-based del lote Arrow) garantiza que el orden de primera aparición
se preserve de forma determinista, sin depender del scan de DuckDB.
- _arrow_table_from_con lee con ORDER BY _seq.
No se requiere DELETE+reinsert.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other_table
|
Table
|
Tabla Arrow a fusionar. |
required |
Returns:
| Type | Description |
|---|---|
DuckDBBackend
|
Nueva instancia con las filas fusionadas, en orden D3. |
apply_curation
¶
apply_curation(
ids: list[str],
*,
action: str,
by: str,
decided_at: str | None = None,
source: str | None = None,
) -> DuckDBBackend
Aplica accept/reject a los papers indicados y devuelve backend nuevo.
Reutiliza _apply_curation_to_rows de backends.memory para
garantizar equivalencia exacta con InMemoryBackend.
R2: decided_at se inyecta desde la frontera (CLI). Si es None,
_apply_curation_to_rows usa datetime.now(UTC) como fallback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
Lista de |
required |
action
|
str
|
|
required |
by
|
str
|
Identificador de quien decide. |
required |
decided_at
|
str | None
|
Timestamp ISO8601 UTC de la decisión (inyectado desde
la frontera CLI; |
None
|
source
|
str | None
|
Origen del evento (p. ej. criterio de filtro PRISMA).
Si es |
None
|
Returns:
| Type | Description |
|---|---|
DuckDBBackend
|
Nueva instancia con la curación aplicada. |
filter_view
¶
Devuelve la tabla filtrada según la vista pedida.
ADR 0024: usa SELECT * EXCLUDE (_seq) … ORDER BY _seq para
mantener el orden D3 y excluir la columna interna del resultado.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
view
|
Literal['seeds', 'candidates', 'accepted']
|
|
required |
Returns:
| Type | Description |
|---|---|
Table
|
Tabla Arrow filtrada. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Si la vista no es reconocida. |
corpus_hash
¶
Computa el hash order-independent del contenido (D2).
Se computa siempre sobre to_arrow() usando la misma función
que InMemoryBackend (ADR 0015, ADR 0013 D2).
Returns:
| Type | Description |
|---|---|
str
|
Hexdigest SHA-256 del contenido de la tabla. |
loop_state
¶
Estado actual del lazo de investigación.
Lee la última fila de loop_state_log (log append-only).
Returns:
| Type | Description |
|---|---|
CycleState | None
|
El |
loop_round
¶
Número de ronda actual del lazo.
Lee la columna round de la última fila de loop_state_log.
Devuelve 0 cuando no hay transiciones (sin estado previo) o cuando
la columna es NULL (bases migradas desde antes de R3).
Returns:
| Type | Description |
|---|---|
int
|
Entero >= 0. 0 = sin estado; 1 = primera ronda; 2+ = re-sembrados. |
set_loop_state
¶
Registra una transición de CycleState (transición permisiva).
Agrega una fila al log append-only loop_state_log. No bloquea
ningún salto (ADR 0016: transiciones permisivas).
R3: persiste también el número de ronda. Si cycle_round es None,
conserva la ronda actual (útil para transiciones dentro de la misma
ronda, p. ej. chain/filter/build).
La curación (accept/reject) es TRANSVERSAL y NO llama
set_loop_state: no transiciona el lazo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
CycleState
|
El nuevo estado del lazo. |
required |
cycle_round
|
int | None
|
Número de ronda a persistir. Si es |
None
|
add_referenced_refs
¶
Appendea IDs backward observados a referenced_but_not_fetched.
No duplica IDs ya presentes (idempotencia basada en existencia): solo
inserta los que aún no están en la tabla, independientemente del
cycle_round. El observed_at lo provee now() de DuckDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref_ids
|
list[str]
|
IDs de OpenAlex observados en backward chaining. |
required |
cycle_round
|
int
|
Número de ronda del ciclo en curso. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Número de IDs nuevos insertados (0 si todos ya existían). |
referenced_refs_count
¶
Número de IDs en referenced_but_not_fetched.
Returns:
| Type | Description |
|---|---|
int
|
Conteo total de filas en la tabla auxiliar. |
referenced_refs
¶
Lista de IDs en referenced_but_not_fetched, ordenados por observed_at.
Returns:
| Type | Description |
|---|---|
list[str]
|
Lista de |
add_external_id
¶
Registra un ID externo para un paper dado un motor.
Idempotente: si ya existe una entrada (paper_id, engine), el valor
se reemplaza (un ID por motor por paper). La PK lógica
(paper_id, engine) garantiza que no haya duplicados.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
engine
|
str
|
Nombre del motor / fuente del ID (p. ej. |
required |
id
|
str
|
El ID externo correspondiente a ese motor. |
required |
external_ids_for
¶
Devuelve todos los IDs externos registrados para un paper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
ID interno del paper en el corpus. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Diccionario |
dict[str, str]
|
ese paper. Vacío si el paper no tiene IDs externos registrados. |
all_external_ids
¶
Devuelve todas las entradas de la tabla external_ids.
Usado internamente para _clone() y tests de paridad.
Returns:
| Type | Description |
|---|---|
list[tuple[str, str, str]]
|
Lista de tuplas |
persist_filter_steps
¶
Persiste los pasos de filtro PRISMA en filter_log.
Ref #126 — trazabilidad PRISMA: los pasos aplicados en b2g filter
se guardan para que manifest.filters sobreviva entre cargas del
store.
Por defecto (replace=True) limpia los pasos anteriores antes de
insertar los nuevos: cada invocación de b2g filter reemplaza el
registro previo completo (idempotencia de run_filter).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
steps
|
list[object]
|
Lista de |
required |
replace
|
bool
|
Si es |
True
|
load_filter_steps
¶
Carga los pasos de filtro PRISMA desde filter_log.
Ref #126 — trazabilidad PRISMA: permite que DuckDBStore.load()
reconstruya manifest.filters con los pasos persistidos.
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
Lista de dicts con las claves |
list[dict[str, object]]
|
|
persist_enricher_refs
¶
Persiste las referencias de enriquecedor en enricher_log.
Ref #141 — trazabilidad de enriquecimiento: los EnricherRef aplicados
en b2g enrich / b2g chain / b2g build se guardan para que
manifest.enrichers sobreviva entre cargas del store.
Por defecto (replace=True) limpia las entradas anteriores antes de
insertar las nuevas: cada invocación reemplaza el registro completo
(idempotencia; el EnricherRef se identifica por nombre, ADR 0025).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
refs
|
list[object]
|
Lista de |
required |
replace
|
bool
|
Si es |
True
|
load_enricher_refs
¶
Carga las referencias de enriquecedor desde enricher_log.
Ref #141 — trazabilidad de enriquecimiento: permite que
DuckDBStore.load() reconstruya manifest.enrichers con los
EnricherRef persistidos.
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
Lista de dicts con las claves |
list[dict[str, Any]]
|
|
close
¶
Cierra la conexión DuckDB subyacente y libera el lock de archivo.
Idempotente: llamarlo varias veces o sobre una conexión ya cerrada
no lanza error. Necesario en contextos donde se abren múltiples
instancias sobre el mismo archivo en el mismo proceso (p. ej. dos
llamadas consecutivas a run_seed_from_bib sobre el mismo path):
Linux/DuckDB mantiene el lock de archivo hasta que la conexión se
cierra explícitamente; depender del GC causa segfault.
overwrite_corpus
¶
Reemplaza TODA la tabla corpus con el contenido de table.
Hace TRUNCATE + INSERT masivo (no upsert fila-a-fila) para que el estado
en disco sea exactamente table, sin residuos de filas previas.
Preserva las tablas hermanas (loop_state_log,
referenced_but_not_fetched).
Úsalo solo en la ruta de ingesta (seed, restore, chain,
thesaurus) donde ya tenés el corpus completo y correcto en
memoria. El upsert normal (_upsert_table) sigue siendo correcto
para el caso «mismo paper desde dos fuentes» (D3); este método NO lo
reemplaza en ese contexto.
ADR 0024: reasigna _seq desde 0 sobre la tabla limpia, manteniendo
el orden de filas que viene en table (que ya salió de
to_arrow() con ORDER BY _seq original).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table
|
Table
|
Tabla Arrow con exactamente el contenido final a persistir.
Debe cumplir |
required |
query
¶
Ejecuta una consulta SQL sobre el backend y devuelve tabla Arrow.
Solo para lectura (no muta el estado).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sql
|
str
|
Sentencia SQL SELECT a ejecutar. |
required |
Returns:
| Type | Description |
|---|---|
Table
|
Resultado como tabla Arrow. |