Class: RDF::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/rdf/query.rb,
lib/rdf/query/pattern.rb,
lib/rdf/query/solution.rb,
lib/rdf/query/variable.rb,
lib/rdf/query/solutions.rb

Overview

An RDF basic graph pattern (BGP) query.

Named queries either match against a specifically named contexts if the name is an RDF::Term 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:[email protected]> .

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

_:a foaf:name "Alice" .
_:a foaf:mbox <mailto:[email protected]> .

See Also:

Since:

  • 0.3.0

Defined Under Namespace

Classes: Pattern, Solution, Solutions, Variable

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

Initializes a new basic graph pattern query.

Overloads:

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

    Parameters:

    • patterns (Array<RDF::Query::Pattern>) (defaults to: [])

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

      any additional keyword options

    Options Hash (options):

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

      Default context for matching against queryable. Named queries either match against a specifically named contexts if the name is an RDF::Term 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.

    Yields:

    • (query)

    Yield Parameters:

    Yield Returns:

    • (void)

      ignored

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

    Parameters:

    • patterns (Hash{Object => Object})

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

      any additional keyword options

    Options Hash (options):

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

      Default context for matching against queryable. Named queries either match against a specifically named contexts if the name is an RDF::Term or bound RDF::Query::Variable. Names that are against unbound variables match either detault or named contexts.

    Yields:

    • (query)

    Yield Parameters:

    Yield Returns:

    • (void)

      ignored

Since:

  • 0.3.0



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rdf/query.rb', line 154

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.delete(:context)

  @patterns  = case patterns.first
    when Hash  then compile_hash_patterns(patterns.first.dup)
    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

#optionsHash (readonly)

Any additional options for this query.

Returns:

  • (Hash)

Since:

  • 0.3.0



117
118
119
# File 'lib/rdf/query.rb', line 117

def options
  @options
end

#patternsArray<RDF::Query::Pattern> (readonly)

The patterns that constitute this query.

Returns:

Since:

  • 0.3.0



105
106
107
# File 'lib/rdf/query.rb', line 105

def patterns
  @patterns
end

#solutionsRDF::Query::Solutions (readonly)

The solution sequence for this query.

Returns:

Since:

  • 0.3.0



111
112
113
# File 'lib/rdf/query.rb', line 111

def solutions
  @solutions
end

#variablesHash{Symbol => RDF::Query::Variable} (readonly)

The variables used in this query.

Returns:

Since:

  • 0.3.0



99
100
101
# File 'lib/rdf/query.rb', line 99

def variables
  @variables
end

Class Method Details

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

Executes a query on the given ‘queryable` graph or repository.

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

  • patterns (Hash{Object => Object}) (defaults to: nil)

    optional hash patterns to initialize the query with

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

    any additional keyword options (see #initialize)

Yields:

  • (query)

Yield Parameters:

Yield Returns:

  • (void)

    ignored

Returns:

See Also:

Since:

  • 0.3.0



91
92
93
# File 'lib/rdf/query.rb', line 91

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

Instance Method Details

#+(other) ⇒ RDF::Query

Add patterns from another query to form a new Query

Parameters:

Returns:

Since:

  • 0.3.0



335
336
337
# File 'lib/rdf/query.rb', line 335

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

#<<(pattern) ⇒ void

This method returns an undefined value.

Appends the given query ‘pattern` to this query.

Parameters:

Since:

  • 0.3.0



183
184
185
186
# File 'lib/rdf/query.rb', line 183

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

#contextRDF::Value

Name of this query, if any

Returns:

Since:

  • 0.3.0



360
361
362
# File 'lib/rdf/query.rb', line 360

def context
  options[:context]
end

#context=(value) ⇒ RDF::Value

Add name to query

Parameters:

Returns:

Since:

  • 0.3.0



354
355
356
# File 'lib/rdf/query.rb', line 354

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

#each_solution {|solution| ... } ⇒ Enumerator Also known as: each

Enumerates over each matching query solution.

Yields:

  • (solution)

Yield Parameters:

Returns:

Since:

  • 0.3.0



376
377
378
# File 'lib/rdf/query.rb', line 376

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

#empty?Boolean

Query has no patterns

Returns:

  • (Boolean)

Since:

  • 0.3.0



366
367
368
# File 'lib/rdf/query.rb', line 366

def empty?
  patterns.empty?
end

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

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::Term 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.

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

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

    any additional keyword options

Options Hash (options):

  • bindings (Hash{Symbol => RDF::Term})

    optional variable bindings to use

  • solutions (Hash{Symbol => RDF::Term})

    optional initial solutions for chained queries

Returns:

See Also:

Since:

  • 0.3.0



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
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
# File 'lib/rdf/query.rb', line 250

def execute(queryable, options = {})
  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({}))

  patterns = @patterns

  # Add context to pattern, if necessary
  unless self.context.nil?
    if patterns.empty?
      patterns = [Pattern.new(nil, nil, nil, :context => self.context)]
    elsif patterns.first.context.nil?
      patterns.first.context = self.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|
      pattern.execute(queryable, solution) do |statement|
        @solutions << solution.merge(pattern.solution(statement))
      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

#failed?Boolean

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



316
317
318
# File 'lib/rdf/query.rb', line 316

def failed?
  @solutions.empty?
end

#matched?Boolean

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



328
329
330
# File 'lib/rdf/query.rb', line 328

def matched?
  !@failed
end

#named?Boolean

Is this is a named query?

Returns:

  • (Boolean)

Since:

  • 0.3.0



341
342
343
# File 'lib/rdf/query.rb', line 341

def named?
  !!options[:context]
end

#optimize(options = {}) ⇒ RDF::Query

Returns an optimized copy of this query.

Parameters:

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

    any additional options for optimization

Returns:

Since:

  • 0.3.0



210
211
212
# File 'lib/rdf/query.rb', line 210

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

#optimize!(options = {}) ⇒ void

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



223
224
225
226
227
228
# File 'lib/rdf/query.rb', line 223

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

#pattern(pattern, options = {}) ⇒ void

This method returns an undefined value.

Appends the given query ‘pattern` to this query.

Parameters:

  • pattern (RDF::Query::Pattern)

    a triple query pattern

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

    any additional keyword options

Options Hash (options):

  • :optional (Boolean) — default: false

    whether this is an optional pattern

Since:

  • 0.3.0



198
199
200
201
# File 'lib/rdf/query.rb', line 198

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

#unnamed?Boolean

Is this is an unamed query?

Returns:

  • (Boolean)

Since:

  • 0.3.0



347
348
349
# File 'lib/rdf/query.rb', line 347

def unnamed?
  !named?
end