Class: RDF::Query

Inherits:
Object show all
Defined in:
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query/hash_pattern_normalizer.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query/pattern.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query/solution.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query/solutions.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query/variable.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/sparql-da60321cd7bc/lib/sparql/algebra/extensions.rb,
vendor/bundler/ruby/2.0.0/bundler/gems/sparql-da60321cd7bc/lib/sparql/extensions.rb

Overview

An RDF basic graph pattern (BGP) query.

Named queries either match against a specifically named contexts if the name is an RDF::Resource or bound RDF::Query::Variable. Names that are against unbound variables match either default or named contexts. The name of false will only match against the default context.

Variable names cause the variable to be added to the solution set elements.

Examples:

Constructing a basic graph pattern query (1)

query = RDF::Query.new do
  pattern [:person, RDF.type,  FOAF.Person]
  pattern [:person, FOAF.name, :name]
  pattern [:person, FOAF.mbox, :email]
end

Constructing a basic graph pattern query (2)

query = RDF::Query.new({
  :person => {
    RDF.type  => FOAF.Person,
    FOAF.name => :name,
    FOAF.mbox => :email,
  }
})

Executing a basic graph pattern query

graph = RDF::Graph.load('etc/doap.nt')
query.execute(graph).each do |solution|
  puts solution.inspect
end

Constructing and executing a query in one go (1)

solutions = RDF::Query.execute(graph) do
  pattern [:person, RDF.type, FOAF.Person]
end

Constructing and executing a query in one go (2)

solutions = RDF::Query.execute(graph, {
  :person => {
    RDF.type => FOAF.Person,
  }
})

In this example, the default graph contains the names of the publishers of two named graphs. The triples in the named graphs are not visible in the default graph in this example.

# default graph
@prefix dc: <http://purl.org/dc/elements/1.1/

<http://example.org/bob>    dc:publisher  "Bob" .
<http://example.org/alice>  dc:publisher  "Alice" .

# Named graph: http://example.org/bob
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

_:a foaf:name "Bob" .
_:a foaf:mbox <mailto:bob@oldcorp.example.org> .

# Named graph: http://example.org/alice
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

_:a foaf:name "Alice" .
_:a foaf:mbox <mailto:alice@work.example.org> .

See Also:

Since:

Direct Known Subclasses

SPARQL::Client::Query

Defined Under Namespace

Classes: HashPatternNormalizer, Pattern, Solution, Solutions, Variable

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Query) initialize(patterns = [], options = {}) {|query| ... } - (Query) initialize(patterns, options = {}) {|query| ... }

Initializes a new basic graph pattern query.

Overloads:

  • - (Query) initialize(patterns = [], options = {}) {|query| ... }

    Parameters:

    Options Hash (options):

    • :solutions (RDF::Query::Solutions) — default: Solutions.new
    • :context (RDF::Resource, RDF::Query::Variable, false) — default: nil

      Default context for matching against queryable. Named queries either match against a specifically named graphs if the name is an Resource or bound Variable. Names that are against unbound variables match either default or named graphs. The name of false will only match against the default context.

    • :name (RDF::Resource, RDF::Query::Variable, false) — default: nil

      Alias for :context.

    Yields:

    • (query)

    Yield Parameters:

    Yield Returns:

    • (void)

      ignored

  • - (Query) initialize(patterns, options = {}) {|query| ... }

    Parameters:

    Options Hash (options):

    Yields:

    • (query)

    Yield Parameters:

    Yield Returns:

    • (void)

      ignored

Since:

  • 0.3.0



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 159

def initialize(*patterns, &block)
  @options  = patterns.last.is_a?(Hash) ? patterns.pop.dup : {}
  patterns << @options if patterns.empty?
  @variables = {}
  @solutions = @options.delete(:solutions) || Solutions.new
  context = @options.fetch(:context, @options.fetch(:name, nil))
  @options.delete(:context)
  @options.delete(:name)

  @patterns  = case patterns.first
    when Hash  then compile_hash_patterns(HashPatternNormalizer.normalize!(patterns.first.dup, @options))
    when Array then patterns.first
    else patterns
  end

  self.context = context

  if block_given?
    case block.arity
      when 1 then block.call(self)
      else instance_eval(&block)
    end
  end
end

Instance Attribute Details

- (Hash) options (readonly)

Any additional options for this query.

Returns:

Since:

  • 0.3.0



118
119
120
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 118

def options
  @options
end

- (Array<RDF::Query::Pattern>) patterns (readonly)

The patterns that constitute this query.

Returns:

Since:

  • 0.3.0



106
107
108
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 106

def patterns
  @patterns
end

- (RDF::Query::Solutions) solutions (readonly)

The solution sequence for this query.

Returns:

Since:

  • 0.3.0



112
113
114
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 112

def solutions
  @solutions
end

- (Hash{Symbol => RDF::Query::Variable}) variables (readonly)

The variables used in this query.

Returns:

Since:

  • 0.3.0



100
101
102
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 100

def variables
  @variables
end

Class Method Details

+ (RDF::Query::Solutions) execute(queryable, patterns = {}, options = {}) {|query| ... }

Executes a query on the given queryable graph or repository.

Parameters:

Yields:

  • (query)

Yield Parameters:

Yield Returns:

  • (void)

    ignored

Returns:

See Also:

Since:

  • 0.3.0



92
93
94
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 92

def self.execute(queryable, patterns = {}, options = {}, &block)
  self.new(patterns, options, &block).execute(queryable, options)
end

Instance Method Details

- (RDF::Query) +(other)

Add patterns from another query to form a new Query

Parameters:

Returns:

Since:

  • 0.3.0



363
364
365
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 363

def +(other)
  Query.new(self.patterns + other.patterns)
end

- <<(pattern)

This method returns an undefined value.

Appends the given query pattern to this query.

Parameters:

Since:

  • 0.3.0



190
191
192
193
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 190

def <<(pattern)
  @patterns << Pattern.from(pattern)
  self
end

- (Boolean) ==(other)

Equivalence for Queries: Same Patterns Same Context

Returns:

  • (Boolean)

Since:

  • 0.3.0



150
151
152
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/sparql-da60321cd7bc/lib/sparql/algebra/extensions.rb', line 150

def ==(other)
  other.is_a?(RDF::Query) && patterns == other.patterns && context == context
end

- (RDF::IRI, RDF::Query::Variable) context

Scope of this query, if any

Returns:

Since:

  • 0.3.0



395
396
397
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 395

def context
  options[:context]
end

- (RDF::IRI, RDF::Query::Variable) context=(value)

Scope the query to named graphs matching value

Parameters:

Returns:

Since:

  • 0.3.0



389
390
391
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 389

def context=(value)
  options[:context] = value
end

- (Boolean) default?

Is this query scoped to the default graph?

Returns:

  • (Boolean)

Since:

  • 0.3.0



375
376
377
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 375

def default?
  options[:context] == false
end

- (RDF::Query) dup

Duplicate query, including patterns and solutions

Returns:

Since:

  • 0.3.0



419
420
421
422
423
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 419

def dup
  patterns = @patterns.map {|p| p.dup}
  patterns << @options.merge(:solutions => @solutions.dup)
  Query.new(*patterns)
end

- (Enumerator) each_solution {|solution| ... } Also known as: each

Enumerates over each matching query solution.

Yields:

  • (solution)

Yield Parameters:

Returns:

Since:

  • 0.3.0



411
412
413
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 411

def each_solution(&block)
  @solutions.each(&block)
end

- (Boolean) empty?

Determine if this is an empty query, having no patterns

Returns:

  • (Boolean)

Since:

  • 0.3.0



401
402
403
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 401

def empty?
  patterns.empty?
end

- (RDF::Query::Solutions) execute(queryable, options = {})

Executes this query on the given queryable graph or repository.

Named queries either match against a specifically named contexts if the name is an RDF::Resource or bound RDF::Query::Variable. Names that are against unbound variables match either detault or named contexts. The name of false will only match against the default context.

If the query nas no patterns, it returns a single empty solution as per SPARQL 1.1 Empty Group Pattern.

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

  • options (Hash{Symbol => Object}) (defaults to: {})

    any additional keyword options

Options Hash (options):

Returns:

See Also:

Since:

  • 0.3.0



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 266

def execute(queryable, options = {})
  validate!
  options = options.dup

  # just so we can call #keys below without worrying
  options[:bindings] ||= {}

  # Use provided solutions to allow for query chaining
  # Otherwise, a quick empty solution simplifies the logic below; no special case for
  # the first pattern
  @solutions = options[:solutions] || (Solutions.new << RDF::Query::Solution.new({}))

  # If there are no patterns, just return the empty solution
  return @solutions if empty?

  patterns = @patterns
  context = options.fetch(:context, options.fetch(:name, self.context))

  # Add context to pattern, if necessary
  unless context.nil?
    if patterns.empty?
      patterns = [Pattern.new(nil, nil, nil, :context => context)]
    elsif patterns.first.context.nil?
      patterns.first.context = context
    end
  end
  
  patterns.each do |pattern|

    old_solutions, @solutions = @solutions, Solutions.new

    options[:bindings].keys.each do |variable|
      if pattern.variables.include?(variable)
        unbound_solutions, old_solutions = old_solutions, Solutions.new
        options[:bindings][variable].each do |binding|
          unbound_solutions.each do |solution|
            old_solutions << solution.merge(variable => binding)
          end
        end
        options[:bindings].delete(variable)
      end
    end

    old_solutions.each do |solution|
      found_match = false
      pattern.execute(queryable, solution) do |statement|
        found_match = true
        @solutions << solution.merge(pattern.solution(statement))
      end
      # If this pattern was optional, and we didn't find any matches,
      # just copy it over as-is.
      if !found_match && pattern.optional?
        @solutions << solution
      end
    end

    #puts "solutions after #{pattern} are #{@solutions.to_a.inspect}"

    # It's important to abort failed queries quickly because later patterns
    # that can have constraints are often broad without them.
    # We have no solutions at all:
    return @solutions if @solutions.empty?
    # We have no solutions for variables we should have solutions for:
    if !pattern.optional? && pattern.variables.keys.any? { |variable| !@solutions.variable_names.include?(variable) }
      return Solutions.new
    end
  end
  @solutions
end

- (Boolean) failed?

Returns true if this query did not match when last executed.

When the solution sequence is empty, this method can be used to determine whether the query failed to match or not.

Returns:

  • (Boolean)

See Also:

Since:

  • 0.3.0



344
345
346
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 344

def failed?
  @solutions.empty?
end

- (Boolean) matched?

Returns true if this query matched when last executed.

When the solution sequence is empty, this method can be used to determine whether the query matched successfully or not.

Returns:

  • (Boolean)

See Also:

Since:

  • 0.3.0



356
357
358
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 356

def matched?
  !@failed
end

- (Boolean) named?

Is this query scoped to a named graph?

Returns:

  • (Boolean)

Since:

  • 0.3.0



369
370
371
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 369

def named?
  !!options[:context]
end

- (RDF::Query) optimize(options = {})

Returns an optimized copy of this query.

Parameters:

  • options (Hash{Symbol => Object}) (defaults to: {})

    any additional options for optimization

Returns:

Since:

  • 0.3.0



217
218
219
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 217

def optimize(options = {})
  self.dup.optimize!(options)
end

- optimize!(options = {})

This method returns an undefined value.

Optimizes this query by reordering its constituent triple patterns according to their cost estimates.

Parameters:

  • options (Hash{Symbol => Object}) (defaults to: {})

    any additional options for optimization

See Also:

Since:

  • 0.3.0



230
231
232
233
234
235
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 230

def optimize!(options = {})
  @patterns.sort! do |a, b|
    (a.cost || 0) <=> (b.cost || 0)
  end
  self
end

- pattern(pattern, options = {})

This method returns an undefined value.

Appends the given query pattern to this query.

Parameters:

Options Hash (options):

  • :optional (Boolean) — default: false

    whether this is an optional pattern

Since:

  • 0.3.0



205
206
207
208
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 205

def pattern(pattern, options = {})
  @patterns << Pattern.from(pattern, options)
  self
end

- (SPARQL::Algebra::Expression) rewrite(&block)

Don't do any more rewriting

Returns:

Since:

  • 0.3.0



157
158
159
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/sparql-da60321cd7bc/lib/sparql/algebra/extensions.rb', line 157

def rewrite(&block)
  self
end

- (Array) to_sxp_bin

Transform Query into an Array form of an SSE

If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP

Returns:

Since:

  • 0.3.0



166
167
168
169
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/sparql-da60321cd7bc/lib/sparql/algebra/extensions.rb', line 166

def to_sxp_bin
  res = [:bgp] + patterns.map(&:to_sxp_bin)
  (context ? [:graph, context, res] : res)
end

- (Boolean) unnamed?

Is this query unscoped? This indicates that it can return results from either a named graph or the default graph.

Returns:

  • (Boolean)

Since:

  • 0.3.0



382
383
384
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 382

def unnamed?
  options[:context].nil?
end

- validate!

This method returns an undefined value.

Validate this query, making sure it can be executed by our query engine. This method is public so that it may be called by implementations of RDF::Queryable#query_execute that bypass our built-in query engine.

Raises:

  • (ArgumentError)

    This query cannot be executed.

Since:

  • 0.3.0



432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'vendor/bundler/ruby/2.0.0/bundler/gems/rdf-fa5fd9674f9a/lib/rdf/query.rb', line 432

def validate!
  # Our first pattern, if it exists, cannot be an optional pattern.
  if @patterns.length > 0 && @patterns[0].optional?
    raise ArgumentError.new("Query must not begin with an optional pattern")
  end

  # All optional patterns must appear after the regular patterns.  We
  # could test this more cleanly using Ruby 1.9-specific features, but
  # we want to run under Ruby 1.8, too.
  i = 0
  i += 1 while i < @patterns.length && !@patterns[i].optional?
  while i < @patterns.length
    unless @patterns[i].optional?
      raise ArgumentError.new("Optional patterns must appear at end of query")
    end
    i += 1
  end

  nil
end