5.2 - Het gebruik van waardelijsten

OVERZICHT

Waardelijsten kunnen voor diverse doeleinden op diverse manieren gebruikt worden. Het eenvoudigst in gebruik zijn conceptwaardelijsten en registerwaardelijsten op peildatum. Registerwaardelijsten compleet bevatten aanzienlijk meer informatie dan hun tegenhangers op peildatum en vragen dus meer inzicht in de gebruikte structuur. De XML-varianten van deze vier waardelijstsoorten bevatten iets minder informatie dan de RDF-varianten. Voor de compleetlijsten is dit verschil nog groter. Voor een bespreking van de XML-structuur en samenhang met de RDF-variant, zie 5.3 - De XML-structuur van XML-waardelijsten. In het hiernavolgende gaan we nader in op de compleetlijsten.

HET GEBRUIK VAN REGISTERWAARDELIJSTEN IN DE COMPLEET-VARIANT

Het gebruik van de registerwaardelijsten in de compleet-variant wordt hierna geïllustreerd aan de hand van een aantal informatievragen met bijbehorende SPARQL. Deze queries werken evengoed op de registers zelf. We nemen hierbij steeds de waardelijst https://identifier.overheid.nl/tooi/set/ministerie_compleet/v1.ttl (met als bestandsnaam ministerie_compleet_v1) als basis omdat het bronregister zowel relatief klein en handzaam is, en tegelijkertijd een goed beeld geeft van enerzijds de complexiteit van de modellering, en anderzijds de rijkdom aan informatie die het beschikbaar maakt. Omdat de waardelijst een afslag is van het register, richten de vragen zich op het register.

Hoeveel ministerie-objecten bevat het register?

Aantal ministeries

SELECT COUNT(?s)
WHERE {
    ?s a tooiont:Ministerie .
    FILTER NOT EXISTS {?s a tooiont:HistorischeVersie}
}

Deze query retourneert het aantal ministerie-objecten, inclusief ministeries die ooit bestaan hebben maar inmiddels zijn opgeheven. Niet meegeteld worden de historische versies van een ministerie. Bij weglating van het filter zullen ook deze meegeteld worden. Dat is bij deze specifieke informatievraag niet de bedoeling.

Hoe zijn de namen van de ministeries veranderd in de tijd?

Historie van ministerienamen

SELECT ?oc ?org ?t ?hv
WHERE {
    [] a tooiont:Toestandswijziging ;
        prov:used / tooiont:afkorting ?org ;
        prov:used / tooiont:organisatiecode ?oc ;
        tooiont:tijdstipWijziging ?t ;
        prov:invalidated / tooiont:afkorting ?hv .
} ORDER BY ?org

Deze querie selecteert alle toestandswijzigingen, en bij elk van deze de huidige (of laatst bekende) afgekorte naam en de organisatiecode van organisatie waar de toestandsverandering betrekking op heett (prov:used), het tijdstip van wijziging, en de afgekorte naam die hoort bij de toestand die na de wijziging niet meer van kracht was (prov:invalidated). Het resultaat van deze query is (gegeven de (versie van de) genoemde waardelijst):

Organisatiecode Ministerie Tijdstip wijziging Oude naam
mnre1045 EZK 2018-01-01T00:00:00 EZ
mnre1045 EZK 2013-01-01T00:00:00 ELenI
mnre1130 IenW 2018-01-01T00:00:00 IenM
mnre1058 JenV 2010-12-01T00:00:00 MinJus
mnre1058 JenV 2018-01-01T00:00:00 VenJ

Dit dient als volgt gelezen te worden: JenV heette tot 1 december 2010 MinJus, en tot 1 januari 2018 heette het VenJ. Merk op dat de waarden in de eerste kolom onveranderlijk zijn. Immers, een andere organisatiecode zou een andere URI betekenen — en dat betekent een andere identiteit. De afkortingen in de tweede kolom staan voor de naam van het ministerie op de peildatum van de waardelijst. Die naam verandert door de tijd.

Welke ministeries hebben door de tijd heen bestaan?

Om te bekijken welke ministeries door de tijd heen opgericht en eventueel weer opgeheven zijn, zoeken we alle instanties van tooiont:ExistentieleWijziging op. Deze gaan terug tot 2010; ministeries die daarvoor zijn opgeheven of opgericht (zonder na 2010 opgeheven te zijn) worden met deze query dus niet gevonden. Bij elke instantie sommen we de organisaties op die opgeheven zijn (prov:invalidated) en de organisaties die opgericht zijn (prov:generated) als gevolg van de wijziging. Omdat een existentiële wijziging nul of meerdere van elk kan hebben gebruiken we de union van twee aparte graph patterns.

Organisaties die bestaan of bestaan hebben

SELECT ?w ?type ?datum ?inv ?gen
WHERE {
    {
        ?w rdf:type / rdfs:subClassOf tooiont:ExistentieleWijziging ;
            a ?type ;
            tooiont:tijdstipWijziging ?t ;
            prov:invalidated / tooiont:afkorting ?inv .
            BIND (xsd:date(?t) AS ?datum ) 
    } UNION {
        ?w rdf:type / rdfs:subClassOf tooiont:ExistentieleWijziging ;
            a ?type ;
            tooiont:tijdstipWijziging ?t ;
            prov:generated / tooiont:afkorting ?gen .
            BIND (xsd:date(?t) AS ?datum ) 
    }
}

De query geeft het volgende resultaat:

Wijziging Type wijziging Datum Beeindigd Gestart
ministerie:wzg_00926444 tooiont:Samenvoeging 14/10/2010 VROM
ministerie:wzg_00926444 tooiont:Samenvoeging 14/10/2010 VW
ministerie:wzg_00926444 tooiont:Samenvoeging 14/10/2010
IenW
ministerie:wzg_01378363 tooiont:Afsplitsing 26/10/2017
LNV
ministerie:wzg_06434036 tooiont:Samenvoeging 14/10/2010 LNV
ministerie:wzg_06434036 tooiont:Samenvoeging 14/10/2010 EZ
ministerie:wzg_06434036 tooiont:Samenvoeging 14/10/2010
EZK

Dit moet gelezen worden als: er was een samenvoeging op 14 oktober 2010, en als gevolg daarvan zijn VROM en VW (Verkeer en Waterstaat) opgeheven, en is IenW gestart. Merk op dat hierbij de afkortingen gebruikt worden die nu nog geldig zijn, of geldig waren op het moment van opheffen. Voor IenW geldt bijvoorbeeld dat op het moment van oprichting nog MinIenM heette.

Welke ministeries waren met welke naamgeving geldig op peildatum 2 september 2010?

Het kan heel nuttig zijn om organisaties die op een peildatum bestonden uit te vragen, met de naam die op die datum geldig waren. In dit specifieke voorbeeld is het nodig bij elk relevant ministerie de historische versies te vinden (voor zover aanwezig), en daaruit de versie te selecteren die op de peildatum geldig was. Bij het selecteren van de ministeries die bestonden op de peildatum moeten we rekening houden met het feit dat de properties prov:generatedAtTime en prov:invalidatedAtTime voor een gegeven ministerie in voorkomende gevallen ongespcificeerd kunnen zijn. De waarde van prov:generatedAtTime (?gt) kan eenvoudig onbekend zijn. Als de waarde van prov:invalidatedAt (?it) niet is gespecificeerd, dan betekent dat dat het ministerie nog bestaat. Er zijn dus vier mogelijkheden. Om de zaak te vereenvoudigen definiëren we twee variabelen, ?start en ?end, die we gelijk stellen aan ?gt en ?it als deze gespecificeerd zijn. Zo niet, dan geven we ze een waarde in het verre verleden of de verre toekomst (regel 9 en 10). Vervolgens filteren we alle ministeries weg die op de peildatum nog niet of niet meer bestonden (regel 11 en 12).

Wat volgt is een geneste query van twee niveaus diep om de historische versies te vinden en daaruit de juiste te selecteren. 

Welke organisaties bestonden er op een peildatum

SELECT ?org ?naamGeldigOpPeildatum
WHERE {
    BIND ( ("2010-09-02T00:00:00"^^xsd:dateTime) AS ?peildatum ) .
    ?org a tooiont:Ministerie ;
            rdfs:label ?label .
    FILTER NOT EXISTS { ?org a tooiont:HistorischeVersie }
    OPTIONAL { ?org prov:generatedAtTime ?gt }
    OPTIONAL { ?org prov:invalidatedAtTime ?it }
    BIND ( (IF (bound(?gt), ?gt, "1800-01-01T00:00:00"^^xsd:dateTime)) AS ?start )
    BIND ( (IF (bound(?it), ?it, "2100-01-01T00:00:00"^^xsd:dateTime)) AS ?end )
    FILTER (?start < ?peildatum )
    FILTER (?end > ?peildatum )

    OPTIONAL { 
        SELECT ?org ?naam
        WHERE {
            {
                SELECT ?org ( MIN( ?eindeGeldigheidVanToestand  )  AS ?e )
                WHERE {
                    BIND ( ("2010-09-02T00:00:00"^^xsd:dateTime) AS ?peildatum ) .
                    ?tw a tooiont:Toestandswijziging ;
                        prov:used ?org ;
                        tooiont:tijdstipWijziging ?eindeGeldigheidVanToestand ;
                    .
                    FILTER (?eindeGeldigheidVanToestand > ?peildatum)
                } GROUP BY ?org HAVING BOUND(?org)  ## Filter met HAVING nodig wegens RDF4J-bug
            }
            ?tw2 a tooiont:Toestandswijziging .
            ?tw2 prov:used ?org .
            ?tw2 tooiont:tijdstipWijziging ?e .
            ?tw2 prov:invalidated / rdfs:label ?naam .
        }
    }
    BIND ( (IF (bound(?naam), ?naam, ?label)) AS ?naamGeldigOpPeildatum )
} 

Het resultaat van deze query is als volgt:

URI Naam geldig op 2 september 2010
ministerie:mnre0170 ministerie van Verkeer en Waterstaat
ministerie:mnre0180 ministerie van Volkshuisvesting, Ruimtelijke Ordening en Milieubeheer
ministerie:mnre1010 ministerie van Algemene Zaken
ministerie:mnre1013 ministerie van Buitenlandse Zaken
ministerie:mnre1018 ministerie van Defensie
ministerie:mnre1025 ministerie van Volksgezondheid, Welzijn en Sport
ministerie:mnre1034 ministerie van Binnenlandse Zaken en Koninkrijksrelaties
ministerie:mnre1040 ministerie van Economische Zaken
ministerie:mnre1058 ministerie van Justitie
ministerie:mnre1073 ministerie van Sociale Zaken en Werkgelegenheid
ministerie:mnre1090 ministerie van Financiën
ministerie:mnre1109 ministerie van Onderwijs, Cultuur en Wetenschap
ministerie:mnre1150 ministerie van Landbouw, Natuur en Voedselkwaliteit

Het doel van de OPTIONAL-groep is om een eventuele historische versie van een ministerie die geldig was op de peildatum te vinden. Zo ja, dan wordt de naam van die historische versie in het resultaat verwerkt. Zo niet, dan nemen we de naam van het ministerie die op het moment van uitvoering van de querie geldig is. Dat gebeurt op regel 34.

We bekijken nu een vereenvoudigde versie van de diepst geneste query. Deze vind per ministerie de bijbehorende toestandswijzigingen en het tijdstip van wijziging:

Vereenvoudigde inner query

SELECT ?org ?tw ?eindeGeldigheidVanToestand 
WHERE {
    ?tw a tooiont:Toestandswijziging ;
        prov:used ?org ;
        tooiont:tijdstipWijziging ?eindeGeldigheidVanToestand ;
    .
} 

Dit levert de volgende resultaten op:

Ministerie Toestandswijziging Tijdstip
ministerie:mnre1045 ministerie:wzg_80272410 2013-01-01T00:00:00
ministerie:mnre1045 ministerie:wzg_17545147 2018-01-01T00:00:00
ministerie:mnre1058 ministerie:wzg_05229330 2018-01-01T00:00:00
ministerie:mnre1058 ministerie:wzg_00821007 2010-12-01T00:00:00
ministerie:mnre1130 ministerie:wzg_08160830 2018-01-01T00:00:00

We nesten deze query om per ministerie alleen de oudst geregistreerde toestandswijziging te vinden.

Geneste query

SELECT ?org ?e ?tw2 ?naam
WHERE {
    {
        SELECT ?org ( MIN( ?eindeGeldigheidVanToestand  )  AS ?e )
        WHERE {
            ?tw a tooiont:Toestandswijziging ;
                prov:used ?org ;
                tooiont:tijdstipWijziging ?eindeGeldigheidVanToestand ;
            .
        } GROUP BY ?org HAVING BOUND(?org)  ## Filter met HAVING nodig wegens RDF4J-bug
    }
    ?tw2 prov:used ?org ;
        tooiont:tijdstipWijziging ?e ;
        prov:invalidated / rdfs:label ?naam ;
    .
}

Deze geeft de volgende resultaten:

Ministerie Tijdstip wijziging Toestandswijziging Naam geldig in de toestand vóór wijziging
ministerie:mnre1045 2013-01-01T00:00:00 ministerie:wzg_80272410 ministerie van Economische Zaken, Landbouw en Innovatie
ministerie:mnre1058 2010-12-01T00:00:00 ministerie:wzg_00821007 ministerie van Justitie
ministerie:mnre1130 2018-01-01T00:00:00 ministerie:wzg_08160830 ministerie van Infrastructuur en Milieu

De binnenste query geeft de eerste twee kolommen van deze tabel. De resultaatset wordt gejoind met de resultaten van de buitenste query. Daarmee worden de laatste twee kolomen gevonden. Met een paar kleine aanpassingen kunnen we dit in de hoofdquery plakken, binnen de OPTIONAL-groep. In de binnenste query voegen we een filter op peildatum toe. Daartoe moeten we de peildatum nog een keer toekennen: SPARQL query-evaluatie werkt van binnen naar buiten. Buiten de OPTIONAL-groep, op regel 34, wordt getest of er voor het betreffende ministerie een historische naam is gevonden. Die kennen we dan toe aan het resultaat. Zo niet, dan gebruiken we de naam van het ministerie.

Wanneer we ervoor zouden kiezen bij de de historische versie-objecten een startmoment en eindmoment toe te voegen, dan zou de hoofdquery aanzienlijk eenvoudiger zijn. De OPTIONAL-groep ziet er dan als volgt uit:

Het OPTIONAL gedeelte

OPTIONAL { 
    ?tw a tooiont:Toestandswijziging .
    ?tw prov:used ?org .
    ?tw prov:invalidated / prov:invalidatedAtTime ?e .
    ?tw prov:invalidated / prov:generatedAtTime ?b .
    ?tw prov:invalidated / rdfs:label ?naam .
    FILTER (?b < ?peildatum)
    FILTER (?e > ?peildatum)
}

Het voordeel van eenvoudig te begrijpen queries gaat echter ten koste van de eenvoud van de data. Het opslaan van veel redundante gegevens maakt data-entry foutgevoelig. Een klein foutje bij de bron of in de verwerkende software kan moeilijk te vinden en lastig te repareren problemen in de data opleveren. We hebben daarom gekozen voor eenvoud in de data.