Workshop 2: Culinaire cultuur in beweging

Van Balkenbrij tot Big Mac: onze eetcultuur is divers en uitermate dynamisch. De kookboekencollectie van de Bibliotheek UvA/HvA biedt een inkijkje in hoe onze eetgewoontes zich de afgelopen eeuwen ontwikkeld hebben. In deze sessie onderzoeken we hoe we de metadata van deze collectie kunnen gebruiken om ontwikkelingen en patronen in onze culinaire cultuur bloot te leggen. In welke perioden werd bijvoorbeeld het vegetarisme gepropageerd? Of hoe verliep de opkomst van de Italiaanse keuken in de Lage Landen? Uiteraard zijn bij het beantwoorden van dergelijke vragen ook andere bronnen en datasets te gebruiken. Denk hierbij aan de kookboekencollectie van de KB, Collectie Nederland, de n-gramviewers van DBNL en Google, Wikidata en het Chronologisch Woordenboek van Nicoline van der Sijs waarin lijsten zijn opgenomen met culinaire leenwoorden uit onder andere het Italiaans en het Frans.

Feedback?

Tijdens de workshop werken we met een eerste vroege versie van de LOD van de UB. Heb je foutjes gezien die verbeterd moeten worden? Moet het datamodel uitgebreid worden, of heb je andere opmerkingen? Laat het ons weten via een gedeeld online document. Dit is bedoeld als feedback op de data. Resultaten en query’s kunnen op deze pagina’s gepresenteerd worden!

De kookboekencollectie verkennen

Laten we eerst eens kijken wat er in de kookboekencollectie zit. Dat is ook een mooie gelegenheid om kennis te maken met SPARQL, de querytaal waarmee we Linked Data kunnen bevragen.

Query 1

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT * WHERE {
  ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131" .
}

Voer de query uit

We krijgen tienduizend resultaten terug. Dat komt niet doordat er precies tienduizend boeken in de kookboekencollectie zitten, maar doordat er een limiet zit op het aantal resultaten dat geretourneerd wordt. Laten we de query aanpassen om het juiste aantal boeken op te vragen.

Query 2

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT (COUNT(DISTINCT ?sub) AS ?aantal) WHERE {
  ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131" .
} 

Voer de query uit

We hebben nu het juiste aantal en tegelijkertijd hebben we kennis gemaakt met een aantal andere functies in SPARQL zoals COUNT en DISTINCT. Maar we willen natuurlijk niet alleen aantallen hebben, maar ook iets over de boeken zelf te weten komen. Laten we daarom eens voor één boek alle triples op vragen.

Query 3

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT ?pred ?obj (DATATYPE(?obj) AS ?datatype) WHERE {
<https://pid.uba.uva.nl/ark:/88238/b1990002173760205131> ?pred ?obj.
}

Voer de query uit

Kijk eens alle metadata van het ‘Nieuw volledig Oost-Indisch kookboek’. Maar we zien vooral ook een aantal predikaten waarmee we een nieuwe query kunnen bouwen. We zien bijvoorbeeld het predikaat dct:spatial waarmee deze titel met het begrip Indonesië wordt verbonden. Laten we dat gegevens eens gebruiken om een overzicht te maken van het aantal boeken per jaar van uitgave in de collectie en het aandeel Indonesische kookboeken daarin.

Query 4

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT DISTINCT ?datum ?aantal ?indonesia WHERE {
  { SELECT ?datum (COUNT(?datum) AS ?aantal) WHERE {
    ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
       <http://semanticweb.cs.vu.nl/2009/11/sem/hasBeginTimeStamp> ?datum.
        FILTER (xsd:integer(?datum) > 1849 &&  xsd:integer(?datum) < 2001)
   } GROUP BY ?datum
  }
   OPTIONAL { SELECT ?datum (COUNT(?datum) AS ?indonesia) WHERE {
    ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
         <http://semanticweb.cs.vu.nl/2009/11/sem/hasBeginTimeStamp> ?datum;
         dct:spatial <http://data.bibliotheken.nl/id/thes/p078544114>.
   } GROUP BY ?datum
  }
} ORDER BY ?datum

Voer de query uit

We hebben nu een overzicht van aantal uitgaven per jaar en het aantal uitgaven dat betrekking heeft op Indonesië. En hier kunnen we weer verder op bouwen. Laten we eens kijken of we nog meer 'ruimtelijke' kwalificaties kunnen vinden.

Query 5

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT DISTINCT ?space WHERE {
   ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
        dct:spatial ?space.
} 

Voer de query uit

# Nu met een count
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT DISTINCT ?space (COUNT(?space) AS ?nr) WHERE {
   ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
        dct:spatial ?space.
} GROUP BY ?space ORDER BY DESC(?nr)

Voer de query uit

Wat valt je op? Zie je problemen? Het zal je in elk geval opvallen dat de URIs waarmee plaatsen en landen geïdentificeerd worden, niet erg veelzeggend zijn. Labels voor de URIs worden in de dataset niet gegeven. Pas bovenstaande query maar eens aan naar:

SELECT DISTINCT ?space ?label WHERE {
   ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
        dct:spatial ?space.
  ?space rdfs:label ?label.
}

Dat werkt dus niet. Gelukkig kunnen we de label van de URIs in het domein bibliotheken.nl ophalen middels een SERVICE statement.

Query 6

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

SELECT DISTINCT ?space ?label WHERE {
   ?sub dct:isPartOf "Collectie Geschiedenis van de Voeding 9940875388005131";
        dct:spatial ?space.
SERVICE <http://data.bibliotheken.nl/sparql>
  {?space skos:prefLabel ?label.
  FILTER langMatches( lang(?label), "nl" )}
} 

Voer de query uit

Je zult merken dat het wel een tijdje duurt (zo’n 25 seconden) voordat je resultaat krijgt. Maar het werkt wel!

Verder kijken

De query op de data van de UB èn de KB laat mooi het potentieel van Linked Data zien. We hoeven queries niet meer tot één dataset te beperken. En dat betekent ook dat we data uit ene datset kunnen gebruiken om de data in een verbonden dataset te verrijken. Hieronder volgen wat aanzetjes.

Chronologische woordenlijst

In de inleidende paragraaf is het Chronologisch Woordenboek (2001) van Nicoline van der Sijs genoemd als interessant vergelijkingsmateriaal. Een 'culinaire' selectie uit dit woordenboek is te raadplegen in dit bestad.

De kookboekencollectie van de KB

Ook de KB heeft een uitgebreide kookboekencollectie en veel gegevens over die kookboeken zijn op te halen bij het SPARQL endpoint van de KB. Maar we blijven middels een trucje met een SERVICE statement nog even in de ons inmiddels vertrouwde omgeving. Laten we eens wat titels van kookboeken bij de KB ophalen.

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX schema: <http://schema.org/>

SELECT ?sub ?title WHERE {

SERVICE <http://data.bibliotheken.nl/sparql>
{ ?sub schema:about <http://data.bibliotheken.nl/id/thes/p077606906>;
     rdfs:label ?title.}

} LIMIT 100

Voer de query uit

Als je het SERVICE statement weghaalt, zou je de query ook rechtstreeks op het endpoint van de KB afkunnen vuren. Er zit ook een gekkigheidje in. De URI <http://data.bibliotheken.nl/id/thes/p077606906> heeft verder geen eigenschappen, behalve dan dat hij de schema:about van 4150 kookboeken is. Als we het PPN nummer opzoeken in de catalogus van de KB, blijkt het om eetwaren naar bereiding te gaan.

Misschien zijn er nog meer van zulke trefwoorden waar we op kunnen zoeken. Laten we eens kijken of er nog iets in de Brinkman trefwoorden catalogus zit.

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX schema: <http://schema.org/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>

SELECT ?uri ?label WHERE {

?uri skos:inScheme <http://data.bibliotheken.nl/id/scheme/brinkman> ;
     skos:prefLabel ?label.
FILTER(regex(?label, "(K|k)(o|oo)k", "i" ))

}

Voer de query uit op het endpoint van de KB

Wikidata

We hebben al geconstateerd dat de metadatering soms wel beter kan. Zou het niet handiger zijn om kookboeken te classificeren naar nationale of regionale keuken in plaats van naar land? Laten we eens in Wikidata zoeken of daar mogelijkheden voor zijn. We vragen een lijst op met nationale en regionale keukens. En als we dat toch doen, dan vragen we meteen even of de Library of Congress daar misschien ook iets over weet.

#National and reginal cuisines
SELECT ?item ?itemLabel ?loc
WHERE 
{
  {?item wdt:P31 wd:Q1968435.} #Ask for instances of "National cuisine"
  UNION
  {?item wdt:P31 wd:Q94951.} # or "Regional cuisine"
  OPTIONAL {?item wdt:P244 ?locgov.
           BIND(CONCAT("https://id.loc.gov/authorities/",STR( ?locgov )) AS ?loc ) .} # If available return Library of Congress identifier for the topic
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } # Return the label in your preferred language, if not available, then in English
  
}

Voer de query uit