← Volver al índice | Arquitectura del Sistema | Arquitectura IA
Modelo de Datos¶
Tipo: Documentación Técnica — Modelo de Datos
Audiencia: Equipo de desarrollo backend, DBA, arquitectos
Fecha: 20 de marzo de 2026
Relacionado con: Arquitectura del Sistema | MLOps y Workflows Agénticos | Docker Compose
1. Visión General¶
El modelo de datos se compone de dos sistemas complementarios:
- PostgreSQL + pgvector: Datos relacionales y vectores de embedding
- ChromaDB: Almacenamiento vectorial dedicado para búsqueda por similitud
flowchart LR
subgraph PG ["PostgreSQL + pgvector"]
REL["Datos relacionales"]
VEC["Vectores - pgvector"]
end
subgraph CHR ["ChromaDB"]
COL["Colecciones vectoriales"]
META["Metadatos de documentos"]
end
subgraph MIN ["MinIO"]
IMG["Imágenes originales"]
ARCH["Archivos adjuntos"]
end
REL <-->|"FK / joins"| VEC
VEC <-->|"sincronización"| COL
REL -->|"ruta S3"| IMG
style PG fill:#3498db,color:#fff
style CHR fill:#f39c12,color:#fff
style MIN fill:#2ecc71,color:#fff
2. Schema PostgreSQL — Diagrama ER Completo¶
erDiagram
DEPARTAMENTO ||--o{ INVESTIGADOR : pertenece
DEPARTAMENTO ||--o{ COLECCION : gestiona
DEPARTAMENTO ||--o{ FUENTE_DATOS : monitoriza
COLECCION ||--o{ MUESTRA : contiene
MUESTRA ||--o{ IMAGEN_MUESTRA : tiene
MUESTRA ||--o{ PARAMETRO_BIOLOGICO : mide
MUESTRA }o--|| ESPECIE : identifica
ESPECIE ||--o{ TAXONOMIA : clasifica
MUESTRA }o--|| CAMPANA : proviene
CAMPANA }o--|| ZONA_GEOGRAFICA : realizada_en
IMAGEN_MUESTRA ||--|| EMBEDDING_VECTOR : genera
INVESTIGADOR ||--o{ IDENTIFICACION_IA : realiza
INVESTIGADOR ||--o{ FUENTE_DATOS : crea
IDENTIFICACION_IA }o--|| MUESTRA : sobre
IDENTIFICACION_IA }o--|| ESPECIE : sugiere
IDENTIFICACION_IA }o--|| MODELO_REGISTRO : usa
MODELO_REGISTRO }o--|| DEPARTAMENTO : sirve
DEPARTAMENTO {
uuid id PK
string nombre
string descripcion
string responsable
timestamp created_at
}
INVESTIGADOR {
uuid id PK
uuid departamento_id FK
string nombre_completo
string email
string entra_id
string rol
boolean activo
timestamp created_at
}
COLECCION {
uuid id PK
uuid departamento_id FK
string nombre
string tipo_preservacion
int total_especimenes
date fecha_inicio
string descripcion
timestamp created_at
}
MUESTRA {
uuid id PK
uuid coleccion_id FK
uuid especie_id FK
uuid campana_id FK
string codigo_interno
date fecha_captura
string metodo_captura
float latitud
float longitud
string estado_conservacion
jsonb metadatos_extra
timestamp created_at
timestamp updated_at
}
ESPECIE {
uuid id PK
string nombre_cientifico
string nombre_comun
string familia
string orden
string clase
string phylum
string reino
}
TAXONOMIA {
uuid id PK
uuid especie_id FK
string nivel
string valor
string fuente
}
PARAMETRO_BIOLOGICO {
uuid id PK
uuid muestra_id FK
float talla_cm
float peso_g
string sexo
string madurez_gonadal
int edad_estimada
string metodo_edad
float indice_gonadosomatico
jsonb datos_adicionales
}
CAMPANA {
uuid id PK
uuid zona_id FK
string nombre
string buque
date fecha_inicio
date fecha_fin
string tipo
int muestras_totales
}
ZONA_GEOGRAFICA {
uuid id PK
string nombre
string mar
float lat_centro
float lon_centro
string geometria_wkt
}
IMAGEN_MUESTRA {
uuid id PK
uuid muestra_id FK
string ruta_s3
string tipo_imagen
int ancho_px
int alto_px
jsonb metadatos_exif
timestamp fecha_captura
}
EMBEDDING_VECTOR {
uuid id PK
uuid imagen_id FK
string modelo_embedding
vector embedding_768d
float confidence_score
timestamp generado_at
}
IDENTIFICACION_IA {
uuid id PK
uuid muestra_id FK
uuid especie_sugerida_id FK
uuid investigador_id FK
string modelo_utilizado
float confianza
string edad_estimada
string sexo_estimado
jsonb top_k_similares
boolean confirmada
timestamp created_at
}
FUENTE_DATOS {
uuid id PK
uuid departamento_id FK
uuid responsable_id FK
string nombre
string tipo
jsonb configuracion
string periodicidad
string esquema_esperado
boolean activa
timestamp ultima_ejecucion
timestamp created_at
}
MODELO_REGISTRO {
uuid id PK
uuid departamento_id FK
string nombre
string version
string stage
string dataset_entrenamiento
float precision_val
float vram_gb
string ruta_pesos
string mlflow_run_id
timestamp desplegado_at
timestamp created_at
}
3. Detalle de Tablas Principales¶
3.1 muestra¶
Tabla central del sistema. Cada muestra biológica se registra aquí.
| Columna | Tipo | Descripción |
|---|---|---|
id |
UUID PK |
Identificador único |
coleccion_id |
UUID FK |
Colección a la que pertenece |
especie_id |
UUID FK |
Especie identificada (puede ser NULL si pendiente) |
campana_id |
UUID FK |
Campaña de origen (puede ser NULL) |
codigo_interno |
VARCHAR(50) |
Código del IEO (ej: IEOMA-CFM-0001) |
fecha_captura |
DATE |
Fecha de recolección |
metodo_captura |
VARCHAR(100) |
Arrastre, palangre, nasas, etc. |
latitud / longitud |
FLOAT |
Coordenadas GPS de captura |
estado_conservacion |
VARCHAR(50) |
Líquido, seco, fresco |
metadatos_extra |
JSONB |
Datos adicionales flexibles |
3.2 embedding_vector¶
Almacena los vectores de embedding generados por el modelo de visión.
| Columna | Tipo | Descripción |
|---|---|---|
id |
UUID PK |
Identificador único |
imagen_id |
UUID FK |
Imagen de origen |
modelo_embedding |
VARCHAR(100) |
Nombre del modelo (ej: clip-vit-l-14) |
embedding_768d |
VECTOR(768) |
Vector de embedding (pgvector) |
confidence_score |
FLOAT |
Confianza del embedding |
3.3 identificacion_ia¶
Registro de cada identificación realizada por el motor de IA.
| Columna | Tipo | Descripción |
|---|---|---|
id |
UUID PK |
Identificador único |
muestra_id |
UUID FK |
Muestra analizada |
especie_sugerida_id |
UUID FK |
Especie propuesta por la IA |
investigador_id |
UUID FK |
Quién solicitó la identificación |
modelo_utilizado |
VARCHAR(100) |
Modelo (ej: qwen25-vl-7b) |
confianza |
FLOAT |
Score de confianza (0.0 - 1.0) |
top_k_similares |
JSONB |
Array de {muestra_id, score} similares |
confirmada |
BOOLEAN |
Si el investigador validó el resultado |
3.4 fuente_datos¶
Fuentes de datos externas monitorizadas dinámicamente. Configuradas desde la UI por Responsables de Departamento sin necesidad de despliegues. Ver MLOps y Workflows Agénticos para la arquitectura de dos niveles (YAML infra vs BBDD dinámica).
| Columna | Tipo | Descripción |
|---|---|---|
id |
UUID PK |
Identificador único |
departamento_id |
UUID FK |
Departamento propietario |
responsable_id |
UUID FK |
Investigador que creó/gestiona la fuente |
nombre |
VARCHAR(200) |
Nombre descriptivo (ej: «Biometrías ECOMED 2025») |
tipo |
VARCHAR(50) |
sharepoint, gsheet, mqtt, oracle_cdc, copernicus |
configuracion |
JSONB |
Datos de conexión: ruta, sheetId, topic, etc. |
periodicidad |
VARCHAR(20) |
15min, 1h, diario, tiempo_real |
esquema_esperado |
JSONB |
JSON Schema para validación de entrada |
activa |
BOOLEAN |
Pausar/activar sin reiniciar el sistema |
ultima_ejecucion |
TIMESTAMP |
Última comprobación exitosa |
3.5 modelo_registro¶
Registro de modelos de IA gestionados por MLflow. Cada fila representa una versión de un modelo desplegada o en staging.
| Columna | Tipo | Descripción |
|---|---|---|
id |
UUID PK |
Identificador único |
departamento_id |
UUID FK |
Departamento al que sirve el modelo |
nombre |
VARCHAR(100) |
Nombre del modelo (ej: YOLOv11-FathomNet) |
version |
VARCHAR(20) |
Versión semántica (ej: v2.1) |
stage |
VARCHAR(20) |
Staging, Production, Archived |
dataset_entrenamiento |
VARCHAR(200) |
Dataset usado (ej: «ICES SmartDots + IEO») |
precision_val |
FLOAT |
Métrica de precisión en validación |
vram_gb |
FLOAT |
VRAM requerida en GB |
ruta_pesos |
VARCHAR(500) |
Ruta en MinIO a los pesos del modelo |
mlflow_run_id |
VARCHAR(100) |
ID del run en MLflow para trazabilidad |
desplegado_at |
TIMESTAMP |
Fecha de último despliegue a producción |
4. Índices y Rendimiento¶
4.1 Índices PostgreSQL¶
-- Búsqueda por código interno del IEO
CREATE UNIQUE INDEX idx_muestra_codigo ON muestra(codigo_interno);
-- Búsqueda geográfica
CREATE INDEX idx_muestra_geo ON muestra(latitud, longitud);
-- Búsqueda temporal
CREATE INDEX idx_muestra_fecha ON muestra(fecha_captura);
-- Búsqueda por especie
CREATE INDEX idx_muestra_especie ON muestra(especie_id);
-- Búsqueda por colección
CREATE INDEX idx_muestra_colección ON muestra(coleccion_id);
-- Índice vectorial para búsqueda por similitud (pgvector)
CREATE INDEX idx_embedding_ivfflat ON embedding_vector
USING ivfflat (embedding_768d vector_cosine_ops)
WITH (lists = 100);
-- Búsqueda de identificaciones pendientes de confirmar
CREATE INDEX idx_identificacion_pendiente ON identificacion_ia(confirmada)
WHERE confirmada = false;
-- Fuentes de datos activas por departamento
CREATE INDEX idx_fuente_activa ON fuente_datos(departamento_id, activa)
WHERE activa = true;
-- Modelos en producción
CREATE INDEX idx_modelo_produccion ON modelo_registro(stage)
WHERE stage = 'Production';
4.2 Rendimiento Esperado¶
| Operación | Objetivo | Índice Utilizado |
|---|---|---|
| Búsqueda por código IEO | < 1ms | idx_muestra_codigo |
| Búsqueda por similitud vectorial (top-10) | < 50ms | idx_embedding_ivfflat |
| Listado por campaña + especie | < 10ms | idx_muestra_especie + idx_muestra_fecha |
| Identificaciones pendientes de confirmar | < 5ms | idx_identificacion_pendiente |
5. Colecciones ChromaDB¶
ChromaDB almacena colecciones vectoriales optimizadas para búsqueda por similitud de imágenes.
5.1 Colecciones del MVP¶
| Colección | Contenido | Metadata |
|---|---|---|
ieo_specimens |
Embeddings de imágenes de especímenes | especie, coleccion, fecha |
ieo_otoliths |
Embeddings de microfotografías de otolitos | especie, edad, zona |
ieo_documents |
Embeddings de chunks de documentos | tipo, departamento, fecha |
5.2 Ejemplo de Inserción¶
collection = client.get_or_create_collection(
name="ieo_specimens",
metadata={"hnsw:space": "cosine"}
)
collection.add(
ids=["specimen-001"],
embeddings=[[0.12, -0.34, 0.56, ...]], # 768d
metadatas=[{
"especie": "Mullus surmuletus",
"coleccion": "CFM-HISTORICA-IEOMA",
"fecha": "1907-01-01",
"muestra_pg_id": "uuid-en-postgresql"
}],
documents=["Salmonete de roca, Mediterráneo occidental"]
)
6. Estrategia de Migraciones¶
6.1 Herramienta¶
- Liquibase integrado con Quarkus (
quarkus-liquibase) - Changesets en formato YAML/XML en
/backend/src/main/resources/db/changelog/ - Changelog master:
db.changelog-master.yaml
6.2 Changesets Planificados¶
| Changeset | Descripción |
|---|---|
001-create-schema.yaml |
Tablas base: departamento, investigador, colección, muestra, especie |
002-create-ia-tables.yaml |
Tablas de IA: imagen_muestra, embedding_vector, identificacion_ia |
003-create-indexes.yaml |
Índices de rendimiento y vectoriales |
004-seed-taxonomia.yaml |
Datos iniciales: taxonomías del proyecto TAXON |
005-seed-colecciones.yaml |
Datos iniciales: colecciones históricas CFM |
006-create-fuente-datos.yaml |
Tabla de fuentes de datos dinámicas |
007-create-modelo-registro.yaml |
Tabla de registro de modelos MLOps |
7. Sincronización PostgreSQL — ChromaDB¶
sequenceDiagram
participant API4 as Quarkus API
participant PG2 as PostgreSQL
participant EMB4 as Modelo Embeddings
participant CHR3 as ChromaDB
Note over API4: Al registrar nueva imagen
API4->>PG2: INSERT imagen_muestra
API4->>EMB4: Genera embedding
EMB4-->>API4: Vector 768d
API4->>PG2: INSERT embedding_vector
API4->>CHR3: Upsert en colección
Note over PG2,CHR3: PostgreSQL es fuente de verdad
[!IMPORTANT] PostgreSQL es la fuente de verdad. ChromaDB es un índice secundario optimizado para búsqueda vectorial. En caso de inconsistencia, se regenera la colección ChromaDB desde PostgreSQL.
Documentos Relacionados¶
| Nivel | Documento | Descripción |
|---|---|---|
| Arquitectura | Arquitectura del Sistema | Visión general, stack, flujos |
| Arquitectura | Arquitectura IA | Pipeline IA, embeddings, modelos |
| Arquitectura | MLOps y Workflows Agénticos | FuenteDatos, ModeloRegistro, sistema agéntico |
| Investigación | Gobernanza de Datasets | Fuentes de datos, carga incremental |
| Investigación | Bancos de Datos Animales | Fuentes intl., APIs, datasets de imágenes, almacenamiento |
| Especificación | API REST | Endpoints que operan sobre estos datos |
| Infraestructura | Docker Compose | Servicios PostgreSQL, ChromaDB |