3,7 miljoen uitspraken, één database
Elke openbare Nederlandse rechterlijke uitspraak staat als XML op rechtspraak.nl — van kantonzaak tot Hoge Raad-arrest. Wij bouwen daar een systeem op dat binnen één seconde vragen beantwoordt die geen bestaande zoekmachine aankan. Zoals: is deze uitspraak eigenlijk nog geldend recht?
De vorige poging faalde. Dit is waarom.
De eerste versie van deze database was half onbruikbaar, en de oorzaken waren leerzamer dan het resultaat. Drie fouten die je maar één keer hoeft te maken:
1. Een fallback die data vergiftigde. Als een XML-bestand geen uitspraaktekst
bevatte, viel de parser terug op "pak dan alle tekst die je vindt". Resultaat: 2,75 miljoen
records met als inhoud letterlijk "Raad voor de Rechtspraak, nl, Uitspraak, NL" —
metadataruis die elke zoekopdracht vervuilde. De nieuwe regel is hard: geen
<uitspraak>-element betekent NULL. Nooit een fallback.
2. Een Engelse stemmer op Nederlandse tekst. De full-text-index gebruikte
porter — een Engelse stemmer. "Vernietiging" en "vernietigd" waren daardoor
verschillende woorden. De nieuwe index gebruikt Nederlandse stemming, en weegt de
samenvatting zwaarder dan de volledige tekst.
3. 3,6 miljoen bestanden in één map. Eén simpele ls duurde
13 minuten en trok de NAS omver. Nu sharden we op land/instantie/jaar: elke map
blijft onder de 10.000 bestanden en elk pad is direct uit het ECLI-nummer af te leiden.
Downloaden zonder te rammen
Rechtspraak.nl is een gratis publieke dienst. De documentatie zegt letterlijk "don't hammer the server" — dus draaide de download op ~6 verzoeken per seconde, ruim onder hun limiet, met een load-guardrail die zichzelf terugschroeft zodra onze eigen NAS het te druk krijgt. De volledige set stond na dagen gecomprimeerd op schijf: ~4 GB gzipte XML. De bron-XML is heilig; de database is een afgeleide die je altijd opnieuw kunt bouwen.
De extractie: 229 gerechten, 10 workers
De metadata-extractie parseert per gerecht de RDF-blokken uit de XML: instantie, datum, rechtsgebied, procedure, zaaknummer — én de formele relaties tussen uitspraken (hoger beroep, cassatie, conclusie), die Rechtspraak.nl gestructureerd meelevert. Die relaties zijn goud: 100% betrouwbaar, nul parsing-risico.
Waarom géén Neo4j en géén aparte vectordatabase
Het standaardrecept voor GraphRAG is: Neo4j voor de graaf, een vectorstore voor de embeddings, en een staging-database voor de rest. Drie systemen die je synchroon moet houden, drie keer backuppen, en cross-store-joins die je latency-budget opeten.
Wij kozen één PostgreSQL 17: recursieve CTE's voor graaf-traversal,
tsvector voor Nederlandse full-text, pgvector voor de embeddings die
nog komen. Eén database, één backup, geen sync — en zoals hieronder blijkt: ruim binnen de
snelheidseis van één seconde.
Het bewijs: 11,6 milliseconden
De scherpste testvraag die we kennen: is ECLI:NL:GHARL:2022:572 nog geldend recht? Voor een advocaat is verwijzen naar een vernietigde uitspraak de duurste fout die er bestaat — en geen enkele keyword- of vectorzoekmachine kan deze vraag beantwoorden, want het antwoord staat niet in de tekst. Het staat in de relaties:
SELECT bron_ecli, type, gevolg FROM relatie_formeel
WHERE doel_ecli = 'ECLI:NL:GHARL:2022:572';
bron_ecli | type | gevolg
----------------------+----------+------------------------------
ECLI:NL:HR:2023:1000 | cassatie | (Gedeeltelijke) vernietiging
en zelf afgedaan
Time: 11.596 ms Antwoord: nee. Vernietigd door de Hoge Raad. In 11,6 milliseconden.
Zwaardere vragen — "welke rechtbankuitspraken over verbintenissenrecht zijn sinds 2020 in hoger beroep vernietigd?" — kosten 441 ms over de volle 3,7 miljoen records. Een recursieve wandeling door de precedentketen: 3,3 ms.
Wat komt
Aflevering 2: de citatiegraaf uit de uitspraakteksten zelf — ECLI-verwijzingen parsen, autoriteitsscores, en waarom je een cycle-guard nodig hebt. Daarna: lokale embeddings op een Mac Mini M1, de heuristische query-router, en de 24-vragen-evaluatie.
Alles in deze serie draait op eigen hardware: een Mac Mini M1 en een Synology NAS. Geen cloud-API's in het retrievalpad.