Ejemplos SPARQL

Un punto final SPARQL legible por máquina permite consultar las descripciones RDF de los conjuntos de datos del catálogo mediante el lenguaje SPARQL. Ofrece a los desarrolladores/profesionales una gran potencia y flexibilidad a la hora de realizar consultas y construir aplicaciones.

Información almacenada

Toda la información que se puede consultar se encuentra cargada en una base de datos semántica. En este tipo de bases de datos la información se almacena en grafos.

La base de datos semántica de datos.gob.es cuenta con dos grafos:

Cómo se usa 

Editor de consultas SPARQL

Para realizar las peticiones se puede utilizar el editor de consultas SPARQL del portal. Este tipo de formularios ofrecen ayuda al desarrollador proporcionando un área de texto que usa colores para resaltar e identificar errores de sintaxis, tiene función autocompletado y permite la opción de ejecutar las consultas, entre otros.

Editor SPARQL de datos.gob.es

Solicitud HTTP

Las consultas SPARQL se pueden hacer a través de peticiones GET, que devuelven los datos según los parámetros que se especifican en la llamada.

La dirección base del punto SPARQL del Catálogo de datos es la siguiente:

http://datos.gob.es/virtuoso/sparql

A esta dirección hay que añadir el parámetro query y a continuación la consulta que queremos realizar.

Por ejemplo, si queremos ejecutar la siguiente consulta que obtiene las diferentes entidades del grafo:

SELECT DISTINCT ?tipo
WHERE { 
  ?x a ?tipo.
}
LIMIT 10
  1. Debemos codificarla como una URL sustituyendo los espacios por +, de la siguiente forma: 

    SELECT+DISTINCT+?tipo+WHERE+{?x+a+?tipo}+LIMIT+10
  2. Una vez codificada y conociendo la dirección de nuestro punto de SPARQL, se ejecutaría de la siguiente manera:

    https://datos.gob.es/virtuoso/sparql?query=SELECT+DISTINCT+?tipo+WHERE+{?x+a+?tipo}+LIMIT+10

 

Si a la dirección base del punto SPARQL, no le añadimos el parámetro query con la consulta que queremos realizar, nos devolverá un error de página no encontrada.

El formato por defecto de las respuestas es HTML, pero se puede especificar otro a través del parámetro format, por ejemplo para obtenerla en formato tabular separado por comas (CSV):

https://datos.gob.es/virtuoso/sparql?query=SELECT+DISTINCT+?tipo+WHERE+{?x+a+?tipo}+LIMIT+10&format=text/csv

Este parámetro puede tomar los siguientes valores:

Valor Formato
text/html HTML
application/vnd.ms-excel Spreadsheet
text/tab-separated-values TSV
application/sparql-results+xml XML
application/sparql-results+json JSON
application/javascript Javascript
text/turtle Turtle
application/rdf+xml RDF/XML
text/plain N-Triples
text/csv CSV

 

Ejemplos

Consultar los grafos disponibles en el punto SPARQL

Si al realizar la consulta no se especifica ningún grafo, se devolverá la información de todos los grafos que estén disponibles.

Se pueden consultar los grafos disponibles con esta consulta:

SELECT DISTINCT ?uri
WHERE { 
  GRAPH ?uri { 
    ?s a ?t 
  } 
}

Si queremos obtener a qué grafo pertenece la información, se puede especificar de la siguiente manera donde la variable ?g vamos a ver en que grafo se encuentra cada ?x

SELECT DISTINCT ?g ?tipo
WHERE { 
  GRAPH ?g { 
    ?x a ?tipo.
  } 
} 
LIMIT 100

Podemos obtener los resultados de un solo de la siguiente manera:

SELECT DISTINCT ?tipo
WHERE { 
	GRAPH <http://datos.gob.es/catalogo> { 
		?x a ?tipo. 
  } 
} 
LIMIT 100

Ahora solo veremos las ?x que se encuentren en el grafo especificado.

Obtener todas las clases que hay en el punto SPARQL

Esta consulta es muy útil porque vamos a ver toda los tipos de información que hay almacenados.

Además para evitar obtener información que no nos ayuda, vamos a especificar nuestros grafos.

Primero especificamos el grafo del Catálogo:

SELECT DISTINCT ?tipo
WHERE { 
 GRAPH <http://datos.gob.es/catalogo> {
  ?x a ?tipo.
 } 
}

Ahora usaremos los dos grafos a la vez gracias a VALUES

SELECT DISTINCT ?tipo
WHERE { 
  GRAPH ?grafo { 
    ?x a ?tipo.
    }
   VALUES ?grafo {
     <http://datos.gob.es/catalogo> <http://datos.gob.es/nti>
   } 
}

El resultado final será parecido a lo siguiente:

 

Obtener todos los conjuntos de datos del Catálogo

Ahora que ya conocemos los tipos, vamos a pedir todos los conjuntos de datos, que se corresponden con esta URI: http://www.w3.org/ns/dcat#Dataset

PREFIX dcat: <http://www.w3.org/ns/dcat#>
SELECT DISTINCT ?dataset
WHERE {
  ?dataset a dcat:Dataset .
}

El resultado es una lista de URLs de todos los conjuntos de datos.

 

Obtener todos los servicios de datos del Catálogo

Ahora que ya conocemos los tipos, vamos a pedir todos los conjuntos de datos, que se corresponden con esta URI: http://www.w3.org/ns/dcat#DataService

PREFIX dcat: <http://www.w3.org/ns/dcat#>
SELECT DISTINCT ?dataService
WHERE {
  ?dataService a dcat:DataService .
}

El resultado es una lista de URLs de todos los servicios de datos.

 

Obtener el número de entidades principales y publicadores por Grafo

Una consulta SPARQL para obtener una visión general rápida del contenido, lista el número de recursos por tipo —dcat:Dataset (conjuntos de datos), dcat:DataService (servicios de datos), dcat:Distribution (distribuciones) y dct:publisher (publicadores del recurso)— por cada grafo (g) con contenido.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct:  <http://purl.org/dc/terms/>
SELECT ?g
       (COUNT(DISTINCT ?dataset) AS ?numDatasets)
       (COUNT(DISTINCT ?service) AS ?numDataServices)
       (COUNT(DISTINCT ?distribution) AS ?numDistributions)
       (COUNT(DISTINCT ?publisher) AS ?numPublishers)
WHERE {
  GRAPH ?g {
    ?dataset a dcat:Dataset .
    OPTIONAL { ?dataset dct:publisher ?publisher. }
    OPTIONAL { ?dataset dcat:distribution ?distribution. }
    OPTIONAL { ?service a dcat:DataService. }
  }
}
GROUP BY ?g
ORDER BY DESC(?numDatasets)
LIMIT 100

El resultado sería:

g numDatasets numDataServices numDistributions numPublishers
http://datos.gob.es/catalogo 97573 2 545171 256

 

Obtener todas las propiedades que tienen los conjuntos de datos

Queremos obtener más información de los conjuntos de datos, pero sólo sabemos sus URIs, vamos a preguntar por todas sus propiedades:

PREFIX dcat: <http://www.w3.org/ns/dcat#>
SELECT DISTINCT ?propiedad
WHERE {
  ?dataset a dcat:Dataset .
  ?dataset ?propiedad ?valor . 
}

Estas son algunas de las propiedades que tienen, se puede observar como al haber definido el prefijo PREFIX dcat: <http://www.w3.org/ns/dcat#>, en la respuesta se incluye dcat:keyword en vez de http://www.w3.org/ns/dcat#keyword

 

Obtener todas las propiedades que tienen los servicios de datos

De forma parecida, podemos recuperar todas las propiedades de los servicios de datos:

PREFIX dcat: <http://www.w3.org/ns/dcat#>
SELECT DISTINCT ?propiedad
WHERE {
  ?dataService a dcat:DataService .
  ?dataService ?propiedad ?valor . 
}

Estas son algunas de las propiedades que tienen:

 

Obtener todos los organismos que publican datos

Vamos a utilizar la propiedad  dct:publisher (publicador) para obtener todos los organismos que publican datos.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
SELECT DISTINCT ?publicador
WHERE {
  ?x a dcat:Dataset .
  ?x dct:publisher ?publicador. 
}

 

Obtener las propiedades de los organismos que publican conjuntos de datos

Con las URIs no sabemos el nombre de los organismos, vamos a preguntar por las propiedades de estas URIs.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
SELECT DISTINCT ?propiedad
WHERE {
  ?x a dcat:Dataset .
  ?x dct:publisher ?publicador. 
  ?publicador ?propiedad ?valor. 
}

Estas son todas las propiedades de los publicadores:

 

Obtener los nombres de los organismos que publican conjuntos de datos

Vamos a recuperar la URI y el nombre de los organismos (foaf:name) que publican conjuntos de datos. Como podría existir que estuvieran en diferentes idiomas, filtramos específicamente por los nombres en español (es), pero podría utilizarse cualquier otra etiqueta de idioma en que estuvieran indicados los organismos.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?publicador ?nombre
WHERE {
  ?x a dcat:Dataset ;
     dct:publisher ?publicador .
  ?publicador foaf:name ?nombre.
  FILTER(LANGMATCHES(LANG(?nombre), "es"))
}

El resultado es una lista con todos los organismos publicadores y su nombre:

publicador nombre
http://datos.gob.es/recurso/sector-publico/org/Organismo/E05068001 "Ministerio para la Transición Ecológica y el Reto Demográfico"
http://datos.gob.es/recurso/sector-publico/org/Organismo/EA0010587 "Instituto Nacional de Estadística"
http://datos.gob.es/recurso/sector-publico/org/Organismo/E05068901 "Ministerio de Asuntos Económicos y Transformación Digital"
http://datos.gob.es/recurso/sector-publico/org/Organismo/EA0019768 "Biblioteca Nacional de España"
Resto de URIs de organismos... Resto de nombres de organismos...

 

Obtener los nombres de los diez organismos que más conjuntos de datos tienen publicados y visualizar el número de éstos

Para realizar esta consulta vamos a tener que agrupar resultados, ordenarlos y limitar el total a 10.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?nombre
 (COUNT(?x) AS ?num)
WHERE {
  { ?x a dcat:Dataset } .
  ?x dct:publisher ?publicador .
  ?publicador foaf:name ?nombre
 .
}
GROUP BY ?nombre
 
ORDER BY DESC(?num)
LIMIT 10

El resultado será el siguiente:

nombre num
"Instituto Nacional de Estadística" 21629
"Instituto Canario de Estadística" 21326
"Comunidad Autónoma del País Vasco" 8707
"Parlamento de Canarias" 4355
Resto de nombres de organismos... Resto de datasets publicados...

 

Obtener los nombres de los diez organismos que más servicios de datos tienen publicados y visualizar el número de éstos

Podemos aplicar el mismo ejemplo anterior, pero en este caso para los servicios de datos  (dcat:DataService) .

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?nombre (COUNT(?x) AS ?num)
WHERE {
  { ?x a dcat:DataService } .
  ?x dct:publisher ?publicador .
  ?publicador foaf:name ?nombre .
}
GROUP BY ?nombre
ORDER BY DESC(?num)
LIMIT 10

El resultado será el siguiente:

nombre num
"Ministerio para la Transición Ecológica y el Reto Demográfico" 1
"Instituto Nacional de Estadística" 1
Resto de nombres de organismos... Resto de servicios publicados...

 

Obtener los nombres de los diez organismos que más datos totales tienen publicados y visualizar el número desagregado

Combinando ambos ejemplos anteriores, podemos retornar el número de servicios  (dcat:DataService)  y conjuntos de datos (dcat:DataService) por organismo publicador, y el total de entidades publicadas. Para ello se suman ambos totales, y se presentan los resultados ordenados de mayor a menor número de recursos publicados. Adicionalmente el FILTER(BOUND(?dataset) || BOUND(?service)) excluye organismos "vacíos" del ranking, mostrando solo aquellos que efectivamente han contribuido con conjuntos o servicios al catálogo.

PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?nombre 
       (COUNT(DISTINCT ?dataset) AS ?numDatasets)
       (COUNT(DISTINCT ?service) AS ?numDataServices)
       ((COUNT(DISTINCT ?dataset) + COUNT(DISTINCT ?service)) AS ?numTotal)
WHERE {
  ?publicador foaf:name ?nombre .
 
  FILTER(LANGMATCHES(LANG(?nombre), "es"))  
  
  OPTIONAL { ?dataset a dcat:Dataset ; dct:publisher ?publicador . }
  OPTIONAL { ?service a dcat:DataService ; dct:publisher ?publicador . }
  
  FILTER(BOUND(?dataset) || BOUND(?service))
}
GROUP BY ?nombre
ORDER BY DESC(?numTotal)
LIMIT 10

El resultado será el siguiente:

nombre numDatasets numDataServices numTotal
"Instituto Nacional de Estadística" 21629 1 21630
"Instituto Canario de Estadística" 21326 0 21326
"Comunidad Autónoma del País Vasco" 8707 0 8707
"Parlamento de Canarias" 4355 0 4355
Resto de nombres de organismos... Resto de datasets publicados... Resto de servicios publicados... Resto de totales publicados...