Files
archivdms/internal/storage/migrations/020_ml_classifier.sql
T
patrick 9a24ea29e1 FDN-01: repository & projektgerüst
Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
2026-08-11 21:27:53 +02:00

56 lines
3.0 KiB
SQL

-- PROJ: ML-Retraining-Klassifizierung Phase 1 (Naive-Bayes)
-- Doku-only (siehe README.md in diesem Verzeichnis) — die tatsächliche
-- Ausführung passiert idempotent über
-- internal/storage/ml_classifier.go (*Store).initMLClassifierSchema(),
-- eingehängt in internal/storage/documents.go (*Store).initSchema() NACH
-- initTaxonomySchema (setzt document_types/correspondents/tags/document_tags/
-- documents voraus).
--
-- Ergänzt die bestehende Regel-Engine (Taxonomie-Matching) um ein optionales,
-- pro Mandant trainiertes Naive-Bayes-Modell: aus bereits klassifizierten
-- Dokumenten werden Token-Häufigkeiten je Klasse (document_type/correspondent/
-- tag) gelernt (ml_classifier_tokens/ml_classifier_classes) und je Trainingslauf
-- protokolliert (ml_classifier_runs).
--
-- Provenienz-Spalten (assigned_via auf document_tags, doc_type_assigned_via/
-- correspondent_assigned_via auf documents) unterscheiden 'manual' (Nutzer
-- hat gesetzt), 'rule' (Regel-Engine) und 'ml_accepted' (vom Klassifizierer
-- vorgeschlagen und vom Nutzer akzeptiert). DEFAULT 'manual' bewusst konservativ
-- gewählt: bestehende Zeilen werden NICHT rückwirkend als 'rule' fehlklassifiziert
-- und fließen dadurch weiterhin normal als Trainingsdaten in den Klassifizierer ein.
CREATE TABLE IF NOT EXISTS ml_classifier_tokens (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('document_types','correspondents','tags')),
entity_id BIGINT NOT NULL,
token TEXT NOT NULL,
count BIGINT NOT NULL DEFAULT 0,
UNIQUE (tenant_id, kind, entity_id, token)
);
CREATE INDEX IF NOT EXISTS idx_ml_tokens_lookup ON ml_classifier_tokens(tenant_id, kind, token);
CREATE TABLE IF NOT EXISTS ml_classifier_classes (
tenant_id BIGINT NOT NULL,
kind TEXT NOT NULL,
entity_id BIGINT NOT NULL,
doc_count BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (tenant_id, kind, entity_id)
);
CREATE TABLE IF NOT EXISTS ml_classifier_runs (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
completed_at TIMESTAMPTZ,
doc_count BIGINT NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running','completed','failed','skipped_insufficient_data')),
error TEXT
);
CREATE INDEX IF NOT EXISTS idx_ml_classifier_runs_tenant ON ml_classifier_runs(tenant_id);
ALTER TABLE document_tags ADD COLUMN IF NOT EXISTS assigned_via TEXT NOT NULL DEFAULT 'manual' CHECK (assigned_via IN ('manual','rule','ml_accepted'));
ALTER TABLE documents ADD COLUMN IF NOT EXISTS doc_type_assigned_via TEXT NOT NULL DEFAULT 'manual' CHECK (doc_type_assigned_via IN ('manual','rule','ml_accepted'));
ALTER TABLE documents ADD COLUMN IF NOT EXISTS correspondent_assigned_via TEXT NOT NULL DEFAULT 'manual' CHECK (correspondent_assigned_via IN ('manual','rule','ml_accepted'));