Querying With ROS
For querying a kDB Store with ROS, there are two approaches, the first one uses the kDB API and the second one uses service calls (as shown in the getting started tutorial). In this tutorial we present both approaches. And the use of the kDB API is more efficient.
Query with the kDB API
The kDB ROS Server broadcast its status on a topic kdb_status
with the hostname and port needed to connect directly to the database. It is therefore possible to create a connection object from the information provided in that topic.
The kDB ROS module also provides classes to conveniently create such a connection object.
-
To query the database from other Python programs, the easiest is to use
ros_kdb.create_connection()
. This will listen to the topickdb_status
which contains all the information needed to connect to the database and create a connection that can be used to query the database.An example of use of the function is provided below. This example create a connection to a runing ROS kDB server. It then runs a SPARQL query to print the UUID of the server:
#include <ros_kdb/connection_helper.h> #include <knowDBC/Query.h> #include <knowDBC/Result.h> #include <kDB/Repository/RDFEnvironment.h> // Create a connection helper, this can take a ROS node as an argument, or create one ros_kdb::ConnectionHelper ch; // Get the connection, this will wait for the connection to be ready kDB::Repository::Connection connection = ch.getConnection(); // The following creates an SPARQL query, that retuns the UUID of the server. knowDBC::Query query = connection.createSPARQLQuery({}, "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }"); // The following executes the query knowDBC::Result result = query.execute(); // Print the results in the command line std::cout << "Server has uuid: " << result.value(0, 0).printable().expectSuccess() << std::endl;
The following needs to be added to the package
CMakeLists.txt
:find_package(ros_kdb REQUIRED) ament_target_dependencies(your_target ros_kdb)
-
To query the database from other Python programs, the easiest is to use
ros_kdb.create_connection()
. This will listen to the topickdb_status
which contains all the information needed to connect to the database and create a connection that can be used to query the database.An example of use of the function is provided below. This example create a connection to a runing ROS kDB server. It then runs a SPARQL query to print the UUID of the server:
import rclpy import ros_kdb rclpy.init() # Create a connection, this can take a ROS namespace as argument, or default to "". # This will wait for the connection to be ready c = ros_kdb.create_connection() q = c.createSPARQLQuery() # The following creates an SPARQL query, that retuns the UUID of the server. q.setQuery("SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }") # The following executes the query r = q.execute() # Print the results in the command line print(f"Server has uuid {r.value(0, 0)}")
-
In kDB < 4.5, Ruby does not have a convenience class for creating a connection, instead it is necesserary to listen to
kdb_status
in the program.require 'rclrb' require 'knowRDF' require 'kDB/Repository' require 'ros_kdb_interfaces/msg' # Initialise Rclrb Rclrb.init(arguments: []) n = Rclrb::Node.new "test_query" # Create a subscription to `kdb_status` n.create_subscription(RosKdbInterfaces::Msg::DatabaseStatus, "kdb_status", 1) do |msg| # Create a connection to the database connection = KDB::Repository::Connection.create msg.hostname, msg.port connection.connect() # The following creates an SPARQL query, that retuns the UUID of the server. query = connection.createSPARQLQuery( KDB::Repository::RDFEnvironment.new(), "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }") # The following executes the query result = query.execute # Print the results in the command line puts "Server has uuid #{result.value(0, 0)}" # And exit Rclrb.shutdown end # Start the execution Rclrb.spin(n)
With kDB >= 4.5, the convenience class was added:
irb(main):003:0> ; Rclrb::init => #<Proc:0x000055f9ac5f9848 /home/cyrille/ros2_ws/src/rclrb/lib/rclrb/init.rb:47> irb(main):004:0> c = RosKDB.create_connection “/test0/”
require 'rclrb' require 'knowRDF' require 'kDB/Repository' require 'ros_kdb' # Initialise Rclrb Rclrb.init(arguments: []) # Create a connection, this can take a ROS namespace as argument, or default to "". # This will wait for the connection to be ready connection = RosKDB.create_connection # The following creates an SPARQL query, that retuns the UUID of the server. query = connection.createSPARQLQuery( KDB::Repository::RDFEnvironment.new(), "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }") # The following executes the query result = query.execute # Print the results in the command line puts "Server has uuid #{result.value(0, 0)}"
Query with service call
To query remote systems, it is possible to allow the PostgreSQL server to listen to external connection. But if that is not possible or desirable, the only solution might be to use service calls.
-
#include <ros_kdb_interfaces/srv/QueryDatabase.h> // Create a service call to 'kdb_server/sparql_query' to execute a SPARQL query. // It can be replaced by 'kdb_server/sql_query' for SQL. rclcpp::Client<ros_kdb_interfaces::srv::QueryDatabase>::SharedPtr client = node->create_client<ros_kdb_interfaces::srv::QueryDatabase>("kdb_server/sparql_query"); // Create a request object auto request = std::make_shared<ros_kdb_interfaces::srv::QueryDatabase::Request>(); // Request can contain multiple query, all executed in the same transaction. // For this example, a single query will be used. ros_kdb_interfaces::msg::Query query; // Select which graphs are available to the query query.graphnames.push_back("http://askco.re/graphs#info"); // Assign the text of the query, it will query for the UUID of the server. query.query = "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }"; request->queries.push_back(query); // Execute the service call auto result = client->async_send_request(request); // Wait for the result rclcpp::spin_until_future_complete(node, result); // Print the result, which is a JSON string std::cout << result.get()->results[0] << std::endl;
-
import json import rclpy import rclpy.node from ros_kdb_interfaces.srv import QueryDatabase from ros_kdb_interfaces.msg import Query rclpy.init(args=args) node = rclpy.node.Node("test_query") # Create a service call to 'kdb_server/sparql_query' to execute a SPARQL query. # It can be replaced by 'kdb_server/sql_query' for SQL. client = node.create_client(QueryDatabase, 'kdb_server/sparql_query') # Create a request object request = QueryDatabase.Request() # Request can contain multiple query, all executed in the same transaction. # For this example, a single query will be used. query = Query() # Select which graphs are available to the query query.graphnames = ["http://askco.re/graphs#info"] # Assign the text of the query, it will query for the UUID of the server. query.query = "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }"; request.queries.append(query); # Execute the service call future = client.call_async(request) # Wait for the result rclpy.spin_until_future_complete(node, future) # Parse the JSON string r = json.loads(future.result().results[0])) # Print the results in the command line print(f"Server has uuid {r['results']['bindings'][0]['uuid']['value']}")
-
require 'json' require 'rclrb' require 'ros_kdb_interfaces/msg' require 'ros_kdb_interfaces/srv' Rclrb.init(arguments: []) node = Rclrb::Node.new "test_query" # Create a service call to 'kdb_server/sparql_query' to execute a SPARQL query. # It can be replaced by 'kdb_server/sql_query' for SQL. client = node.create_client RosKdbInterfaces::Srv::QueryDatabase, 'kdb_server/sparql_query' # Create a request object request = RosKdbInterfaces::Srv::QueryDatabase::Request.new # Request can contain multiple query, all executed in the same transaction. # For this example, a single query will be used. query = RosKdbInterfaces::Msg::Query.new # Select which graphs are available to the query query.graphnames = ["http://askco.re/graphs#info"] # Assign the text of the query, it will query for the UUID of the server. query.query = "SELECT ?uuid FROM <http://askco.re/graphs#info> WHERE { <http://askco.re/db/info#self> <http://askco.re/db/info#hasUUID> ?uuid }"; request.queries.append(query); # Execute the service call future = client.call_async request # Parse the JSON string r = JSON.parse future.result.results[0] # Print the results in the command line puts "Server has uuid #{r['results']['bindings'][0]['uuid']['value']}"