Use Literal or String as SPARQL Predicate - sparql

I am constructing a small knowledge graph from triples of strings using rdflib. A typical triple would look like: "Bob" "went" "home", and I am adding them to my graph as shown below (I know I should be using standard objects and namespaces, but this is an experiment to construct the most "barebones" graph that I can):
for s, p, o in triples:
g.add((Literal(s), Literal(p), Literal(o)))
I am attempting to query such a graph using SPARQL, and my query for extracting "Bob" from the above triple looks like:
q = """
SELECT ?s
WHERE { (?s) %s Literal("home"). }
""" % (Literal('went'))
This gives me the error below, which tells me that the query is malformed:
ParseException: Expected {SelectQuery | ConstructQuery | DescribeQuery | AskQuery}, found 'w' (at char 23), (line:1, col:24)
I have tried plugging in the actual strings (e.g. "went" instead of Literal("went")), but that doesn't work either. Several posts like this answer and this answer address how to match literals, but that does not seem to help.
So my question is, is it possible to use Literals or simple strings as predicates in SPARQL, and if so, how? Any help would be much appreciated.

Related

Functions in SPARQL to Manipulate IRIs?

I want to write some reusable SPARQL queries to do things like take an IRI, get the name part (typically after the # sign), modify it (e.g., replace underscores with blank spaces) and put it in the rdfs:label property. This would be useful for Protege which doesn't fill in the rdfs:label if you use user defined IRIs. Or take an IRI with a user defined name, do the same and then replace the user defined IRI with a UUID. I looked in the SPARQL spec for functions to manipulate IRIs and either they don't exist or I'm missing something obvious. I'm posting this to make sure it isn't the latter. I know it is easy to do the equivalent with things like SUBSTR but I'm surprised that there aren't predefined operators to do things like getting the name part of an IRI and getting the base and want to double check before I roll my own.
In case anyone else wants to do this, I figured it out. There are some answers on this site but they are all for SQL or other languages than SPARQL. The following is for classes and it should be obvious how to adapt it for other entities. Note: this works in the Snap SPARQL Plugin for Protege (that's why I use CONSTRUCT rather than INSERT), however, there is a bug in their implementation of SUBSTR so that it uses 0 based indexing rather than 1 based as the spec says. So if you use this in Snap SPARQL change the 1 to a 2.
CONSTRUCT {?c rdfs:label ?lblname.}
WHERE {?c rdfs:subClassOf owl:Thing.
BIND(STRAFTER(STR(?c), '#') as ?name)
BIND(REPLACE(?name,"([A-Z])", " $1" ) as ?namewbs)
BIND (IF (STRSTARTS(?namewbs," "),SUBSTR(?namewbs,1),?namewbs) AS ?lblname)
FILTER(?c != owl:Thing || ?c != owl:Nothing)}

Is it possible to use variables as integers in SPARQL property paths?

I am currently trying to create pointers to datatype values as they cannot be linked directly. However, I would like to be able to evaluate the pointers from within the SPARQL environment, which raised specifically in the case that the desired value is part of an ordered rdf:List some questions for me. My approach is to use property paths within a SPARQL query in which I can use the defined individual, property and index of the ordered list that the pointer has attached to it.
Given the following example data with the shortened syntax for ordered lists by ttl:
ex:myObject ex:somePropery ("1" "2" "3") .
ex:myPointer ex:lookAtIndividual ex:myObject;
ex:lookAtProperty ex:someProperty ;
ex:lookAtIndex "3"^^xsd:integer .
Now I would like to create a SPARQL query that -- based on the pointer -- returns the value at the given index. To my understanding the query could/should look something like this:
SELECT ?value
WHERE {
ex:myPointer ex:lookAtIndividual ?individual ;
ex:lookAtProperty ?prop ;
ex:lookAtIndex ?index .
?individual ?prop/rdf:rest{?index-1}/rdf:first ?value .
}
But if I try to execute this query with TopBraid, it shows an error message that ?index has been found when <INTEGER> was expected. I also tried binding the index in the SPARQL query via BIND(?index-1 AS ?i), again without success. If the pointed value is not stored in a list, the query without property path works fine.
Is it in general possible to use a value that is connected via datatype property within a SPARQL query as path length for property paths?
This syntax: rdf:rest{<number>} is not standard SPARQL. So the short answer is, regrettably: no, you can't use variables as integers in SPARQL property paths, for the simple reason that you can't use integers in SPARQL property paths at all.
In an earlier draft of the SPARQL standard, there was a proposal to use this kind of syntax to allow specifying the min and max length of a property path, e.g. rdf:rest{1, 3} would match any paths using rdf:rest properties between length 1 and 3. But this was never fully standardized and most SPARQL engines don't implement it.
If you happen to use a SPARQL engine that does implement it, you will have to get in touch with the developers directly to ask if they can extend the mechanism to allow use of variables in this position (the error message suggests to me that it's currently just not possible).
As an aside: there's a SPARQL 1.2 community initiative going on. It only just got started but one of the proposals on the table is re-introducing this particular piece of functionality to the standard.

What is the benefit of defining datatypes for literals in an RDF graph?

I am using rdflib in Python to build my first rdf graph. However, I do not understand the explicit purpose of defining Literal datatypes. I have scraped over the documentation and did my due diligence with google and the stackoverflow search, but I cannot seem to find an actual explanation for this. Why not just leave everything as a plain old Literal?
From what I have experimented with, is this so that you can search for explicit terms in your Sparql query with BIND? Does this also help with FILTERing? i.e. FILTER (?var1 > ?var2), where var1 and var2 should represent integers/floats/etc? Does it help with querying speed? Or am I just way off altogether?
Specifically, why add the following triple to mygraph
mygraph.add((amazingrdf, ns['hasValue'], Literal('42.0', datatype=XSD.float)))
instead of just this?
mygraph.add((amazingrdf, ns['hasValue'], Literal("42.0")))
I suspect that there must be some purpose I am overlooking. I appreciate your help and explanations - I want to learn this right the first time! Thanks!
Comparing two xsd:integer values in SPARQL:
ASK { FILTER (9 < 15) }
Result: true. Now with xsd:string:
ASK { FILTER ("9" < "15") }
Result: false, because when sorting strings, 9 comes after 1.
Some equality checks with xsd:decimal:
ASK { FILTER (+1.000 = 01.0) }
Result is true, it’s the same number. Now with xsd:string:
ASK { FILTER ("+1.000" = "01.0") }
False, because they are clearly different strings.
Doing some maths with xsd:integer:
SELECT (1+1 AS ?result) {}
It returns 2 (as an xsd:integer). Now for strings:
SELECT ("1"+"1" AS ?result) {}
It returns "11" as an xsd:string, because adding strings is interpreted as string concatenation (at least in Jena where I tried this; in other SPARQL engines, adding two strings might be an error, returning nothing).
As you can see, using the right datatype is important to communicate your intent to code that works with the data. The SPARQL examples make this very clear, but when working directly with an RDF API, the same kind of issues crop up around object identity, ordering, and so on.
As shown in the examples above, SPARQL offers convenient syntax for xsd:string, xsd:integer and xsd:decimal (and, not shown, for xsd:boolean and for language-tagged strings). That elevates those datatypes above the rest.

Sparql query with Blank node can be complex

I read this blog article, Problems of the RDF model: Blank Nodes, and there's mentioned that using blank nodes can complicate the handling of data.
Can you give me an example why using blank nodes is difficult to perform a SPARQL query?
I do not understand the complexity of blank nodes.
Can you explain me the meaning and semantics of an existential variable?
I do not understand clearly this explanation given in the RDF Semantics Recommendation, 1.5. Blank Nodes as Existential Variables.
Existential Variables
In the (first-order) predicate calculus, there is existential quantification which lets us make assertions about things that exist, without saying (or, possibly, knowing) which specific individuals in the domain we're actually talking about. For instance, a sentence like
hasUserId(JoshuaTaylor,1281433)
entails the sentence
∃x.hasUserId(x,1281433)
Of course, there are lots of scenarios in which the second sentence could be true without the first one being true. In that sense, the second sentence gives us less information than the first. It's also important to note that the variable x in the second sentence doesn't provide any way to find out which element in the domain of discourse actually has the given userId. It also also doesn't make any claim that there's only one such thing that has the given user id. To make that clearer, we might use an example:
∃y.hasAge(y,29)
This is presumably true, since someone or something out there is age 29. Note that we can't talk about y as the individual that is age 29, though, because there could be lots of them. All this sentence tells us is that there is at least one.
Even though we used different variables in the two sentences, there's nothing to say that the individuals with the specified properties might not be the same. This is particularly important in nested quantification, e.g.,
∃x.∃y.likes(x, y)
This sentence could be true because there is one individual in the domain that likes itself. just because x and y have different names in the sentence doesn't mean that they might not refer to the same individual.
Blank Nodes as Existential Variables
There is a defined RDF entailment model defined in RDF Semantics. This has been described more in another Stack Overflow question, RDF Graph Entailment. The idea is that an RDF graph is treated a big existential quantification over the blank nodes mentioned in the graph. E.g., if the triples in the graph are t1, …, tn, and the blank nodes that appear in those triples are b1, …, bm, then the graph is a formula:
∃b1, …, bm.(t1 &wedge; … &wedge; tn)
Based on the discussion of the existential variables above, note that this means that blank nodes in the data might refer to same element of the domain, or different elements, and that it's not required that exactly one element could take the place of a blank node. This means that a graph with blank nodes, when interpreted in this manner, provides much less information than you might expect.
Blank Nodes in Real Data
Now, the discussion above is useful if people are using blank nodes as existential variables. In many cases, authors think of them more as anonymous, but definite and distinct objects. E.g., if we casually write
#prefix : <https://stackoverflow.com/q/20629437/1281433/> .
:Carol :hasAddress [ :hasNumber 4222 ;
:hasStreet :Clinton_Way ] .
we may well be trying to say that there is a single address out there with the specified properties, but according to the RDF entailment model, that's not what we're doing.
In practice, this isn't so much of a problem, because we're usually not using RDF entailment. What is a problem though is that since the scope of blank variables is local to a graph, we can't run a SPARQL query against an endpoint asking for Carol's address and get back an IRI that we can reuse. If we run a query like this:
prefix : <https://stackoverflow.com/q/20629437/1281433/>
construct {
:Mike :hasAddress ?address
}
where {
:Carol :hasAddress ?address
}
then we get back the following (unhelpful) graph as a result:
#prefix : <https://stackoverflow.com/q/20629437/1281433/> .
:Mike :hasAddress [] .
We won't have a way to get more information about the address because all we have now is a blank node. If we had used IRIs, e.g.,
#prefix : <https://stackoverflow.com/q/20629437/1281433/> .
:Carol :hasAddress :address1267389 .
:address1267389 :hasNumber 4222 ;
:hasStreet :Clinton_Way .
then the query would have produced something more helpful:
#prefix : <https://stackoverflow.com/q/20629437/1281433/> .
:Mike :hasAddress :address1267389 .
Why is this more useful? The first case is like having the data
∃ x.(hasAddress(Carol,x) &wedge; hasNumber(x,4222) &wedge; hasStreet(x,ClintonWay))
and getting back a result
∃ y.hasAddress(Mike,y)
Sure, it's possible that Mike and Carol have the same address, but from these sentences there's no way to know for sure. It's much more helpful to have data like
hasAddress(Carol,address1267389)
hasNumber(address1267389,4222)
hasStreet(address1267389,ClintonWay))
and getting back a result
hasAddress(Mike,address1267389)
From this, you know that they have the same address, and you can ask things about it.
Conclusion
How much this will affect your data and its consumers depends on what the typical use cases are. For automatically constructed graphs, it may be hard to know in advance just what kind of data you'll need to be able to refer to later, so it's a good idea to generate IRIs for as many of your resources as you can. Since IRIs are free-form, it's usually not too hard to do this. For instance, if you've got some sensible “base” IRI, e.g.,
http://example.org/myData/
then you can easily append suffixes to identify your resources. E.g.,
http://example.org/myData/addresses/addr1
http://example.org/myData/addresses/addr2
http://example.org/myData/addresses/addr3
http://example.org/myData/individuals/ind34
http://example.org/myData/individuals/ind35

Selecting strings with LIKE operator in SPARQL

In ANSI SQL, you can write something like:
SELECT * FROM DBTable WHERE Description LIKE 'MEET'
or also:
SELECT * FROM DBTable WHERE Description LIKE '%MEET%'
What I would like help with is writing the SPARQL equivalent of the above please.
Use a regex filter. You can find a short tutorial here
Here's what it looks like:
PREFIX ns: <http://example.com/namespace>
SELECT ?x
WHERE
{ ?x ns:SomePredicate ?y .
FILTER regex(?y, "YOUR_REGEX", "i") }
YOUR_REGEX must be an expression of the XQuery regular expression language
i is an optional flag. It means that the match is case insensitive.
If you have a fixed string to match you can use that directly in your graph pattern e.g.
PREFIX ns: <http://example.com/namespace>
SELECT ?x
WHERE
{ ?x ns:SomePredicate "YourString" }
Note this does not always work because pattern matching is based on RDF term equality which means "YourString" is not considered the same term as say "YourString"#en so if that may be an issue use the REGEX approach Tom suggests
Also some SPARQL engines provide a full text search extension which allows you to integrate Lucene style queries into your SPARQL queries which may better fit your use case and almost certainly be more efficient for the generic search which would otherwise require a REGEX