简体   繁体   中英

Literal as subject in SPARQL CONSTRUCT query

I am struggling creating a correct SPARQL query which will produce the right format so that I can open in it Protege. Our ontology is about cocktails, we want to have all DBPedia cocktails in our database, including the ingredients ( dbp:ingredients ) and recipe ( dbp:prep ). Getting the cocktail in the database works fine, but the ingredients and recipe not. I have now the following query:

CONSTRUCT {?drink dct:subject ?category.
?drink dbp:prep ?recipe.
?drink dbp:ingredients ?ingredients.
?drink rdf:type owl:NamedIndividual .
?category rdf:type owl:Class.
dct:subject rdf:type owl:ObjectProperty.
dbp:prep rdf:type owl:ObjectProperty.
dbp:ingredient rdf:type owl:Objectproperty.
}
WHERE {
?drink dct:subject ?category.
?drink dbp:prep ?recipe.
?drink dbp:ingredients ?ingredients.}

Since ?ingredients and ?recipe are now not declared, it does not show in the individuals tab in Protege. But when I add this to the CONSTRUCT part of the query:

?recipe rdf:type owl:NamedIndividual.
?ingredients rdf:type owl:NamedIndividual.

I get an error:

Virtuoso RDF01 Error Bad variable value in CONSTRUCT: "*5 cL vodka *10 cL orange juice" (tag 246 box flags 0) is not a valid subject, only object of a triple can be a literal

I think because the prep and ingredients on dbpedia are just a string, no linked data. However, how do I make this work so that it does show in Protege?

It's not possible to have a literal as subject of an RDF triple. Instead, creating a resource for recipe and ingredients + attaching the string values as rdfs:comment (or maybe rdfs:label ) could be a workaround. It works like this:

CONSTRUCT {
?drink dct:subject ?category.
?drink dbp:prep ?recipe.
?drink dbp:ingredients ?ingredients.
?drink rdf:type owl:NamedIndividual .
?category rdf:type owl:Class.
dct:subject rdf:type owl:ObjectProperty.
dbp:prep rdf:type owl:ObjectProperty.
dbp:ingredients rdf:type owl:Objectproperty.
# add string values as rdfs:comment
?recipe rdfs:comment ?recipe_str .
?ingredients rdfs:comment ?ingredients_str
}
WHERE {
?drink dct:subject ?category.
?drink dbp:prep ?recipe_str.
?drink dbp:ingredients ?ingredients_str.
BIND(URI(CONCAT("http://dbpedia.org/resource/recipe", MD5(STR(?recipe_str)))) as ?recipe)
BIND(URI(CONCAT("http://dbpedia.org/resource/ingredients", MD5(STR(?ingredients_str)))) as ?ingredients)
}

Note, it would somehow fail if the recipe (resp. ingredients) is already a resource. It doesn't hold for dbp:prep and dbp:ingredients on DBpedia, but in general, if you're not sure and you have some rdf:Property which in fact allows for both resources and literals, you need to handle this properly, eg by using the IF-ELSE construct:

BIND(IF(isLiteral(?recipe_str), URI(CONCAT("http://dbpedia.org/resource/recipe", MD5(STR(?recipe_str)))), ?recipe_str) as ?recipe)
BIND(IF(isLiteral(?ingredients_str), URI(CONCAT("http://dbpedia.org/resource/ingredients", MD5(STR(?ingredients_str)))), ?ingredients_str)  as ?ingredients)

and you also would have to omit the rdfs:comment triples then indeed...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM