Selecting strings with LIKE operator in SPARQL - sql

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

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.

sparql-query and sparql-update both are not the same?

I find that these are two different query languages:
SPARQL-QUERY and SPARQL-UPDATE.
What other types I could see in SPRARQL?
And I am looking for a syntax where I can replace a particular element property with a new value.
But, using insert query, I can only see that the new value is being added as additional value of the property instead of replacing the whole values of the property.
So, is there any other language for this purpose, like sparql-update something?
Also, I can see that delete option is there. But I don't want to specify a particular value, but to delete the whole pattern. Of course, we can specify the pattern I guess. But I just wonder, if there is a specific language for this purpose.
EDIT:
And in the following query, I don't find the purpose of using where clause at all. It always inserts specified value as a new value, but is not replacing it. We need to use the delete clause specifically. Then what's the purpose of where clause here?
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX indexing: <http://fedora.info/definitions/v4/indexing#>
PREFIX custom: <http://namespaces.info/custom#>
DELETE {
}
INSERT {
<> indexing:hasIndexingTransformation "default";
rdf:type indexing:Indexable;
dc:title "title3";
custom:ownerId "owner6";
dc:identifier "test:10";
}
WHERE {
<>
custom:ownerId "owner1";
}
The SPARQL recommendation is separated into separate documents, see SPARQL 1.1 Overview from W3C.
The WHERE clause can be empty, but also look into INSERT DATA, which takes a set of triple specifications (not patterns - no variables) and inserts them. No WHERE clause id needed int that case. Same for deleting triple specifications with DELETE DATA.

Avoiding count explosion in querying with SPARQL ontologies containing owl:sameAs triples

I am trying to build a (local) ontology that describes a finite number of objects, and that links these objects to external resources via the owl:sameAs predicate. However, when I simply query for the number of objects of that kind, I obtain twice as much as the object described. It is clear that also the external resources are counted independently, as what is taken into account is the number of URIs, and not the number of distinct objects.
I have solved this issue in the following way: I assume that the local ontology can be seen as a "reference hub" for knowing basic stuff about these objects, so I select all the objects of a certain kind, and then filter out only those that contain the base URI of the local ontology, i.e.:
# How many objects are there?
PREFIX ch: <http://www.example.com/ontologies/domain#>
SELECT (COUNT(DISTINCT ?elem) AS ?count) WHERE {
?elem a ch:Element.
FILTER (REGEX (STR(?elem) ,"http://www.example.com/ontologies/domain") ).
}
However, I have two concerns with this way of doing:
1) it looks a bit of a hack (even if somehow principled), whilst I would like something that makes more logical sense
2) I have the impression that this query is not very efficient.
I have searched quite a bit here, and on google, but didn't come out with any better solution... any suggestions here?
Thank you very much for any help!
GROUP BY a representative element
If there's some property that should have distinct values for each individual, then you can use it to impose the "equivalent class" structure that you need. E.g., something like this:
prefix ch: <http://www.example.com/ontologies/domain#>
select (count(?label) as ?count) where {
?elem a ch:element ;
rdfs:label ?label .
}
group by ?label
Synthesize a representative element
if there's not a value that will be shared by all elements in an equivalence class, you can still get a representative element from the set by asking for the minimal element in each equivalence class. We can use the IRIs of the elements to order the elements, and use that to select a unique individual. This does presume that each ?elem and all the things that it is the same as have well defined behavior under the str function (and IRIs do).
prefix ch: <http://www.example.com/ontologies/domain#>
select (count(distinct ?elem) as ?count) where {
?elem a ch:element .
filter not exists {
?elem (owl:sameAs|^owl:sameAs)* ?elem_
filter( str(?elem_) < str(?elem) )
}
}

How do I consistently query dbpedia for programming languages by name?

There seems to be no consistent way to query for programming languages based on name. Examples:
http://dbpedia.org/page/D_(programming_language)
rdfs:label "D (programming language)"#en
dbpprop:name "D programming language"
owl:sameAs freebase:"D (programming language)"
foaf:name "D programming language"
vs.
http://dbpedia.org/page/C++
rdfs:label "C++"#en
dbpprop:name "C++"
owl:samwAs freebase:"C++"
foaf:name "C++"
Since there's no standard convention for whether "programming language", "(programming language)", "programming_language", "(programming_language", or "" is part of a name for a programming language in dbpedia, I have no idea how to consistently search by name.
I'd like to create some sort of SPARQL query that returns http://dbpedia.org/page/D_(programming_language) for "D" and http://dbpedia.org/page/C++ for "C++", but I don't know how do to this.
Unless at least one of the various triples for programming languages uses a consistent naming convention, I'll have to hack it by querying first against name + " (programming_language)", and falling back to name + "(programming language", name + " programming language" when no results are found. But I'd like a much more robust method.
You could of course just match using a basic substring match or a regex, e.g. like this to find a match for "C++":
SELECT DISTINCT ?pl ?label
WHERE {
?pl a dbpedia-owl:ProgrammingLanguage ;
rdfs:label ?label .
FILTER(langMatches(lang(?label), "en"))
FILTER(regex(str(?label), "C\\+\\+"))
}
Of course, the above will be problematic for a programming language name like "D", since you will get back several matches ("D", "Dylan", "MAD", etc.). In those cases, you might want to do some clever postprocessing of the result, for example tokenizing the returned label and seeing if your input string occurs as a standalone word.
Regex matching in SPARQL is notoriously expensive (in terms of evaluation time), but since you combine it with a type constraint to a particular category, the DBPedia endpoint should be able to handle this kind of query just fine.
I'd use
SELECT distinct ?pl ?label
WHERE {
?pl a dbpedia-owl:ProgrammingLanguage ;
rdfs:label ?label.
?label bif:contains "'C++'" .
filter (str (?label) like '%C++%')
filter (lang(?label)="en")
}
?label bif:contains "'C++'" would filter to some degree, more specifically to C++, C, Objective-C etc., because ++ would be treated as a noise and excluded from actual search pattern.
After that you have C and need two pluses, so filter (str (?label) like '%C++%') would check for them faster than regex.
Add filter (lang(?label)="en") or filter (langmatches(lang(?label),"en")) or no lang check at all by taste.