How to print the retrieved statements in SPARQL after executing a query - java

I am quite new to Java Sesame and SPARQL. I have added statements into the Sesame repository and am now trying to retrieve some statements and simply print them. From what I understood that I need to parse the query in order to print the retrieved statements. The code below shows where I have reached so far:
String queryString = "SELECT ?subject ?object WHERE { ?subject <http://example.org/is> ?object . } LIMIT 1";
...
SPARQLParser parser = new SPARQLParser();
ParsedQuery query = parser.parseQuery(queryString, null);
StatementPatternCollector collector = new StatementPatternCollector();
query.getTupleExpr().visit(collector);
List<StatementPattern> patterns = collector.getStatementPatterns();
// To print the first statement only for example.
System.out.println(patterns.get(0));
Here is the output:
StatementPattern
Var (name=name)
Var (name=-const-1, value=http://example.org/is, anonymous)
Var (name=object)
According to the output, it does not show me the subject and object. My questions are: How can I print the results of the query as shown above. Is this code the right way to parse the query for printing the statements later. Your help would be very much appreciated.

You get the results of a query by evaluating the query, not by parsing it. What your code does is inspect the query's algebra model and retrieve patterns from that algebra. This approach will not give you query results.
Evaluating a query in Sesame is far simpler than this:
// open a connection to the Sesame repository containing your statements
RepositoryConnection conn = repository.getConnection();
try {
// create a prepared query object from your query string
TupleQuery query = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
// evaluate the query on the repository
TupleQueryResult result = query.evaluate();
// iterate over the results and do something with each result
while (result.hasNext()) {
BindingSet s = result.next();
Value subject = s.getValue("subject");
Value object = s.getValue("object");
System.out.println("value of ?subject: " + subject);
System.out.println("value of ?object: " + object);
}
} finally {
conn.close();
}
As Joshua pointed out, your query retrieves variable bindings (for the variables mentioned in your SELECT clause), not RDF statements. You can of course re-create the RDF statement from those variable bindings in Java, but if you really want full statements rather than just the subject and object, it's probably easier to switch to using a SPARQL CONSTRUCT query instead of a SELECT query.
For more information on how to evaluate different kinds of queries and work with the results in Sesame, see the Sesame user documentation (section 6.5 in particular) and the API Javadoc.

Related

sparql using live.dbpedia and getting XML Schema in the result

I'm adventuring with sparql and a java application, I've found a few connection basics to get up and running as it were but fear I'm making a mistake which will later turn into something worse.
Every connection suggestion regardless of the library used says to connect to "http://dbpedia.org/sparql/" yet this doesn't work for me.
I checked the url that is returned when I run a query using the online editor and noticed the live prefix, so I added that as my connection string, and it works. That is to say, my connection string looks like "http://live.dbpedia.org/sparql"
And it does return the result, however, the result has the XML Schema attached which is making me wonder whether or not it's because of this live. I've added in.
Below is the simple connection code I'm using, is this correct? Any and all help greatly appreciated thank you.
If the 'live' is correct, is it possible to extra the just the value wihtout the Schema?
StringBuilder sb = new StringBuilder();
sb.append("PREFIX dbr: <http://dbpedia.org/resource/> \n");
sb.append("PREFIX dbp: <http://dbpedia.org/property/> \n");
sb.append("PREFIX dbo: <http://dbpedia.org/ontology/> \n");
sb.append("SELECT ?dob \n");
sb.append("WHERE {dbr:Tony_Blair dbp:birthDate ?dob} \n");
Query query = QueryFactory.create(sb.toString());
QueryExecution qexec = QueryExecutionFactory.sparqlService("http://live.dbpedia.org/sparql", query);
try {
ResultSet results = qexec.execSelect();
for ( ; results.hasNext() ; )
{
QuerySolution soln = results.nextSolution() ;
System.out.println(soln.get("?dob"));
}
the result being:
1953-05-06^^http://www.w3.org/2001/XMLSchema#date
Well the result as you show it is missing some brackets and quotes, but I assume that is caused by how you copy-pasted it. More usually it would look like this:
"1953-05-06"^^<http://www.w3.org/2001/XMLSchema#date>
But in essence your query and code is correct. The "attached XML Schema" here is the datatype of the returned literal string.
An RDF literal consists of a lexical value (in your case "1953-05-06") and a datatype (in your case http://www.w3.org/2001/XMLSchema#date). It can also, optionally have a language tag e.g. "colour"#en-UK.
If you wish to remove the datatype from the result and only retrieve the lexical value, you can use the STR() function as part of the SELECT clause in your query:
SELECT (STR(?dob) as ?date_of_birth)
As for the connection string that you are struggling with: there are two separate DBPedia endpoints. The "regular" one is http://dbpedia.org/sparql (no trailing slash) - this queries a static dataset that is synced/updated with Wikipedia changes every so 6 months or so. The "live" endpoint, http://live.dbpedia.org/sparql, is an effort to have a more up-to-date dataset ready for querying. See https://wiki.dbpedia.org/online-access/DBpediaLive for more details.

writing a basic n1ql query in java

I have just started learning Couchbase. I am trying to write a basic query using java sdk but I am not able to understand how to write it. Below is the query:
SELECT *
FROM users_with_orders usr
JOIN orders_with_users orders
ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END
This is for joining without array:
LetPath path = select("*,META(usr).id as _ID,META(usr).cas as _CAS).from(bucketName +" usr").join(bucketname +" orders").onKeys("usr.order_id)
How should I proceed with the above query for on keys array?
Thanks!!!!
As described in the docs on Querying from the SDK, you can use either a simple string with the Java SDK or use the DSL. For example:
// query with a simple string
System.out.println("Simple string query:");
N1qlQuery airlineQuery = N1qlQuery.simple("SELECT `travel-sample`.* FROM `travel-sample` WHERE name=\"United Airlines\" AND type=\"airline\"");
N1qlQueryResult queryResult = bucket.query(airlineQuery);
for (N1qlQueryRow result: queryResult) {
System.out.println(result.value());
}
//query with a parameter using the DSL
System.out.println("Parameterized query using the DSL:");
Statement statement = select(path(i("travel-sample"), "*")).from(i("travel-sample")).where(x("name").eq(x("$airline_param")).and(x("type").eq(s("airline"))));
JsonObject placeholderValues = JsonObject.create().put("airline_param", "United Airlines");
N1qlQuery airlineQueryParameterized = N1qlQuery.parameterized(statement, placeholderValues);
N1qlQueryResult queryResultParameterized = bucket.query(airlineQueryParameterized);
for (N1qlQueryRow row : queryResultParameterized) {
System.out.println(row);
}
(I posted a full gist of this example for the imports, etc.)
See the docs for more info, but you may want to use the DSL to allow IDE code completion and Java compile time checking. When developing an interactive web application, you'll probably also want to use parameterized statements (for security) and may even want prepared statements (for performance).

when is criteria better than HQL or nativeSQL Query?

In my Case after getting a certain list I need to to iterate that list to set some other fields of the POJO class.
if (transportHeaderList.get(i) instanceof TransportHeaderIiss){
transHeadIiss=(TransportHeaderIiss)transportHeaderList.get(i);
customerVendor= tOManagementDAO.getVendorCode(transHeadIiss.getCustVendUid());
}
if(customerVendor!=null){
transHeadIiss.setVendorCode(customerVendor.getCustVendCode());
}
The Above code calls getVendorCode method to get custVendorCode value from the database. The code for getVendorCode is as follows
public CustomerVendorIiss getVendorCode(Long custVendUid) {
List list=new ArrayList();
/* Criteria criteria = sessionFactory.getCurrentSession().createCriteria(CustomerVendorIiss.class);
criteria.add(Restrictions.eq("companyCode",user.getDefaultCompany().getCompanyCode()));
if(custVendUid!=null && custVendUid.intValue()>0)
{
criteria.add(Restrictions.eq("custVendUid",custVendUid));
}
list=criteria.list();*/
UsersIiss user= ApplicationContextProvider.getLoggedInUser();
String sqlQuery="select custVendCode as custVendCode from CustomerVendorIiss where companyCode ='"+ user.getDefaultCompany().getCompanyCode() +"' and custVendUid= "+custVendUid;
Query query = sessionFactory.getCurrentSession().createQuery(sqlQuery);
query.setResultTransformer(Transformers.aliasToBean(CustomerVendorIiss.class));
list=query.list();
if(list.size()>0){
return (CustomerVendorIiss)list.get(0);
}else{
return null;
}
}
When I executed above code with criteria, it took a lot time to get the values from table and set it to POJO class and sometimes I would get java.lang.OutOfMemoryError: Java heap space error . I guess that's because I am not de-allocating the criteria object.
when I executed the above code using createQuery() method I did not run into that issue and all that process of getting and setting was faster.
I want to understand what is that I am doing wrong here?
it would be great to know how and when criteria is better or HQL is better ?
Thank you !!
Actually these queries are different. The second one has an additional restriction
companyCode ='"+ user.getDefaultCompany().getCompanyCode() +"'
So try to add the same to the criteria
criteria.add(Restrictions.eq("companyCode",user.getDefaultCompany().getCompanyCode()));
Also it's not god to concate strings this way to get the query. SQL injection is possible. Use parameters instead.
Criteria and HQL is better than SQL in one case - you need DB independent logic to swap DB when necessary without rewriting code.

java looping through multiple sql queries

I'm trying to loop through multiple sql queries that are executed. I want to first get all the question information for a certain task and then get the keywords for that question. I have three records in my Questions table, but when the while loop at the end of list.add(keyword); is done, it jumps to the SELECT Questions.Question loop (as it should) and then just jumps out and gives me only one record and not the other 2.
What am I doing wrong? Can someone maybe help me fix my code? I've thought of doing batch sql executes (maybe that is the solution), but within each while loop, I need information from the previous sql statement, so I can't just do it all at the end of the batch.
SQL Code:
String TaskTopic = eElement.getElementsByTagName("TaskTopic").item(0).getTextContent();
// perform query on database and retrieve results
String sql = "SELECT Tasks.TaskNo FROM Tasks WHERE Tasks.TaskTopic = '" + TaskTopic + "';";
System.out.println(" Performing query, sql = " + sql);
result = stmt.executeQuery(sql);
Document doc2 = x.createDoc();
Element feedback = doc2.createElement("Results");
while (result.next())
{
String TaskNo = result.getString("TaskNo");
// perform query on database and retrieve results
String sqlquery = "SELECT Questions.Question, Questions.Answer, Questions.AverageRating, Questions.AverageRating\n" +
"FROM Questions\n" +
"INNER JOIN TaskQuestions ON TaskQuestions.QuestionID = Questions.QuestionID \n" +
"INNER JOIN Tasks ON Tasks.TaskNo = '" + TaskNo + "';";
result = stmt.executeQuery(sqlquery);
while (result.next())
{
String Question = result.getString("Question");
String Answer = result.getString("Answer");
String AverageRating = result.getString("AverageRating");
String sqlID = "SELECT QuestionID FROM Questions WHERE Question = '" + Question + "';";
result = stmt.executeQuery(sqlID);
while (result.next())
{
String ID = result.getString("QuestionID");
String sqlKeywords = "SELECT Keyword FROM LinkedTo WHERE QuestionID = '" + ID + "';";
result = stmt.executeQuery(sqlKeywords);
while (result.next())
{
String keyword = result.getString("Keyword");
list.add(keyword);
}
}
feedback.appendChild(x.CreateQuestionKeyword(doc2, Question, Answer, AverageRating, list));
}
}
Why this should be done in SQL
Creating loops is exponentially less efficient than writing a sql query. Sql is built to pull back this type of data and can plan out how it is going to get this data from the database (called an execution plan).
Allowing Sql to do its job and determine the best way to pull back the data instead of explicitly determining what tables you are going to use first and then calling them one at a time is better in terms of the amount of resources you will use, how much time it will take to get the results, code readability, and maintainability in the future.
What information you are looking for
In the psuedocode you provided, you are using the Keyword, Question, Answer, and AnswerRating values. Finding these values should be the focus of the sql query. Based on the code you have written, Question, Answer, and AnswerRating are coming from the Questions table and Keyword is coming from the LinkedTo table, so both of these tables should be available to have data pulled from them.
You can note at this point that we have essentially just mapped out what the Select and From portions of your query should look like.
It also looks like you have a parameter called TaskTopic so we need to include the table Tasks to make sure the correct data is returned. Lastly, the TaskQuestions table is the link between the tasks and the questions. Now that we know what the query should look like, let's see what the results are using sql syntax.
The Code
You did not include the declaration of stmt, but I assume that it is a PreparedStatement. You can add parameters to a prepared statement. Notice the ? in the sql code? The parameters you provide will be added in place of the ?. To do this, you should use stmt.setString(1, TaskTopic);. Note that if there were more than one parameter, you would need to add them in the order that they exists in the sql query (using 1, 2, ...)
SELECT l.Keyword,
q.Question,
q.Answer,
q.AverageRating
FROM LinkedTo l Inner Join
Questions q
on l.questionID = q.QuestionID
Where exists ( Select 1
From TaskQuestions tq INNER JOIN
Tasks t
on tq.TaskNo = t.TaskNo
Where t.TaskTopic = ?
and tq.QuestionID = q.QuestionID)
This is one way that you can write the query to return the same results. There are other ways to write this to get what you are looking for.
What's Going On?
There are a few things in this query you may not be familiar with. First are table aliases. Instead of writing the table name over and over again, you can alias your tables. I used the letter q to represent the Questions table. Any time you see q. you should recognize that I am referring to a column from Questions. The q after Questions is what gives the table its alias.
Exists Instead of doing a bunch of inner joins with tables that you are not selecting information from, you can use an exists to check if what you are looking for is in those tables. You can continue to do inner joins if you need data from the tables, but if you don't, Exists is more efficient.
I suspect you had issues with the query before (and probably the one you provided) because you did not provide any information to join TaskQuestions and Tasks together. That most likely resulted in the duplicates. I joined on TaskNo but this may not be the correct column depending on how the tables are set up.

Parameterized SPARQL query with JENA

I'm trying to build a small semantic web application using Jena framework, JSP and JAVA. I have a remote SPARQL endpoint and I've already written a simple query which works fine but now I need to use some parameters. Here is my code so far:
final static String serviceEndpoint = "http://fishdelish.cs.man.ac.uk/sparql/";
String comNameQuery =
"PREFIX fd: <http://fishdelish.cs.man.ac.uk/rdf/vocab/resource/> " +
"SELECT ?name ?language ?type" +
"WHERE { ?nameID fd:comnames_ComName ?name ;" +
"fd:comnames_Language ?language ;" +
"fd:comnames_NameType ?type ." +
"}";
Query query = QueryFactory.create(comNameQuery);
QueryExecution qe = QueryExecutionFactory.sparqlService(serviceEndpoint,query);
try {
ResultSet rs = qe.execSelect();
if ( rs.hasNext() ) {
System.out.println(ResultSetFormatter.asText(rs));
}
}
catch(Exception e) {
System.out.println(e.getMessage());
}
finally {
qe.close();
}
What I want to do is to parameterized ?name. I'm new to Jena and I'm not really sure how to use parameters in a SPARQL query. I would appreciate it if someone could help me with this.
If you just want to restrict a variable to have a certain value for local queries you can do so with an overload of the QueryFactory.create() method which takes a QuerySolutionMap to set value restrictions. Note this doesn't alter your query just restricts the final results so this is not really parameterization.
If you want to actually have true parameterized queries (i.e. substitute variables for constants) then there are a couple of ways to do this depending on your version of ARQ.
Using any current release (up to 2.9.0) the only way to do it is string concatenation i.e. instead of having ?name in your query you would just insert the value you want e.g. "Bob"
Using the latest trunk (2.9.1-SNAPSHOT onwards) there is a new ParameterizedSparqlString class which makes this much more user friendly e.g.
ParameterizedSparqlString queryStr = new ParameterizedSparqlString(comNameQuery);
queryStr.setLiteral("name", "Bob");
Query query = QueryFactory.create(queryStr.toString());
And in fact you can simplify your code further since ParameterizedSparqlString has a StringBuffer style interface and can be used to build your query bit by bit and includes useful functionality like prepending prefixes to your query.
The advantage of this new method is that it provides a more generic way of doing parameterized queries that can also be used with updates and is usable for preparing remote queries which the existing methods do not cover.
You could try looking into Twinkql. It is a SPARQL-to-Java mapping framework. It uses Jena in the back end, but tries to simplify SPARQL queries and Java binding of the results.
It allows you to define SPARQL queries in xml:
<select id="getNovel" resultMap="novelResultMap">
<![CDATA[
SELECT ?novel ?author
WHERE {
?novel a <http://dbpedia.org/class/yago/EnglishNovels> ;
<http://dbpedia.org/property/name> "#{novelName}"#en ;
<http://dbpedia.org/property/author> ?author .
}
]]>
</select>
Note the #{novelName} placeholder -- this is where parameters can be passed in at query time.
Also, results can be bound to Java Beans:
<resultMap id="novelResultMap" resultClass="org.twinkql.example.Novel">
<uniqueResult>novel</uniqueResult>
<rowMap var="novel" varType="localName" beanProperty="name" />
<rowMap var="author" varType="localName" beanProperty="author"/>
</resultMap>
There is an API to call these queries, to pass in parameters, etc. It is much like MyBatis, but for SPARQL instead of SQL.

Categories