How to construct long queries using rdf4j - sparql

I am trying to construct a long query using the rdf4j library and would like to use the count function that is available with SPARQL.
The original SPARQL query looks like this:
SELECT (COUNT(?letter) AS ?count) WHERE { \
?letter a :Letter . \
?letter :writtenBy :John . \
?letter :writtenOn ?date . \
FILTER(?date > NOW() && }
This is what I have so far using the rdf4j library
GraphPattern longPattern = GraphPatterns.tp(letter, ex.iri("a"), ex.iri("Letter")).
and(GraphPatterns.tp(letter, ex.iri("writtenBy"), ex.iri("John"))).
and(GraphPatterns.tp(letter, ex.iri("writtenOn"), date));
How can I implement the Count and use the NOW() functionality of sparql? I know there is a filter method but I don't know how to use the NOW() with it. All of the variables (letter, date) and a select query have been initialised within java using SparqlBuilder.

In the RDF4J SparqlBuilder, functions are created using org.eclipse.rdf4j.sparqlbuilder.constraint.Expressions static methods. For example, to create the BNode() function, you just do this:
Expression bnodeFunc = Expressions.bnode();
Similarly, for the COUNT aggregate function:
Expression countAgg = Expressions.count(letter);
and to use that in your SELECT clause, you'd do something like this:
Variable count = SparqlBuilder.var("count");
Projection select = SparqlBuilder.select(countAgg.as(count));
As for the now() function: Annoyingly, the list of function factory methods in Expressions is incomplete: for now() there is no direct static factory method. However, you can use the general Expressions.function method to create it, as follows:
Expression nowFunc = Expressions.function(SparqlFunction.NOW);
By the way, your current graph pattern can be simplified quite a bit. Instead of this:
GraphPattern longPattern = GraphPatterns.tp(letter, default.iri("a"), default.iri("Letter")).
and(GraphPatterns.tp(letter, default.iri("writtenBy"), legislate.iri("John"))).
and(GraphPatterns.tp(letter, legislate.iri("writtenOn"), date));
Do this:
TriplePattern longPattern = letter.isA(ex.iri("Letter"))
.andHas(ex.iri("writtenBy"), legislate.iri("John"))
.andHas(legislate.iri("writtenOn"), date);
This is easier to read and shorter, and secondly, your use of default.iri("a") was incorrect (as an aside I don't even know how you have a Java variable called default because that's a reserved keyword and should result in a compilation error - so I've replaced with ex here).
Putting it all together you'd get something like this:
SelectQuery select = Queries.SELECT()
.prefix(ex)
.prefix(legislate)
.select(countAgg.as(count))
.where(GraphPatterns.and(longPattern)
.filter(Expressions.gt(date, nowFunc)));

Related

SPARQL: filter on both string and integer?

I'm testing SPARQL with Protégé on this data file
https://raw.githubusercontent.com/miranda-zhang/cloud-computing-schema/master/example/sparql-generate/result/gcloud_vm.ttl
Validated the following works:
PREFIX cocoon: <https://raw.githubusercontent.com/miranda-zhang/cloud-computing-schema/master/ontology_dev/cocoon.ttl>
SELECT ?VM ?cores
WHERE {
?VM a cocoon:VM ;
cocoon:numberOfCores ?cores .
}
For example, it returns something like:
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-ULTRAMEM-80-PREEMPTIBLE "80"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-HIGHCPU-64-PREEMPTIBLE "64"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-STANDARD-2 "2"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-F1-MICRO "shared"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-HIGHCPU-8-PREEMPTIBLE "8"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-HIGHCPU-32 "32"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-HIGHMEM-16-PREEMPTIBLE "16"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-STANDARD-96-PREEMPTIBLE "96"#
https://w3id.org/cocoon/data/vm/gcloud/CP-COMPUTEENGINE-VMIMAGE-N1-STANDARD-4 "4"#
I'm not sure if I can apply a filter on ?cores, I tried the following, but they returned nothing:
cocoon:numberOfCores "shared" .
Or
FILTER(?cores = "4") .
I'd also like to apply filter on ?cores (i.e. > 4 and < 8), so I have to make it an xsd:integer? But then I have to get rid of shared which is about < 1 core
Thanks AKSW, impressive knowledge about Protégé.
In the end, I changed my data type to xsd:decimal. Seems to be enough for now.

How to compare the month parts of two dates?

I am trying to query query the current month, here is my query:
$clients = $this->Clients;
$query = $clients->find();
if($this->Auth->user('role') !== 'admin'){
$query->where(['user_id =' => $this->Auth->user('id')]);
$query->where(['MONTH(dob) = ' => 'EXTRACT(month FROM (NOW()))']);
$query->order(['dob' => 'ASC']);
}
It returns 0 records (my field is a date type), however this query in phpmyadmin works:
SELECT * FROM `clients` WHERE MONTH(dob) = EXTRACT(month FROM (NOW()))
What am I doing wrong?
Just look at the actual generated query (check out your DBMS query log, or try DebugKit), it will look different, as the right hand side value in a key => value condition set is subject to parameter-binding/casting/quoting/escaping. In your case it will be treated as a string, so the condition will finally look something like:
WHERE MONTH(dob) = 'EXTRACT(month FROM (NOW()))'
That will of course not match anything.
You could pass the whole SQL snippet as a single array value, or as an expression object, that way it would be inserted into the query as is (do not insert user values that way, that would create an SQL injection vulnerability!), but I'd suggest to use portable function expressions instead.
CakePHP ships with functions expressions for EXTRACT and NOW, so you can simply do something like:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$query->where(function (QueryExpression $exp, Query $query) {
return $exp->eq(
$query->func()->extract('MONTH', new IdentifierExpression('dob')),
$query->func()->extract('MONTH', $query->func()->now())
);
});
Looks a bit complicated, but it's worth it, it's cross DBMS portable as well as auto-quoting compatible. The generated SQL will look something like
WHERE EXTRACT(MONTH FROM (dob)) = (EXTRACT(MONTH FROM (NOW())))
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
Cookbook > Database Access & ORM > Query Builder > Using SQL Functions
API > \Cake\Database\Expression\QueryExpression::eq()
API > \Cake\Database\FunctionsBuilder::extract()
API > \Cake\Database\FunctionsBuilder::now()

IPython SQL Magic - Generate Query String Programmatically

I'm generating SQL programmatically so that, based on certain parameters, the query that needs to be executed could be different (i.e., tables used, unions, etc). How can I insert a string like this: "select * from table", into a %%sql block? I know that using :variable inserts variable into the %%sql block, but it does so as a string, rather than sql code.
The answer was staring me in the face:
query="""
select
*
from
sometable
"""
%sql $query
If you want to templatize your queries, you can use string.Template:
from string import Template
template = Template("""
SELECT *
FROM my_data
LIMIT $limit
""")
limit_one = template.substitute(limit=1)
limit_two = template.substitute(limit=2)
%sql $limit_one
Source: JupySQL documentation.
Important: If you use this approach, ensure you trust/sanitize the input!

How to customize ORDER BY condition in SPARQL

I want to order the output of the SPARQL queries not alphabetically, but in a certain order that I define myself. I cannot find information on how to do it.
For example, I have a query:
SELECT DISTINCT ?a ?b ?c
WHERE { ... }
ORDER BY ?c
The variable c can have a limited range of values: "s", "m", "m1", "m2", "p" and "w".
I want the ordering to be as follows:
1) s
2) m
3) m1
4) m2
4) p
5) w
So, it is not an alphabetical order.
How to force the ORDER BY to order output in this order?
I use SPARQL endpoint Fuseki to query a turtle file, and jinja2 templates to render the results.
In general, you'd need to write a custom function, as described in Jeen's answer. However, when you have a limited number of values, and you know the specific ordering, you can simply include a values block that associates each value with its sort index and then sort on that. E.g., if you wanted to sort some sizes, you could do something like this:
select ?item where {
values (?size ?size_) { ("small" 1) ("medium" 2) ("large" 3) }
?item :hasSize ?size
}
order by ?size_
You can achieve any custom sorting order by writing a custom function that implements the sorting logic and injecting that function into your SPARQL engine. See this tutorial on how to create a custom function for the Sesame SPARQL engine - other SPARQL engines have similar functionality.
Once you have this function, you can use it in the ORDER BY argument:
SELECT ....
ORDER BY ex:customFunction(?c)

GORM / HQL - LISTAGG

in GORM (using grails) i need to combine in subselect multiple results into one value. (result of this subselect will be concatenated value on which i can make search / sort etc. ...)
Query is writen as HQL. Something like this in oracle
http://www.techonthenet.com/oracle/functions/listagg.php
Can be something like that achieved in HQL (e.g. GORM) ?
...
AND (
SELECT LISTAG(e.title) AS con FROM Entity e
WHERE Entity.searchKey = TRUE
AND e.parrent = par
AND LOWER(e.title) LIKE :search
) > 0
...
ORDER BY con ASC
thansk
Hibernate, and the HQL/GORM layers that sit on top of Hibernate, do not directly support database-specific functions like Oracle's LISTAGG(). There are, however, a few ways to use native SQL within Grails. If you would like to add your concatenated value to one of your domain objects, you can use GORM's derived property feature (http://grails.org/doc/latest/guide/GORM.html#derivedProperties).
Something along these lines:
class MyDomain {
Long parentId
String titleAgg
static mapping = {
titleAgg formula: '(SELECT LISTAGG(e.title) FROM Entity e WHERE e.parrent = parent_id)'
}
}
A second option would be to use the Grails-defined dataSource bean along with groovy.sql.Sql to execute native SQL statements. See here for an example.