SPARQL

SPARQL es el acrónimo de Protocolo Simple y Lenguaje de Consulta de RDF. SPARQL es una tecnología que permite hacer consultas sobre información expresada en RDF, usando distintas fuentes de datos y permite obtener también los resultados en formato RDF para poder reutilizarlos en las aplicaciones.
Acceso al Punto SPARQL

Tabla de Contenido

Primeros pasos

Listado de grafos

El punto SPARQL está dividido en grafos de forma que en un grafo existen las tripletas relaciondadas con un conjunto de datos determinado. Podemos conocer los diferentes grafos existentes ejecutando la siguiente consulta SPARQL

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

Resultado de la consulta
Grafo Contenido
http://www.zaragoza.es/turismo/restaurante/ Restaurantes
http://www.zaragoza.es/turismo/monumento/ Monumentos
http://www.zaragoza.es/cultura-ocio/evento-zaragoza/ Agenda de actividades
http://www.zaragoza.es/empleo/oferta/ Oferta de empleo
http://www.zaragoza.es/urbanismo-infraestructuras/equipamiento/urbano/ Paradas de taxi, aparcamientos ...
http://www.zaragoza.es/urbanismo-infraestructuras/equipamiento/recurso/ Equipamientos/Recursos de la ciudad
http://www.zaragoza.es/sector-publico/subvencion/ Subvenciones
http://www.zaragoza.es/sector-publico/contrato Perfil del contratante
http://www.zaragoza.es/dataset/catalogo/ Catálogo de datos abiertos
http://www.zaragoza.es/medio-ambiente/calidad-aire/ Calidad del aire
http://www.zaragoza.es/urbanismo-infraestructuras/callejero/ Callejero, portalero e información semántica asociada
http://www.zaragoza.es/turismo/edificio-historico/ Catálogo de edificios históricos
http://www.zaragoza.es/turismo/alojamiento/ Alojamientos de la ciudad
http://www.zaragoza.es/sector-publico/organismo/ Estructura organizativa del ayuntamiento
...

Objetos de un grafo

Dentro de cada uno de los grafos están los diferentes objetos asociados. Para ver los objetos que existen dentro de un grafo podemos ejecutar la siguiente consulta. Indicando el grafo sobre el que queremos realizar la consulta.

Graph IRI: http://www.zaragoza.es/urbanismo-infraestructuras/equipamiento/recurso/
select distinct ?uri where {[] a ?uri}

Resultado:

  • http://www.zaragoza.es/api/kos/cultura-ocio/ludotecas
  • http://www.zaragoza.es/api/kos/deporte/campos-de-futbol
  • http://www.zaragoza.es/api/kos/salud/farmacias
  • http://www.zaragoza.es/api/kos/cultura-ocio/museos
  • ...

Propiedades de un objeto

Supongamos que queremos trabajar con los museos (http://www.zaragoza.es/api/kos/cultura-ocio/museos), en primer lugar tenemos que conocer las propiedades que puede tener el objeto, para lo cual ejecutaremos la siguiente consulta.

select distinct ?uri 
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
    ?uri ?obj.
}

Resultado y significado
Propiedad Significado
http://www.w3.org/1999/02/22-rdf-syntax-ns#type Tipo
http://purl.org/dc/terms/modified Fecha de modificación
http://www.w3.org/2000/01/rdf-schema#label Nombre del recurso
http://schema.org/name Nombre del recurso
http://purl.org/dc/terms/title Nombre del recurso
http://www.geonames.org/ontology#name Nombre del recurso
http://www.w3.org/2000/01/rdf-schema#comment Descripción
http://purl.org/dc/terms/description Descripción
http://schema.org/description Descripción
http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#accesibilidad Información de accesibilidad
http://schema.org/price Precio
http://purl.org/dc/terms/identifier Identificador
http://www.w3.org/2006/vcard/ns#email Correo electrónico
http://www.w3.org/2006/vcard/ns#street-adr Dirección
http://www.w3.org/2006/vcard/ns#url Sitio web
http://www.w3.org/2004/02/skos/core#Concept
http://www.w3.org/2006/vcard/ns#photo Imagen del recurso
http://www.w3.org/2006/vcard/ns#tel Teléfono
http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#gradoAccesibilidad Grado de accesibilidad
http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#servicios Servicios
http://schema.org/typicalAgeRange Población destinataria
http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#institucion Institución
http://www.w3.org/2003/01/geo/wgs84_pos#geometry Coordenadas
http://www.w3.org/2006/vcard/ns#category Tipo de equipamiento
http://purl.org/goodrelations/v1#hasOpeningHoursSpecification Horario

En el listado anterior aparecen repetidas propiedades para facilitar el trabajo con varios vocabularios

Contar el número de registros de un tipo determinado.

Para contar el número de registros de un tipo ejecutaríamos la siguiente consulta:

select COUNT(?Concepto) AS ?numero Where{ ?Concepto a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>. }

Ejemplo de listado

Una vez hemos visto las propiedades, nos planteamos, por ejemplo, obtener un listado de museos con las propiedades, uri del recurso, nombre, horario y el tipo, para lo que ejecutaríamos la siguiente consulta.

select distinct ?uriCont ?nombre ?horario ?tipo
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        <http://www.w3.org/2000/01/rdf-schema#label> ?nombre;
        <http://purl.org/goodrelations/v1#hasOpeningHoursSpecification> ?horario;
        <http://www.w3.org/2006/vcard/ns#category> ?tipo.
}

En el campo tipo nos aparece su URI pero queremos el nombre del tipo, para saber qué información está almacenada sobre una uri, podemos ejecutar

describe <http://www.zaragoza.es/api/recurso/urbanismo-infraestructuras/equipamiento/subtema/144>

En el resultado vemos que el nombre del tipo está en la propiedad rdfs:label por lo que la consulta la modificaríamos de la siguiente forma

select distinct ?uriCont ?nombre ?horario ?tipo
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        <http://www.w3.org/2000/01/rdf-schema#label> ?nombre;
        <http://purl.org/goodrelations/v1#hasOpeningHoursSpecification> ?horario;
        <http://www.w3.org/2006/vcard/ns#category>/rdfs:label ?tipo.
}

Observando los resultados vemos que aparecen registros repetidos porque un recurso puede tener varios tipos, por lo que vamos a concatenar los diferentes tipos en una sola columna.

select distinct ?uriCont ?nombre ?horario (group_concat(distinct ?tipo;separator=",")) as ?tipo
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        <http://www.w3.org/2000/01/rdf-schema#label> ?nombre;
        <http://purl.org/goodrelations/v1#hasOpeningHoursSpecification> ?horario;
        <http://www.w3.org/2006/vcard/ns#category>/rdfs:label ?tipo.
}

A la consulta anterior vamos a añadir las coordenadas del recurso.

select distinct ?uriCont ?nombre ?horario (group_concat(distinct ?tipo;separator=",")) as ?tipo ?coordenadas
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        <http://www.w3.org/2000/01/rdf-schema#label> ?nombre;
        <http://purl.org/goodrelations/v1#hasOpeningHoursSpecification> ?horario;
        <http://www.w3.org/2006/vcard/ns#category>/rdfs:label ?tipo;
        <http://www.w3.org/2003/01/geo/wgs84_pos#geometry> ?coordenadas.

}

Nos vuelven a salir recursos repetidos porque las coordenadas están en 3 sistemas de referencia, utm30n, etre89 y wgs84, en el ejemplo vamos a utilizar el sistema wgs84, recuperando la latitud y la longitud, con OPTIONAL para recuperar los recursos aunque no estén localizados .

select distinct ?uriCont ?nombre ?horario (group_concat(distinct ?tipo;separator=",")) as ?tipo ?latitud ?longitud
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        <http://www.w3.org/2000/01/rdf-schema#label> ?nombre;
        <http://purl.org/goodrelations/v1#hasOpeningHoursSpecification> ?horario;
        <http://www.w3.org/2006/vcard/ns#category>/rdfs:label ?tipo.
    optional {
        ?uriCont <http://www.w3.org/2003/01/geo/wgs84_pos#geometry> ?coordenadas. 
            ?coordenadas <http://www.w3.org/2003/01/geo/wgs84_pos#lat> ?latitud;
            <http://www.w3.org/2003/01/geo/wgs84_pos#long> ?longitud.
    } 
}

La consulta anterior la vamos a simplificar utilizando prefijos, el prefijo rdfs no se tiene que declarar porque es uno de los reconocidos por defecto.

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX v:<http://www.w3.org/2006/vcard/ns#>
PREFIX geo:<http://www.w3.org/2003/01/geo/wgs84_pos#>
select distinct ?uriCont ?nombre ?horario (group_concat(distinct ?tipo;separator=",")) as ?tipo ?latitud ?longitud
where  {
    ?uriCont a cultura:museos;
        rdfs:label ?nombre;
        gr:hasOpeningHoursSpecification ?horario;
        v:category/rdfs:label ?tipo.
    optional {
        ?uriCont geo:geometry ?coordenadas. 
            ?coordenadas geo:lat ?latitud;
            geo:long ?longitud.
    }
}

Podemos indicar que nos devuelva el valor sin el tipo de dato de la siguiente forma:

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX v:<http://www.w3.org/2006/vcard/ns#>
PREFIX geo:<http://www.w3.org/2003/01/geo/wgs84_pos#>
select distinct ?uriCont str(?nombre) as ?nombre str(?horario) as ?horario (group_concat(distinct ?tipo;separator=",")) as ?tipo ?latitud ?longitud
where  {
    ?uriCont a cultura:museos;
        rdfs:label ?nombre;
        gr:hasOpeningHoursSpecification ?horario;
        v:category/rdfs:label ?tipo.
    optional {
        ?uriCont geo:geometry ?coordenadas. 
            ?coordenadas geo:lat ?latitud;
            geo:long ?longitud.
    }
}

Ejemplo de detalle

Podemos ver todas las propiedades de un recurso en concreto utilizando la siguiente consulta:

select * 
where {  
    <http://www.zaragoza.es/api/recurso/urbanismo-infraestructuras/equipamiento/recurso/2174> ?prop ?value. 
}

Lo que ocurre es que existirán propiedades que no aparezcan en todos los recursos del mismo tipo por lo que es preferible conocer las propiedades que puede tener ese tipo de recurso, para lo cual ejecutaremos la misma consulta del apartado anterior, obteniendo el mismo resultado.

select distinct ?uri 
where  {
    ?uriCont a <http://www.zaragoza.es/api/kos/cultura-ocio/museos>;
        ?uri ?obj.
}

Con las propiedades obtenidas preparamos la consulta para obtener los datos del recurso 2174

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX v: <http://www.w3.org/2006/vcard/ns#>
PREFIX tur:<http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX s:<http://schema.org>

SELECT ?uriCont ?nombre ?description ?infoAccesibilidad ?precio ?email ?direccion ?photo ?web ?tel ?gradoAccesibilidad ?servicios ?poblacion ?institucion ?coordenadas ?tipo ?horario ?lastUpdated
WHERE {
    ?uriCont a cultura:museos.
    ?uriCont dcterms:identifier "2174".
    ?uriCont rdfs:label ?nombre.
    ?uriCont rdfs:comment ?description.
    ?uriCont tur:accesibilidad ?infoAccesibilidad.
    ?uriCont s:price ?precio.
    ?uriCont v:email ?email.
    ?uriCont v:street-adr ?direccion.
    ?uriCont v:photo ?photo.
    ?uriCont v:url ?web.
    ?uriCont v:tel ?tel.
    ?uriCont tur:gradoAccesibilidad ?gradoAccesibilidad.
    ?uriCont tur:servicios ?servicios.
    ?uriCont s:typicalAgeRange ?poblacion.
    ?uriCont tur:institucion ?institucion.
    ?uriCont geo:geometry ?coordenadas.
    ?uriCont v:category ?tipo.
    ?uriCont gr:hasOpeningHoursSpecification ?horario.
    ?uriCont dcterms:modified ?lastUpdated.
}

Al ejecutar la consulta no nos devuelve ningún resultado por lo que añadimos optional a los campos:

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX v: <http://www.w3.org/2006/vcard/ns#>
PREFIX tur:<http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX s:<http://schema.org>

SELECT ?uriCont ?nombre ?description ?infoAccesibilidad ?precio ?email ?direccion ?photo ?web ?tel ?gradoAccesibilidad ?servicios ?poblacion ?institucion ?coordenadas ?tipo ?horario ?lastUpdated
WHERE {
    ?uriCont a cultura:museos.
    ?uriCont dcterms:identifier "2174".
    ?uriCont rdfs:label ?nombre.
    optional{?uriCont rdfs:comment ?description.}
    optional{?uriCont tur:accesibilidad ?infoAccesibilidad.}
    optional{?uriCont s:price ?precio.}
    optional{?uriCont v:email ?email.}
    optional{?uriCont v:street-adr ?direccion.}
    optional{?uriCont v:photo ?photo.}
    optional{?uriCont v:url ?web.}
    optional{?uriCont v:tel ?tel.}
    optional{?uriCont tur:gradoAccesibilidad ?gradoAccesibilidad.}
    optional{?uriCont tur:servicios ?servicios.}
    optional{?uriCont s:typicalAgeRange ?poblacion.}
    optional{?uriCont tur:institucion ?institucion.}
    optional{?uriCont geo:geometry ?coordenadas.}
    optional{?uriCont v:category ?tipo.}
    optional{?uriCont gr:hasOpeningHoursSpecification ?horario.}
    optional{?uriCont dcterms:modified ?lastUpdated.}
}

Ahora vemos que nos aparecen muchos registros repetidos, tanto por los diferentes tipos como por las coordenadas en diferentes sistemas de referencia

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX v: <http://www.w3.org/2006/vcard/ns#>
PREFIX tur:<http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX s:<http://schema.org>

SELECT ?uriCont ?nombre ?description ?infoAccesibilidad ?precio ?email ?direccion ?photo ?web ?tel ?gradoAccesibilidad ?servicios ?poblacion ?institucion ?latitud ?longitud (group_concat(distinct ?tipo;separator=",")) as ?tipo ?horario ?lastUpdated
WHERE {
    ?uriCont a cultura:museos.
    ?uriCont dcterms:identifier "2174".
    ?uriCont rdfs:label ?nombre.
    optional{?uriCont rdfs:comment ?description.}
    optional{?uriCont tur:accesibilidad ?infoAccesibilidad.}
    optional{?uriCont s:price ?precio.}
    optional{?uriCont v:email ?email.}
    optional{?uriCont v:street-adr ?direccion.}
    optional{?uriCont v:photo ?photo.}
    optional{?uriCont v:url ?web.}
    optional{?uriCont v:tel ?tel.}
    optional{?uriCont tur:gradoAccesibilidad ?gradoAccesibilidad.}
    optional{?uriCont tur:servicios ?servicios.}
    optional{?uriCont s:typicalAgeRange ?poblacion.}
    optional{?uriCont tur:institucion ?institucion.}
    optional {
        ?uriCont geo:geometry ?coordenadas. 
            ?coordenadas geo:lat ?latitud;
            geo:long ?longitud.
    } 
    optional{?uriCont v:category ?tipo.}
    optional{?uriCont gr:hasOpeningHoursSpecification ?horario.}
    optional{?uriCont dcterms:modified ?lastUpdated.}
}

Ahora ya podemos obtener los datos del registro sin duplicados. En algunos elementos en vez del valor nos aparece su uri, por lo que tenemos que obtener los valores de esos campos.

PREFIX cultura: <http://www.zaragoza.es/api/kos/cultura-ocio/>
PREFIX v: <http://www.w3.org/2006/vcard/ns#>
PREFIX tur:<http://vocab.linkeddata.es/datosabiertos/def/turismo/lugar#>
PREFIX gr:<http://purl.org/goodrelations/v1#>
PREFIX s:<http://schema.org>

SELECT ?uriCont ?nombre ?description ?infoAccesibilidad ?precio ?email ?direccion ?photo ?web ?tel ?gradoAccesibilidad ?servicios ?poblacion ?institucion ?latitud ?longitud (group_concat(distinct ?tipo;separator=",")) as ?tipo ?horario ?lastUpdated
WHERE {
    ?uriCont a cultura:museos.
    ?uriCont dcterms:identifier "2174".
    ?uriCont rdfs:label ?nombre.
    optional{?uriCont rdfs:comment ?description.}
    optional{?uriCont tur:accesibilidad ?infoAccesibilidad.}
    optional{?uriCont s:price ?precio.}
    optional{?uriCont v:email ?email.}
    optional{?uriCont v:street-adr ?direccion.}
    optional{?uriCont v:photo ?photo.}
    optional{?uriCont v:url ?web.}
    optional{?uriCont v:tel/v:Tel ?tel.}
    optional{?uriCont tur:gradoAccesibilidad ?gradoAccesibilidad.}
    optional{?uriCont tur:servicios ?servicios.}
    optional{?uriCont s:typicalAgeRange/rdfs:label ?poblacion.}
    optional{?uriCont tur:institucion ?institucion.}
    optional {
        ?uriCont geo:geometry ?coordenadas. 
            ?coordenadas geo:lat ?latitud;
            geo:long ?longitud.
    } 
    optional{?uriCont v:category/rdfs:label ?tipo.}
    optional{?uriCont gr:hasOpeningHoursSpecification ?horario.}
    optional{?uriCont dcterms:modified ?lastUpdated.}
}

Formatos de respuesta

Hasta ahora al no haber seleccionado el formato veíamos los resultados en formato HTML, pero podemos indicar otros formatos como son:

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

La url resultante de la ejecución es la que podemos utilizar desde las aplicaciones, y tendrá la siguiente sintaxis:

http://datos.zaragoza.es/sparql?default-graph-uri=' + encodeURIComponent(grafo) + '&query=' + encodeURIComponent(querySPARQL) + '&format=' + encodeURIComponent(formato) + '&timeout=0

Listado de prefijos precargados en el punto SPARQL

dbpedia http://dbpedia.org/resource/
dbpprop http://dbpedia.org/property/
dc http://purl.org/dc/elements/1.1/
dcterms http://purl.org/dc/terms/
fn http://www.w3.org/2005/xpath-functions/#
foaf http://xmlns.com/foaf/0.1/
geo http://www.w3.org/2003/01/geo/wgs84_pos#
gr http://purl.org/goodrelations/v1#
ldp http://www.w3.org/ns/ldp#
ogcgml http://www.opengis.net/ont/gml#
ogcgs http://www.opengis.net/ont/geosparql#

Enlaces de interés