You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2016/05/02 11:50:06 UTC
[29/50] [abbrv] marmotta git commit: - support SPARQL ASK queries in
ostrich
- support SPARQL ASK queries in ostrich
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/4a5e588c
Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/4a5e588c
Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/4a5e588c
Branch: refs/heads/MARMOTTA-584
Commit: 4a5e588cd274794f7b7880cab49ebd88962cb72b
Parents: e764c2b
Author: Sebastian Schaffert <ss...@apache.org>
Authored: Sat Feb 13 15:25:58 2016 +0100
Committer: Sebastian Schaffert <ss...@apache.org>
Committed: Sat Feb 13 15:25:58 2016 +0100
----------------------------------------------------------------------
libraries/ostrich/backend/client/client.cc | 53 ++++++++++++----
.../backend/persistence/leveldb_service.cc | 63 ++++++++++++++------
.../backend/persistence/leveldb_service.h | 4 ++
libraries/ostrich/backend/service/sparql.proto | 4 ++
.../ostrich/backend/sparql/rasqal_adapter.cc | 47 +++++++++++++--
.../ostrich/backend/sparql/rasqal_adapter.h | 6 ++
libraries/ostrich/backend/test/SparqlTest.cc | 20 +++++++
7 files changed, 164 insertions(+), 33 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/client/client.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/client/client.cc b/libraries/ostrich/backend/client/client.cc
index b4a5178..8921938 100644
--- a/libraries/ostrich/backend/client/client.cc
+++ b/libraries/ostrich/backend/client/client.cc
@@ -70,19 +70,13 @@ class ClientReaderIterator : public util::CloseableIterator<T> {
public:
ClientReaderIterator() : finished(true) { }
- ClientReaderIterator(ClientReader<Proto>* r) : reader(r) {
- finished = !reader->Read(&buffer);
+ ClientReaderIterator(ClientReader<Proto>* r) : reader(r), finished(false) {
+ read();
}
const T& next() override {
current_ = T(buffer);
-
- if (!finished) {
- finished = !reader->Read(&buffer);
- if (finished) {
- reader->Finish();
- }
- }
+ read();
return current_;
}
@@ -99,6 +93,16 @@ class ClientReaderIterator : public util::CloseableIterator<T> {
Proto buffer;
T current_;
bool finished;
+
+ void read() {
+ if (!finished) {
+ finished = !reader->Read(&buffer);
+ if (finished) {
+ auto st = reader->Finish();
+ LOG_IF(FATAL, !st.ok()) << "Reading results failed: " << st.error_message();
+ }
+ }
+ }
};
typedef ClientReaderIterator<rdf::Statement, rdf::proto::Statement> StatementReader;
@@ -214,6 +218,25 @@ class MarmottaClient {
}
}
+ void askQuery(const std::string& query, std::ostream &out) {
+ ClientContext context;
+ spq::SparqlRequest request;
+ request.set_query(query);
+
+ google::protobuf::BoolValue result;
+
+ Status status = sparql_->AskQuery(&context, request, &result);
+ if (status.ok()) {
+ if (result.value()) {
+ out << "YES" << std::endl;
+ } else {
+ out << "NO" << std::endl;
+ }
+ } else {
+ LOG(FATAL) << "SPARQL query failed: " << status.error_message();
+ }
+ }
+
void listNamespaces(std::ostream &out) {
ClientContext context;
@@ -238,7 +261,7 @@ class MarmottaClient {
if (status.ok()) {
return result.value();
} else {
- return -1;
+ LOG(FATAL) << "Calculating size failed: " << status.error_message();
}
}
private:
@@ -318,6 +341,16 @@ int main(int argc, char** argv) {
}
}
+ if ("ask" == std::string(argv[1])) {
+ std::string query = argv[2];
+ if (FLAGS_output != "") {
+ std::ofstream out(FLAGS_output);
+ client.askQuery(query, out);
+ } else {
+ client.askQuery(query, std::cout);
+ }
+ }
+
if ("delete" == std::string(argv[1])) {
rdf::proto::Statement query;
TextFormat::ParseFromString(argv[2], &query);
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/persistence/leveldb_service.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/persistence/leveldb_service.cc b/libraries/ostrich/backend/persistence/leveldb_service.cc
index 5ea08a1..f2637bd 100644
--- a/libraries/ostrich/backend/persistence/leveldb_service.cc
+++ b/libraries/ostrich/backend/persistence/leveldb_service.cc
@@ -22,6 +22,7 @@
#include <model/rdf_operators.h>
#include <util/unique.h>
#include <util/time_logger.h>
+#include <glog/logging.h>
using grpc::Status;
using grpc::StatusCode;
@@ -242,18 +243,23 @@ grpc::Status LevelDBSparqlService::TupleQuery(
rdf::URI base_uri = query->base_uri();
- svc.TupleQuery(query->query(), base_uri,
- [&result](const SparqlService::RowType& row) {
- spq::SparqlResponse response;
- for (auto it = row.cbegin(); it != row.cend(); it++) {
- auto b = response.add_binding();
- b->set_variable(it->first);
- *b->mutable_value() = it->second.getMessage();
- }
- return result->Write(response);
- });
-
- return Status::OK;
+ try {
+ svc.TupleQuery(query->query(), base_uri,
+ [&result](const SparqlService::RowType& row) {
+ spq::SparqlResponse response;
+ for (auto it = row.cbegin(); it != row.cend(); it++) {
+ auto b = response.add_binding();
+ b->set_variable(it->first);
+ *b->mutable_value() = it->second.getMessage();
+ }
+ return result->Write(response);
+ });
+
+ return Status::OK;
+ } catch (sparql::SparqlException e) {
+ LOG(ERROR) << "SPARQL execution failed: " << e.what();
+ return Status(StatusCode::INVALID_ARGUMENT, e.what());
+ }
}
@@ -265,12 +271,35 @@ grpc::Status LevelDBSparqlService::GraphQuery(grpc::ServerContext* context,
rdf::URI base_uri = query->base_uri();
- svc.GraphQuery(query->query(), base_uri,
- [&result](const rdf::Statement& triple) {
- return result->Write(triple.getMessage());
- });
+ try {
+ svc.GraphQuery(query->query(), base_uri,
+ [&result](const rdf::Statement& triple) {
+ return result->Write(triple.getMessage());
+ });
- return Status::OK;
+ return Status::OK;
+ } catch (sparql::SparqlException e) {
+ LOG(ERROR) << "SPARQL execution failed: " << e.what();
+ return Status(StatusCode::INVALID_ARGUMENT, e.what());
+ }
+}
+
+grpc::Status LevelDBSparqlService::AskQuery(grpc::ServerContext* context,
+ const spq::SparqlRequest* query,
+ google::protobuf::BoolValue* result) {
+
+ SparqlService svc(util::make_unique<LevelDBTripleSource>(persistence));
+
+ rdf::URI base_uri = query->base_uri();
+
+ try {
+ result->set_value(svc.AskQuery(query->query(), base_uri));
+
+ return Status::OK;
+ } catch (sparql::SparqlException e) {
+ LOG(ERROR) << "SPARQL execution failed: " << e.what();
+ return Status(StatusCode::INVALID_ARGUMENT, e.what());
+ }
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/persistence/leveldb_service.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/persistence/leveldb_service.h b/libraries/ostrich/backend/persistence/leveldb_service.h
index 44056a3..87b5b12 100644
--- a/libraries/ostrich/backend/persistence/leveldb_service.h
+++ b/libraries/ostrich/backend/persistence/leveldb_service.h
@@ -114,6 +114,10 @@ class LevelDBSparqlService : public spq::SparqlService::Service {
grpc::Status GraphQuery(grpc::ServerContext* context,
const spq::SparqlRequest* pattern,
grpc::ServerWriter<rdf::proto::Statement>* result) override;
+
+ grpc::Status AskQuery(grpc::ServerContext* context,
+ const spq::SparqlRequest* pattern,
+ google::protobuf::BoolValue* result) override;
private:
persistence::LevelDBPersistence* persistence;
};
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/service/sparql.proto
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/service/sparql.proto b/libraries/ostrich/backend/service/sparql.proto
index 6d75a5f..e6da6d3 100644
--- a/libraries/ostrich/backend/service/sparql.proto
+++ b/libraries/ostrich/backend/service/sparql.proto
@@ -22,6 +22,7 @@ package marmotta.sparql.proto;
option java_package = "org.apache.marmotta.ostrich.client.proto";
import "model.proto";
+import "google/protobuf/wrappers.proto";
// SPARQL request consisting of a single query string.
message SparqlRequest {
@@ -46,4 +47,7 @@ service SparqlService {
// Execute a SPARQL 1.1 graph query and stream back the triples.
rpc GraphQuery(SparqlRequest) returns (stream marmotta.rdf.proto.Statement);
+
+ // Execute a SPARQL 1.1 ask query and return true or false.
+ rpc AskQuery(SparqlRequest) returns (google.protobuf.BoolValue);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/sparql/rasqal_adapter.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/sparql/rasqal_adapter.cc b/libraries/ostrich/backend/sparql/rasqal_adapter.cc
index 09e7bd6..1f6055b 100644
--- a/libraries/ostrich/backend/sparql/rasqal_adapter.cc
+++ b/libraries/ostrich/backend/sparql/rasqal_adapter.cc
@@ -62,7 +62,7 @@ std::string formatBindings(const std::map<std::string, rdf::Value>& bindings) {
#endif
void log_handler(void *user_data, raptor_log_message *message) {
- LOG(ERROR) << "SPARQL Error(" << message->code << "): " << message->text;
+ LOG_IF(ERROR, message->code >= 0) << "SPARQL Error(" << message->code << "): " << message->text;
}
// Bind the current statement to the variables configured in the triple match.
@@ -262,7 +262,7 @@ void SparqlService::TupleQuery(const std::string& query, const rdf::URI& base_ur
if (rasqal_query_prepare(q, STR(query), base) != 0) {
raptor_free_uri(base);
rasqal_free_query(q);
- throw SparqlException("Query preparation failed", query);
+ throw SparqlException("could not parse query", query);
}
bool next = true;
@@ -270,14 +270,14 @@ void SparqlService::TupleQuery(const std::string& query, const rdf::URI& base_ur
if (r == nullptr) {
raptor_free_uri(base);
rasqal_free_query(q);
- throw SparqlException("Query execution failed", query);
+ throw SparqlException("query execution failed", query);
}
if (!rasqal_query_results_is_bindings(r)) {
rasqal_free_query_results(r);
rasqal_free_query(q);
raptor_free_uri(base);
- throw SparqlException("Query is not a tuple query", query);
+ throw SparqlException("query is not a tuple query", query);
}
int rowcount = 0;
@@ -313,7 +313,7 @@ void SparqlService::GraphQuery(const std::string& query, const rdf::URI& base_ur
if (rasqal_query_prepare(q, STR(query), base) != 0) {
raptor_free_uri(base);
rasqal_free_query(q);
- throw SparqlException("Query preparation failed", query);
+ throw SparqlException("could not parse query", query);
}
bool next = true;
@@ -328,7 +328,7 @@ void SparqlService::GraphQuery(const std::string& query, const rdf::URI& base_ur
rasqal_free_query_results(r);
rasqal_free_query(q);
raptor_free_uri(base);
- throw SparqlException("Query is not a graph query", query);
+ throw SparqlException("query is not a graph query", query);
}
while (next) {
@@ -341,6 +341,41 @@ void SparqlService::GraphQuery(const std::string& query, const rdf::URI& base_ur
raptor_free_uri(base);
}
+bool SparqlService::AskQuery(const std::string& query, const rdf::URI& base_uri) {
+ util::TimeLogger timeLogger("SPARQL ask query");
+
+ auto q = rasqal_new_query(world, "sparql11-query", nullptr);
+ auto base = raptor_new_uri(rasqal_world_get_raptor(world),
+ STR(base_uri.getUri()));
+ if (rasqal_query_prepare(q, STR(query), base) != 0) {
+ raptor_free_uri(base);
+ rasqal_free_query(q);
+ throw SparqlException("could not parse query", query);
+ }
+
+ auto r = rasqal_query_execute(q);
+ if (r == nullptr || rasqal_query_results_get_boolean(r) < 0) {
+ raptor_free_uri(base);
+ rasqal_free_query(q);
+ throw SparqlException("query execution failed", query);
+ }
+
+ if (!rasqal_query_results_is_boolean(r)) {
+ rasqal_free_query_results(r);
+ rasqal_free_query(q);
+ raptor_free_uri(base);
+ throw SparqlException("query is not a boolean query", query);
+ }
+
+ bool result = rasqal_query_results_get_boolean(r) > 0;
+
+ rasqal_free_query_results(r);
+ rasqal_free_query(q);
+ raptor_free_uri(base);
+
+ return result;
+}
+
} // namespace sparql
} // namespace marmotta
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/sparql/rasqal_adapter.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/sparql/rasqal_adapter.h b/libraries/ostrich/backend/sparql/rasqal_adapter.h
index 32e82d2..2f75887 100644
--- a/libraries/ostrich/backend/sparql/rasqal_adapter.h
+++ b/libraries/ostrich/backend/sparql/rasqal_adapter.h
@@ -98,6 +98,12 @@ class SparqlService {
void GraphQuery(const std::string& query, const rdf::URI& base_uri,
std::function<bool(const rdf::Statement&)> stmt_handler);
+
+ /**
+ * Execute a boolean (ASK) query, returning the boolean result.
+ */
+ bool AskQuery(const std::string& query, const rdf::URI& base_uri);
+
/**
* Return a reference to the triple source managed by this service.
*/
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4a5e588c/libraries/ostrich/backend/test/SparqlTest.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/test/SparqlTest.cc b/libraries/ostrich/backend/test/SparqlTest.cc
index 0f663f5..a45a282 100644
--- a/libraries/ostrich/backend/test/SparqlTest.cc
+++ b/libraries/ostrich/backend/test/SparqlTest.cc
@@ -267,5 +267,25 @@ TEST(SPARQLTest, Graph) {
}
+TEST(SPARQLTest, AskTrue) {
+ rdf::Statement stmt = rdf::Statement(rdf::URI("http://example.com/s1"),
+ rdf::URI("http://example.com/p1"),
+ rdf::URI("http://example.com/o1"));
+ SparqlService svc(std::unique_ptr<TripleSource>(new MockTripleSource({stmt})));
+
+ EXPECT_TRUE(svc.AskQuery("ASK {}", base_uri));
+}
+
+
+TEST(SPARQLTest, AskFalse) {
+ rdf::Statement stmt = rdf::Statement(rdf::URI("http://example.com/s1"),
+ rdf::URI("http://example.com/p1"),
+ rdf::URI("http://example.com/o1"));
+ SparqlService svc(std::unique_ptr<TripleSource>(new MockTripleSource({stmt})));
+
+ EXPECT_FALSE(svc.AskQuery("ASK { <http://example.com/s2> ?p ?o}", base_uri));
+}
+
+
} // namespace sparql
} // namespace marmotta
\ No newline at end of file