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