| RDF-Query documentation | Contained in the RDF-Query distribution. |
RDF::Query::Algebra::BasicGraphPattern - Algebra class for BasicGraphPattern patterns
This document describes RDF::Query::Algebra::BasicGraphPattern version 2.907.
Beyond the methods documented below, this class inherits methods from the RDF::Query::Algebra class.
new ( @triples )Returns a new BasicGraphPattern structure.
construct_argsReturns a list of arguments that, passed to this class' constructor, will produce a clone of this algebra pattern.
triplesReturns a list of triples belonging to this BGP.
quadsReturns a list of the (implicit) quads belonging to this BGP.
sseReturns the SSE string for this algebra expression.
explainReturns a string serialization of the algebra appropriate for display on the command line.
as_sparqlReturns the SPARQL string for this algebra expression.
as_hashReturns the query as a nested set of plain data structures (no objects).
as_spin ( $model )Adds statements to the given model to represent this algebra object in the SPARQL Inferencing Notation (http://www.spinrdf.org/).
typeReturns the type of this algebra expression.
referenced_variablesReturns a list of the variable names used in this algebra expression.
potentially_boundReturns a list of the variable names used in this algebra expression that will bind values during execution.
definite_variablesReturns a list of the variable names that will be bound after evaluating this algebra expression.
check_duplicate_blanksReturns true if blank nodes respect the SPARQL rule of no blank-label re-use across BGPs, otherwise throws a RDF::Query::Error::QueryPatternError exception.
connectedReturns true if the pattern is connected through shared variables, false otherwise.
subsumes ( $pattern )Returns true if the bgp subsumes the pattern, false otherwise.
bf ()Returns a string representing the state of the nodes of the triple (bound or free).
clonebind_variables ( \%bound )Returns a new algebra pattern with variables named in %bound replaced by their corresponding bound values.
Gregory Todd Williams <gwilliams@cpan.org>
| RDF-Query documentation | Contained in the RDF-Query distribution. |
# RDF::Query::Algebra::BasicGraphPattern # -----------------------------------------------------------------------------
package RDF::Query::Algebra::BasicGraphPattern; use strict; use warnings; no warnings 'redefine'; use base qw(RDF::Query::Algebra); use Data::Dumper; use Log::Log4perl; use Scalar::Util qw(blessed refaddr reftype); use Carp qw(carp croak confess); use Time::HiRes qw(gettimeofday tv_interval); use RDF::Trine::Iterator qw(smap swatch); ###################################################################### our ($VERSION); my %AS_SPARQL; BEGIN { $VERSION = '2.907'; } ######################################################################
sub new { my $class = shift; my @triples = @_; foreach my $t (@triples) { unless ($t->isa('RDF::Trine::Statement')) { throw RDF::Query::Error::QueryPatternError -text => "Patterns belonging to a BGP must be graph statements"; } } return bless( [ @triples ] ); }
sub construct_args { my $self = shift; return ($self->triples); }
sub triples { my $self = shift; return @$self; }
sub quads { my $self = shift; my @triples = $self->triples; my @quads; foreach my $t (@triples) { my @nodes = $t->nodes; foreach my $i (0 .. 3) { my $n = $nodes[ $i ]; if (not blessed($n)) { if ($i == 3) { $nodes[ $i ] = RDF::Trine::Node::Nil->new(); } else { $nodes[ $i ] = RDF::Query::Node::Variable->new(); } } } my $st = RDF::Trine::Statement::Quad->new( @nodes ); push(@quads, $st); } return @quads; }
sub sse { my $self = shift; my $context = shift; my $prefix = shift || ''; my $indent = $context->{indent} || ' '; my @triples = sort map { $_->sse( $context ) } $self->triples; return sprintf( "(BGP\n${prefix}${indent}%s\n${prefix})", join("\n${prefix}${indent}", @triples) ); }
sub explain { my $self = shift; my $s = shift; my $count = shift; my $indent = $s x $count; my $string = "${indent}basic graph pattern\n"; foreach my $t ($self->triples) { $string .= "${indent}${s}" . $t->as_sparql . "\n"; } return $string; }
sub as_sparql { my $self = shift; if (exists $AS_SPARQL{ refaddr( $self ) }) { return $AS_SPARQL{ refaddr( $self ) }; } else { my $context = shift; # if (ref($context)) { # $context = { %$context }; # } my $indent = shift || ''; my @triples; foreach my $t ($self->triples) { push(@triples, $t->as_sparql( $context, $indent )); } my $string = join("\n${indent}", @triples); $AS_SPARQL{ refaddr( $self ) } = $string; return $string; } }
sub as_hash { my $self = shift; my $context = shift; return { type => lc($self->type), patterns => [ map { $_->as_hash } $self->triples ], }; }
sub as_spin { my $self = shift; my $model = shift; my @t = $self->triples; my @nodes = map { $_->as_spin( $model ) } @t; return @nodes; }
sub type { return 'BGP'; }
sub referenced_variables { my $self = shift; return RDF::Query::_uniq(map { $_->referenced_variables } $self->triples); }
sub potentially_bound { my $self = shift; return RDF::Query::_uniq(map { $_->potentially_bound } $self->triples); }
sub definite_variables { my $self = shift; return RDF::Query::_uniq(map { $_->definite_variables } $self->triples); }
sub _check_duplicate_blanks { my $self = shift; my %seen; foreach my $t ($self->triples) { my @blanks = $t->referenced_blanks; foreach my $b (@blanks) { $seen{ $b }++; } } return [keys %seen]; }
sub connected { my $self = shift; my @triples = $self->triples; return 1 unless (scalar(@triples) > 1); my %index; my %variables; foreach my $i (0 .. $#triples) { my $t = $triples[ $i ]; $index{ $t->as_string } = $i; foreach my $n ($t->nodes) { next unless ($n->isa('RDF::Trine::Node::Variable')); push( @{ $variables{ $n->name } }, $t ); } } my @connected; foreach my $i (0 .. $#triples) { foreach my $j (0 .. $#triples) { $connected[ $i ][ $j ] = ($i == $j) ? 1 : 0; } } my %seen; my @queue = $triples[0]; while (my $t = shift(@queue)) { my $string = $t->as_string; next if ($seen{ $string }++); my @vars = map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } $t->nodes; my @connected_to = map { @{ $variables{ $_ } } } @vars; foreach my $c (@connected_to) { my $cstring = $c->as_string; my $i = $index{$string}; my $k = $index{ $cstring }; my @conn = @{ $connected[$i] }; $conn[ $k ] = 1; foreach my $j (0 .. $#triples) { if ($conn[ $j ] == 1) { $connected[ $k ][ $j ] = 1; $connected[ $j ][ $k ] = 1; } } push(@queue, $c); } } foreach my $i (0 .. $#triples) { return 0 unless ($connected[0][$i] == 1); } return 1; }
sub subsumes { my $self = shift; my $pattern = shift; if ($pattern->isa('RDF::Trine::Statement')) { foreach my $t ($self->triples) { return 1 if ($t->subsumes($pattern)); } return 0; } elsif ($pattern->isa('RDF::Query::Algebra::BasicGraphPattern')) { OUTER: foreach my $p ($pattern->triples) { foreach my $t ($self->triples) { next OUTER if ($t->subsumes($p)); } return 0; } return 1; } else { return 0; } }
sub bf { my $self = shift; my @bf; my %var_to_num; my %use_count; my $counter = 1; foreach my $t ($self->triples) { my $bf = $t->bf; if ($bf =~ /f/) { $bf = ''; foreach my $n ($t->nodes) { if ($n->isa('RDF::Query::Node::Variable')) { my $name = $n->name; my $num = ($var_to_num{ $name } ||= $counter++); $use_count{ $name }++; $bf .= "{${num}}"; } else { $bf .= 'b'; } } } push(@bf, $bf); } my $bf = join(',',@bf); if ($counter <= 10) { $bf =~ s/[{}]//g; } return $bf; }
sub clone { my $self = shift; my $class = ref($self); return $class->new( map { $_->clone } $self->triples ); }
sub bind_variables { my $self = shift; my $class = ref($self); my $bound = shift; return $class->new( map { $_->bind_variables( $bound ) } $self->triples ); } sub DESTROY { my $self = shift; delete $AS_SPARQL{ refaddr( $self ) }; } 1; __END__