Permalink
Browse files

Optionally infer triples using AllegroGraph's RDFS++ support

Aymeric Brisse requested support for AllegroGraph's RDFS++ inference,
and supplied me with example RDF data and several test cases.  Those
test cases made it easy to write this patch.

This patch adds support for "query options", which can be passed to
build_query, and which are interpreted by raw_query.  Right now, the
only supported query option is 'infer', which controls whether or not we
use AllegroGraph's inference support.

To add new query options, we need to update 3 places in the code:

  query_spec.rb: Add a new, self-contained spec.
  AbstractRepository#build_query: Document the option.
  AbstractRepository#raw_query: Implement the option.
  • Loading branch information...
1 parent 02ff44a commit b2fcc21816bcdc009a1f900866b9628c79bf6ab9 @emk committed May 19, 2011
Showing with 93 additions and 14 deletions.
  1. +6 −0 README.md
  2. +44 −13 lib/rdf/allegro_graph/abstract_repository.rb
  3. +7 −1 lib/rdf/allegro_graph/query.rb
  4. +36 −0 spec/query_spec.rb
View
@@ -310,3 +310,9 @@ Thank you for contributing to `rdf-agraph`!
[git_commit_message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[rspec]: http://relishapp.com/rspec
[yard]: http://yardoc.org/
+
+## Acknowledgements
+
+Many thanks to the following people for helping to improve `rdf-agraph`:
+
+* Aymeric Brisse: Unit tests for AllegroGraph inference.
@@ -167,10 +167,16 @@ def query_pattern(pattern)
# @see RDF::Queryable#query
# @see RDF::Query#execute
def query_execute(query, &block)
+ query_options =
+ if query.respond_to?(:query_options)
+ query.query_options
+ else
+ {}
+ end
if query.respond_to?(:requires_prolog?) && query.requires_prolog?
- prolog_query(query.to_prolog(self), &block)
+ prolog_query(query.to_prolog(self), query_options, &block)
else
- sparql_query(query_to_sparql(query), &block)
+ sparql_query(query_to_sparql(query), query_options, &block)
end
end
protected :query_execute
@@ -191,13 +197,17 @@ def query_execute(query, &block)
# @return [Enumerator<RDF::Query::Solution>]
#
# @param [String] query The query to run.
+ # @param [Hash{Symbol => Object}] query_options
+ # The query options (see build_query).
# @return [void]
# @note This function returns a single-use Enumerator! If you want to
# to treat the results as an array, call `to_a` on it, or you will
# re-run the query against the server repeatedly. This curious
# decision is made for consistency with RDF.rb.
- def sparql_query(query, &block)
- raw_query(:sparql, query, &block)
+ #
+ # @see #build_query
+ def sparql_query(query, query_options={}, &block)
+ raw_query(:sparql, query, query_options, &block)
end
# Run a raw Prolog query.
@@ -212,19 +222,32 @@ def sparql_query(query, &block)
# @return [Enumerator<RDF::Query::Solution>]
#
# @param [String] query The query to run.
+ # @param [Hash{Symbol => Object}] query_options
+ # The query options (see build_query).
# @return [void]
# @note This function returns a single-use Enumerator! If you want to
# to treat the results as an array, call `to_a` on it, or you will
# re-run the query against the server repeatedly. This curious
# decision is made for consistency with RDF.rb.
- def prolog_query(query, &block)
- raw_query(:prolog, query, &block)
+ #
+ # @see #build_query
+ def prolog_query(query, query_options={}, &block)
+ raw_query(:prolog, query, query_options, &block)
end
# Run a raw query in the specified language.
- def raw_query(language, query, &block)
- @repo.query.language = language
- results = json_to_query_solutions(@repo.query.perform(query))
+ def raw_query(language, query, query_options={}, &block)
+ # Build our query parameters.
+ params = {
+ :query => query,
+ :queryLn => language.to_s
+ }
+ params[:infer] = query_options[:infer].to_s if query_options[:infer]
+
+ # Run the query and process the results.
+ json = @repo.request_json(:get, path, :parameters => params,
+ :expected_status_code => 200)
+ results = json_to_query_solutions(json)
if block_given?
results.each {|s| yield s }
else
@@ -235,6 +258,10 @@ def raw_query(language, query, &block)
# Construct an AllegroGraph-specific query.
#
+ # @param [Hash{Symbol => Object}] query_options
+ # @option query_options [true,false,String] :infer
+ # The AllegroGraph inference mode to use. Defaults to `false`. The
+ # value `true` is equivalent to `'rdfs++'`.
# @yield query
# @yieldparam [Query] The query to build. Use the Query API to add
# patterns and functors.
@@ -243,8 +270,8 @@ def raw_query(language, query, &block)
#
# @see Query
# @see RDF::Query
- def build_query(&block)
- Query.new(self, &block)
+ def build_query(query_options={}, &block)
+ Query.new(self, query_options, &block)
end
@@ -351,8 +378,12 @@ def serialize_prolog(value)
protected
# Build a repository-relative path.
- def path(relative_path)
- "#{@repo.path}/#{relative_path}"
+ def path(relative_path=nil)
+ if relative_path
+ "#{@repo.path}/#{relative_path}"
+ else
+ @repo.path
+ end
end
# Deserialize an RDF::Value received from the server, or an array of such
@@ -19,10 +19,16 @@ class Query < RDF::Query
# Include our APIs.
include Functors::SnaFunctors
+ # Our query options.
+ #
+ # @see AbstractRepository#build_query
+ attr_reader :query_options
+
# Create a new query.
# @private
- def initialize(repository, &block)
+ def initialize(repository, query_options={}, &block)
@repository = repository
+ @query_options = query_options
super(&block)
end
View
@@ -84,4 +84,40 @@
EOD
end
end
+
+ context "with an RDFS/OWL ontology" do
+ Concepts = RDF::Vocabulary.new("http://www.example.com/Concepts#")
+
+ before do
+ @repository.insert(
+ [Concepts.Celine, RDF.type, Concepts.Woman],
+ [Concepts.Woman, RDF.type, RDF::OWL.Class],
+ [Concepts.Person, RDF.type, RDF::OWL.Class],
+ [Concepts.Woman, RDF::RDFS.subClassOf, Concepts.Person])
+ end
+
+ it "does not run inference by default" do
+ sln = @repository.build_query do |q|
+ q << [Concepts.Celine, RDF.type, :klass]
+ end.run.to_a
+ sln.should include_solution(:klass => Concepts.Woman)
+ sln.should_not include_solution(:klass => Concepts.Person)
+ end
+
+ it "does run inference when passed :infer => true" do
+ sln = @repository.build_query(:infer => true) do |q|
+ q << [Concepts.Celine, RDF.type, :klass]
+ end.run.to_a
+ sln.should include_solution(:klass => Concepts.Woman)
+ sln.should include_solution(:klass => Concepts.Person)
+ end
+
+ it "does run inference when passed :infer => 'rdfs++'" do
+ sln = @repository.build_query(:infer => 'rdfs++') do |q|
+ q << [Concepts.Celine, RDF.type, :klass]
+ end.run.to_a
+ sln.should include_solution(:klass => Concepts.Woman)
+ sln.should include_solution(:klass => Concepts.Person)
+ end
+ end
end

0 comments on commit b2fcc21

Please sign in to comment.