Eigenes Werkzeug · Beleg zu Daten & Prozesse

Von der API bis zur Prüfabfrage

189 Gehölzarten, 378 Bilder, eine fremde Datenquelle. Ein Python-Programm holt zu jeder Art zwei lizenzierte Fotos von iNaturalist und schreibt zu jedem Bild einen Metadatensatz. Aus diesen Metadaten entsteht hier eine kleine Datenbank – und acht Abfragen, die prüfen, ob der Bestand hält, was er verspricht. Eine davon findet etwas.

Der Anlass war unspektakulär: eine Lernkartensammlung zur Gehölzkunde, 189 botanische Namen in einem Anki-Deck, ohne Bilder. Bilder von Hand zu suchen hätte für jede Art zwei Entscheidungen gebraucht – welche Beobachtung, welches Foto – und bei 189 Arten wären das 378 Entscheidungen nach einem Bauchgefühl gewesen, das sich hinterher niemand mehr erklären kann.

Also wurden die Kriterien zuerst aufgeschrieben und dann in Code gefasst: Die Art muss exakt getroffen sein, die Beobachtung soll Research Grade haben, das Bild eine Mindestkantenlänge von 500 px, die Lizenz muss verwertbar sein – und die beiden Bilder einer Art dürfen nicht aus derselben Beobachtung stammen, sonst zeigen sie dieselbe Pflanze am selben Tag.

Das ist eine Datenpipeline. Es ist noch keine Datenbank. Die Metadaten lagen als CSV und JSON nebeneinander, ohne Schlüssel, ohne Beziehungen und ohne eine einzige Abfrage, die eine Aussage über ihre Qualität erzwingt. Diese Schicht ist 2026 nachträglich für dieses Portfolio entstanden – vier Tabellen in SQLite, acht Prüfabfragen, ein Bericht.

Der interessante Teil ist nicht, dass die Abfragen laufen. Der interessante Teil ist, dass eine davon einen Befund liefert – und dass dieser Befund nicht weggeräumt wurde.

Was davon meine Arbeit ist

  • Das Python-Programm – Konfiguration, API-Anbindung, Namensauflösung, Bewertung der Kandidaten, Download, Berichte. 12 Module, rund 2.300 Zeilen.
  • Die Datenbank und die Abfragen – Datenmodell, Import, acht Prüfungen, Prüfbericht. Nachträglich, 2026.
  • Nicht von mir – sämtliche Bilder und alle Inhalte der Metadatensätze. Sie stammen von iNaturalist-Nutzer:innen und stehen unter fünf verschiedenen Creative-Commons-Lizenzen.

Anlass war eine private Lernkartensammlung, kein Auftrag. Der User-Agent des Programms sagt das auch der API.

Auf einen Blick

  • 189 Arten · 378 Metadatensätze · 378 Beobachtungen
  • 396 API-Anfragen, keine einzige Abweisung wegen Überlastung
  • 376 von 378 Fotos mit Research Grade
  • 378 von 378 mit Lizenzangabe: cc0 136, cc-by 214, cc-by-nc 26, cc-by-sa 2
  • 8 Prüfabfragen: 6 bestanden, 1 Befund, 1 zählt
  • 45 Regeltests, alle bestanden

Der Datenweg

1 Deck lesen 189 botanische Namen aus einer .apkg-Datei – mit zipfile und sqlite3 der Standardbibliothek. Das Deck wird nur gelesen, nie verändert.
2 Taxon auflösen Je Name mehrere Suchvarianten gegen /v1/taxa, von spezifisch nach allgemein. Ein reiner Gattungstreffer gilt nicht als Erfolg.
3 Kandidaten bewerten Bis zu 30 Beobachtungen je Art aus /v1/observations, jedes Foto nach sieben Kriterien bepunktet. Ohne Lizenz kein Download.
4 Ablegen und protokollieren Bild plus Metadatensatz mit Autor, Lizenz, Quell-URL, Prüfsumme. Dazu fünf Berichte, darunter einer nur für Problemfälle.
5 Datenbank und Prüfung Vier Tabellen in SQLite, acht Abfragen, ein Prüfbericht. Nachträglich ergänzt – der Teil, den das Originalprogramm nicht hat.

Schritte 1 bis 4 sind das Originalprogramm, Stand des Laufs: 30. August 2026. Schritt 5 ist die Ergänzung für dieses Portfolio. Beide Teile sind getrennt gehalten – der Originalcode wurde nicht angefasst.

Wie ein Bild ausgewählt wird

Die Auswahl ist ausdrücklich nicht „die ersten zwei Treffer". Jedes Foto bekommt Punkte, und jeder Punkt trägt seine Begründung mit in den Bericht. Die Reihenfolge der Kriterien ist die eigentliche Entscheidung – sie legt fest, was was überstimmt.

Aus src/selection.py und src/config.py des Programms, nicht nacherzählt.
KriteriumPunkteWarum
Taxon identisch+40Ein anderes Taxon zeigt womöglich eine andere Art.
Research Grade+35Mehrere Personen haben die Bestimmung bestätigt.
Lizenz+15 bis +30Freiere Lizenz ist besser: cc0 vor cc-by vor cc-by-sa vor cc-by-nc.
Kurze Kante ab 1.500 px+20Auflösung, gestaffelt bis hinunter zur Mindestkante.
Abweichendes Taxon−15Abwertung, kein Ausschluss – der Bericht führt es als Problemfall.
Kurze Kante unter 500 px−25Für eine Lernkarte unbrauchbar.
Seitenverhältnis über 3:1−10Deutet auf Panorama oder engen Ausschnitt hin.
Keine Lizenzangabe−1000Ausschluss. „Alle Rechte vorbehalten" wird nie stillschweigend übernommen.

Danach kommt die Regel, die im Bericht am häufigsten sichtbar wird: Erst wird je Beobachtung das beste Foto genommen, und nur wenn keine zweite Beobachtung übrig bleibt, ein zweites Foto derselben. Deshalb stammen bei allen 189 Arten die beiden Bilder aus verschiedenen Beobachtungen – Prüfabfrage 7 rechnet das nach.

Gegenüber der API verhält sich das Programm zurückhaltend: eine Sekunde Pause zwischen zwei Anfragen, höchstens 50 pro Minute bei erlaubten 60, vier Versuche mit wachsender Wartezeit. Im dokumentierten Lauf kam über 396 Anfragen keine einzige Abweisung wegen Überlastung zurück.

Das Datenmodell

Vier Tabellen. Was in den Quelldaten nicht vorkommt, steht auch nicht im Modell: Ein Anki-Deck mit botanischen Namen kennt keinen deutschen Trivialnamen, und welche Suchvariante am Ende gegriffen hat, hält kein Metadatensatz fest. Zwei leere Spalten mitzuführen wäre die unehrlichere Lösung gewesen.

TabelleZeilenFelder
plants
Artenstamm
189 plant_id, scientific_name (Name im Deck), name_kern, taxon_id, taxon_name (Name bei iNaturalist), taxon_kern, name_abweichung
observations
Beobachtungen
378 observation_id, plant_id, source, observed_on, quality_grade, place_guess, source_url
images
Bildmetadaten
378 image_id, observation_id, plant_id, selected_rank, filename, url, license_code, author, attribution, width, height, sha256, file_present
checks
Prüfergebnisse
8 check_id, check_type, frage, sql, expected, actual, status, note

Der Import ist wiederholbar und nicht additiv: Ein zweiter Lauf legt die Datei neu an, statt Zeilen zu verdoppeln. Fehlende Werte bleiben NULL – nichts wird stillschweigend ersetzt, denn genau diese Lücken sollen die Abfragen ja finden.

Dass die Tabelle observations genauso viele Zeilen hat wie images, ist kein Modellierungsfehler, sondern das Ergebnis der Auswahlregel: Weil je Bild eine eigene Beobachtung gewählt wurde, steht hinter jedem Bild genau eine. Ein Modell, das das nicht abbilden könnte, könnte Prüfabfrage 7 nicht stellen.

Die acht Prüfabfragen

Jede Abfrage hat einen Sollwert. Bestanden heißt: Die Abfrage findet nichts. Befund heißt: Sie findet etwas – und das ist dann das Ergebnis, kein Fehler des Programms.

Nr.PrüfungFrageErgebnis
1AbdeckungWelche Pflanzen haben weniger als zwei ausgewählte Bilder?0 – bestanden
2DublettenWelche Bild-URLs kommen mehrfach vor?0 – bestanden
3NachvollziehbarkeitWelche Bilder haben keine Quell-ID oder keine Quell-URL?0 – bestanden
4LizenzWelche Bilder tragen keine verwertbare Lizenzangabe?0 – bestanden
5NutzbarkeitWelche Bilder unterschreiten 500 px Mindestkantenlänge?0 – bestanden
6AblageZu welchen Metadatensätzen fehlt die Bilddatei im Ordner?6 – Befund
7PlausibilitätStammen die beiden Bilder einer Art aus verschiedenen Beobachtungen?0 – bestanden
8TaxonomieBei welchen Arten steht hinter dem abweichenden Namen ein anderer Artbegriff?21 – gezählt

Die acht Abfragen ausführen Prüfbericht (CSV)

Der Befund: sechs fehlende Dateien

Der Download-Bericht des Programms meldet 378 Bilder vorhanden, Ziel 378. Im Bildordner liegen aber 372 Dateien. Die Abfrage, die Metadaten gegen Dateibestand hält, benennt die Differenz:

SELECT i.filename, p.scientific_name, i.license_code
FROM images i
JOIN plants p ON p.plant_id = i.plant_id
WHERE i.file_present = 0
ORDER BY p.scientific_name, i.selected_rank
filenamescientific_namelicense_code
Lonicera_pileata_1.jpgLonicera pileata*cc-by
Lonicera_pileata_2.jpgLonicera pileata*cc-by
Spiraea_x_arguta_1.jpgSpiraea × argutacc0
Spiraea_x_arguta_2.jpgSpiraea × argutacc-by
Spiraea_x_vanhouttei_1.jpgSpiraea × vanhoutteicc0
Spiraea_x_vanhouttei_2.jpgSpiraea × vanhoutteicc0

Es sind nicht sechs beliebige Dateien. Es sind genau die Bilder der drei Arten, die das Programm im Problembericht selbst als REVIEW markiert hat. Spiraea × arguta und Spiraea × vanhouttei fallen bei iNaturalist auf dasselbe Taxon zusammen – ohne Gegenmaßnahme hätten beide Arten identische Fotos bekommen. Das Programm hat das nach dem Durchlauf erkannt, für die zweite Art auf Ersatzfotos ausgewichen und beide Fälle zur Prüfung vorgelegt. Lonicera pileata* wurde auf das breitere Taxon Lonicera ligustrina aufgelöst.

Warum der Befund stehen bleibt

Es wäre in zwei Minuten erledigt gewesen: Datensätze löschen, Abfrage grün, acht von acht. Nur wäre dann eine Prüfung verschwunden, die genau das gefunden hat, wofür sie da ist. Der Zustand ist nachvollziehbar – jemand hat die drei fraglichen Arten aussortiert, ohne die Metadaten mitzunehmen. Eine Datenqualitätsprüfung, deren Befunde man wegräumt, prüft nichts mehr.

Die achte Abfrage zählt, statt zu urteilen

Bei 36 der 189 Arten weicht der Name bei iNaturalist vom Namen im Deck ab. Als Zahl ist das wertlos: Bei 15 davon ist es nur die Schreibweise – das Deck führt Prunus avium* mit einer Merkhilfe, iNaturalist schreibt Prunus avium. Solche Zusätze werden vor dem Vergleich gestrichen, in SQL wie in der Browserfassung nach derselben Regel.

Übrig bleiben 21 Fälle, in denen der Name selbst ein anderer ist. Auch diese sind nicht gleichartig, und genau deshalb bewertet die Abfrage sie nicht:

BeispielWas dahintersteckt
Euonymus europaeaEuonymus europaeusGrammatische Endung. Dieselbe Art.
Sorbus ariaAria edulisGültige taxonomische Revision, andere Gattung.
Mahonia aquifoliumBerberis aquifoliumEbenso – der gebräuchliche Name ist heute ein Synonym.
Hydrangea arborescens ssp. arborescensHydrangea arborescensUnterart auf Art zusammengezogen. Bilder zeigen möglicherweise eine andere Unterart.
Lonicera pileata*Lonicera ligustrinaAuf ein breiteres Taxon aufgelöst. Fachlich zu prüfen.

Die ersten drei Zeilen sind unbedenklich, die letzten beiden nicht – und diesen Unterschied kann keine SQL-Abfrage entscheiden. Sie kann nur die Liste erzeugen, die jemand ansehen muss. Deshalb hat Abfrage 8 als einzige keinen Sollwert und den Status gezählt statt bestanden. Eine Prüfung, die hier ein Urteil fällte, wäre genau die Sorte Automatisierung, die hinterher niemand mehr auffängt.

Zweiter Fall: eine Rechtsdatenbank

Dieselbe Arbeitsweise an einer ganz anderen Datenbank. Das Rechtsinformationssystem des Bundes (RIS) führt österreichisches Recht mit Fassungsständen. Wer daraus ohne Fassungsangabe zitiert, zitiert möglicherweise aufgehobenes Recht – und merkt es nicht.

Die Frage kam aus einem eigenen Studienprojekt. Das Detailkonzept zum Wienerberg bezeichnet das Gebiet als Landschaftsschutzgebiet, ohne eine Rechtsquelle zu nennen. Auf welcher Grundlage steht dieser Schutz, und welche Fassung gilt heute?

Abgefragt wurde die offene OGD-Schnittstelle des Bundeskanzleramts in vier Schritten: erst die Ermächtigungsnorm im Wiener Naturschutzgesetz, dann die Suche nach Verordnungen zum Stichwort Wienerberg, dann die geltende Fassung, zuletzt die Frage nach der älteren Verordnung.

Der letzte Schritt ist der, den man leicht überspringt – und der hier das Ergebnis umdreht.

Die Recherchekette

  • § 24 Wr. NSchG kennt zwei Wege ins Landschaftsschutzgebiet: über eine Verordnung (Abs. 1) oder unmittelbar kraft Gesetzes für Flächen, die 1985 als Wald- und Wiesengürtel gewidmet waren (Abs. 4).
  • Suchwort „Wienerberg" liefert 21 Dokumente aus Wien, aus zehn Rechtsvorschriften.
  • Zwei davon betreffen die Fläche unmittelbar – und eine hebt die andere auf.

Das Ergebnis

Die Verordnung „Geschützter Landschaftsteil Wienerberg", LGBl. für Wien Nr. 46/1995, ist seit dem 9. Mai 2015 außer Kraft. § 10 der Verordnung „Landschaftsschutzgebiet Favoriten" hebt sie ausdrücklich auf und widerruft zugleich den Schutz aller Flächen des 10. Bezirks, die in den neuen Plänen nicht mehr ausgewiesen sind.

Geltende Grundlage ist damit die Verordnung Landschaftsschutzgebiet Favoriten, LGBl. für Wien Nr. 20/2015, zuletzt geändert durch LGBl. Nr. 36/2024; § 1 in der Fassung seit 23. November 2024 (Dokumentnummer LWI40016955). Ermächtigungsnorm ist § 24 Abs. 1 Wiener Naturschutzgesetz, LGBl. Nr. 45/1998. Abfragedatum: 1. September 2026.

Was aus dieser Quelle nicht folgt

Ob eine bestimmte Fläche am Wienerberg im Schutzgebiet liegt, sagt das RIS nicht. § 1 der Verordnung bestimmt den Geltungsbereich ausschließlich über die Pläne in den Anlagen – über eine ununterbrochene rote Linie. Keine Grundstücksnummern, keine Koordinaten. Für eine flächenscharfe Aussage müsste der Plan der jeweiligen Anlage mit dem konkreten Grundstück abgeglichen werden. Das ist hier nicht geschehen und wird deshalb auch nicht behauptet.

Das Protokoll ist ein Skript, kein Text: Derselbe Aufruf fragt dieselben Dokumente erneut ab. Kommt ein anderer Fassungsstand zurück, hat sich die Rechtslage geändert – genau dafür steht das Abfragedatum im Kopf der Datei.

Rechercheprotokoll (Textdatei)

Quelle: Rechtsinformationssystem des Bundes, OGD-Schnittstelle v2.6, data.bka.gv.at/ris/api/v2.6/. RIS-Daten stehen unter CC BY 4.0, Republik Österreich. Rechtsverbindlich ist allein der kundgemachte Text im Landesgesetzblatt, nicht die konsolidierte Fassung im RIS.

Woher die Regeln für die Rechtsrecherche stammen

Nicht aus einem Jusstudium. Sie stammen aus einem Werkzeug, das ich gebaut habe – einem Claude-Skill für österreichisches Recht, entstanden für eine Wirtschaftsrecht-Studentin an der WU Wien. Die Arbeit daran war nicht juristisch, sondern die Sorte Arbeit, die eine Fachanwendung braucht: festlegen, welche Quelle wann gilt, und absichern, dass das Werkzeug lieber schweigt als plausibel danebenliegt.

FestlegungWirkung
RIS ist Primärquelle für geltendes RechtKeine Fachdatenbank und keine Sekundärliteratur als Beleg für den Gesetzeswortlaut.
Sechs Recherchewege, je nach FrageAktuelle Norm, historische Fassung, Judikatur und Literatur laufen über verschiedene Routen.
Jeder Treffer trägt Fundstelle und FassungOhne Dokumentnummer, Fassungsstand und Abfragedatum gilt ein Treffer als nicht verifiziert.
Nicht auffindbar bleibt nicht auffindbarKein Umformulieren zu „wahrscheinlich". Eine erfundene Geschäftszahl ist schlimmer als eine Lücke.
19 Testfälle, 10 davon kritischDie kritischen prüfen den Halluzinationsschutz. Schlägt einer fehl, ist das Werkzeug für seinen Zweck unbrauchbar.

Zum Skill gehört ein Bundle, das den RIS-Zugang installierbar macht. Der Server darin ist nicht meiner: Es ist das unveränderte npm-Paket ris-mcp-ts (MIT) von philrox / Honeyfield-Org. Eigene Arbeit war der Vergleich von vier verfügbaren Servern nach Lizenz, Wartungsstand und Abdeckung, die begründete Auswahl und die Verpackung.

Grenzen dieses Belegs

  • Keine Berufserfahrung mit Datenbanken. Die SQLite-Schicht ist 2026 nachträglich für dieses Portfolio entstanden. Es gibt keine berufliche Station, in der ich mit SQL gearbeitet habe, und das Originalprogramm hat keine Datenbank. Belegt ist, dass ich ein Datenmodell aufsetzen, Daten reproduzierbar importieren und Qualitätsprüfungen formulieren kann.
  • 378 Datensätze sind eine kleine Datenmenge. Nichts an diesem Beleg sagt etwas über Datenmengen, Indizes, Abfrageoptimierung oder Datenbankbetrieb aus.
  • Kein juristischer Beleg. Der RIS-Fall zeigt Recherche in einer Fachdatenbank mit Quellenhierarchie und Fassungsständen. Er ist keine Rechtsauskunft, keine Rechtsberatung und kein Nachweis juristischer Ausbildung oder Behördenpraxis.
  • Kein Anlass war beruflich. Die Bildersammlung entstand für eigene Lernkarten, der Skill als Werkzeug für eine andere Person, der Recherchefall aus einem Studienprojekt.
  • Keine Bilder zum Herunterladen. Die 618 MB Bildmaterial gehören iNaturalist-Nutzer:innen und stehen unter fünf verschiedenen Lizenzen. Weitergegeben werden nur die Metadaten – mit Autor, Lizenz und Quell-URL, denn ohne sie dürfte auch das nicht.

Zum Nachrechnen

Prüfabfragen im Browser Datenbank (SQLite, 252 KB) Prüfbericht (CSV) Metadaten (CSV, 132 KB) RIS-Protokoll (Text)

Die Datenbank lässt sich mit jedem SQLite-Werkzeug öffnen; die Tabelle checks enthält alle acht Abfragen im Wortlaut samt Sollwert und Ergebnis. Erzeugt werden beide Dateien von skripte/artdaten-datenbank.py, das Rechercheprotokoll von skripte/ris-recherche.py. Beide Skripte liegen außerhalb des Website-Ordners und werden nicht mit ausgeliefert.

Weiterlesen

Zurück zum Einstieg für Daten und Prozesse · derselbe Umgang mit Pflanzendaten, aber mit einem Sprachmodell im Ablauf: Pflanzendatenbank und Automation · das Gebiet aus dem Rechtsfall, fachlich: Wienerberg – Feldbezug und Grenzen · Datenqualität an einem anderen Bestand: PIM-Werkzeug.