Modul 4 der Spezifikation, dazu das Lexikon, auf das es sich stuetzt. Drei Schritte, streng getrennt: die NER liefert Kandidatenspannen, das Lexikon entscheidet den Typ, die Amtstabelle loest Aemter gegen das Datum des Items auf. Die Trennung ist gemessen begruendet und nicht uebernommen: de_core_news_lg haelt "Merz" fuer einen Ort, "Landtagswahl" fuer einen Ort und "Ukraine-Krieg" fuer eine Person. Der NER-Typ steht als ner_typ in der Nutzlast, entscheidet aber nichts. Modellwahl gemessen: sm und lg finden fast gleich viele Entitaeten (14249 gegen 14261), aber nicht dieselben - nur 10,7 Prozent der Items bekommen von beiden dasselbe Ergebnis, der Jaccard ueber alle Spannen liegt bei 0,590. lg findet 170-mal zusaetzlich "AfD" sowie Merz, Putin, Trump, Kushner, Witkoff. Zeitlich kostet das nichts (7,3 gegen 8,0 Sekunden fuer den Gesamtbestand), an Plattenplatz 568 MB. Der Spiegel ist eine Abschrift, keine Auslegung: lexikon/*.json enthaelt die Wikidata-Antworten unveraendert, mit MANIFEST.json als Beleg. Jede Ableitung geschieht in lexikon_laden.py. Nur lexikon.py --spiegeln fasst das Netz an, und es laeuft von Hand - die WDQS ist ein spendenfinanzierter Dienst, kein Endpunkt fuer eine Pipeline im Viertelstundentakt. p2-005 legt akteure und amtsinhaber an, dazu zwei Betriebssichten. Keine Ausschlussbeschraenkung gegen ueberlappende Amtszeiten: Doppelspitzen sind im deutschen Parteiensystem der Normalfall, und Bremen fuehrt "Buergermeister" als kollegiales Amt. Die Sicht amtsinhaber_ueberschneidungen macht Ueberlappungen sichtbar, statt sie zu verbieten. Amtszeiten sind halboffen - der Tag der Uebergabe gehoert dem Nachfolger, sonst waere jeder Amtswechsel eine Ueberschneidung. Messung ueber den Gesamtbestand: 3407 Items in 21,1 Sekunden, 14652 Nennungen, 2889 aufgeloest. Ein Slot-Lauf erzeugt bitgleich dieselbe Nutzlast wie der Gesamtlauf, 0 Abweichungen. spaCy ist stapelunabhaengig (Stapelgroesse 64, 7, 1 und rueckwaerts: identische Spannen), der Kunstgriff mit der festen Tokenlaenge aus dem Embeddingmodul ist hier nicht noetig. Zwei Fallen sind in NOTES.md festgehalten: eine geratene QID haengt einen Eintrag an ein fremdes Objekt (Q157617 ist die Commerzbank, nicht der Bundesrat), und FILTER (lang(?name) = "de") verliert lautlos alles ohne deutsches Label - Apple, Microsoft und Meta. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NupWEBPzsyohVPG47HsTz8
63 lines
2.7 KiB
Docker
63 lines
2.7 KiB
Docker
# Phase 2 als Container.
|
|
#
|
|
# podman build -t wurzelwerk-p2 .
|
|
#
|
|
# Debian trixie wie der Postgres-Container - dieselbe glibc, dieselbe
|
|
# Zeichensortierung. Fuer die Module ohne Modell spielt das keine Rolle,
|
|
# fuer kuenftige Vergleiche in der Datenbank schon.
|
|
FROM docker.io/library/python:3.13-slim-trixie
|
|
|
|
# OMP_NUM_THREADS ist keine Bequemlichkeit, sondern Voraussetzung:
|
|
# - PyTorch liest die CPU-Zahl am Host ab, nicht die cgroup-Quota. Ohne
|
|
# feste Zahl startet es im Container mehr Threads als es Kontingent hat.
|
|
# - Die Threadzahl bestimmt die Reihenfolge der Gleitkommaadditionen und
|
|
# damit die letzten Stellen jedes Vektors. Sie gehoert deshalb in die
|
|
# coder_version (siehe embeddings.py).
|
|
# 4 laeuft auf jeder Maschine, die hier in Frage kommt - Prod hat 16 Threads,
|
|
# die Entwicklungsmaschine 32.
|
|
ENV PYTHONUNBUFFERED=1 \
|
|
PYTHONDONTWRITEBYTECODE=1 \
|
|
HF_HOME=/cache/huggingface \
|
|
OMP_NUM_THREADS=4 \
|
|
MKL_NUM_THREADS=4 \
|
|
TOKENIZERS_PARALLELISM=false
|
|
|
|
WORKDIR /app
|
|
|
|
# torch zuerst und in einer eigenen Schicht: 196 MB, die sich nicht aendern,
|
|
# wenn eine Anforderungsdatei angefasst wird. Ausdruecklich aus dem CPU-Index -
|
|
# die Vorgabe von PyPI zoege mehrere Gigabyte CUDA-Bibliotheken nach, die auf
|
|
# diesem Server nichts ausrichten koennen (der SM750 ist ein Anzeigechip).
|
|
RUN python3 -m pip install --no-cache-dir --upgrade pip \
|
|
&& python3 -m pip install --no-cache-dir \
|
|
--index-url https://download.pytorch.org/whl/cpu torch==2.14.0+cpu
|
|
|
|
COPY requirements.txt requirements-embedding.txt requirements-akteure.txt ./
|
|
RUN python3 -m pip install --no-cache-dir -r requirements.txt \
|
|
&& python3 -m pip install --no-cache-dir -r requirements-embedding.txt \
|
|
&& python3 -m pip install --no-cache-dir -r requirements-akteure.txt
|
|
|
|
# Das NER-Modell mit fester Version, direkt aus der Modellfreigabe. Es liegt
|
|
# im Abbild und nicht im Cache-Volume: 568 MB, die sich nie aendern, und der
|
|
# erste Lauf auf Prod soll nicht an einem Download haengen.
|
|
RUN python3 -m pip install --no-cache-dir \
|
|
https://github.com/explosion/spacy-models/releases/download/de_core_news_lg-3.8.0/de_core_news_lg-3.8.0-py3-none-any.whl \
|
|
&& python3 -m pip freeze > /app/requirements-lock.txt
|
|
|
|
COPY *.py ./
|
|
COPY migrations/ ./migrations/
|
|
# Der Wikidata-Spiegel gehoert ins Abbild: akteure.py laedt aus der
|
|
# Datenbank, aber lexikon_laden.py soll im Container laufen koennen, ohne
|
|
# dass jemand dafuer Wikidata anfasst.
|
|
COPY lexikon/ ./lexikon/
|
|
|
|
# Eigener Benutzer, kein root. /cache traegt die Modellgewichte und muss ein
|
|
# Volume sein - 2,2 GB im Container-Layer waeren bei jedem Neubau weg.
|
|
RUN useradd --uid 10001 --create-home wurzelwerk \
|
|
&& mkdir -p /cache/huggingface \
|
|
&& chown -R 10001:10001 /cache /app
|
|
USER 10001
|
|
|
|
ENTRYPOINT ["python3"]
|
|
CMD ["check_db.py"]
|