Attean
view release on metacpan or search on metacpan
lib/Attean/SimpleQueryEvaluator.pm view on Meta::CPAN
}
if (defined($second)) {
if (blessed($val) and $val->does('Attean::API::Binding')) {
# patterns need to be made ground to be bound as values (e.g. TriplePattern -> Triple)
$val = $val->ground($r);
}
# warn "Unfold error: $@" if ($@);
$bindings{$second} = $val if ($val);
}
my $new = Attean::Result->new( bindings => \%bindings )->join($r);
push(@results, $new);
}
}
}
my %vars = map { $_ => 1 } $iter->variables;
$vars{$first}++;
$vars{$second}++ if defined($second);
return Attean::ListIterator->new(variables => [keys %vars], values => \@results, item_type => 'Attean::API::Result');
} elsif ($algebra->isa('Attean::Algebra::Filter')) {
# TODO: Merge adjacent filter evaluation so that they can share a row_cache hash (as is done for Extend above)
my $expr = $algebra->expression;
my $iter = $self->evaluate( $child, $active_graph );
return $iter->grep(sub {
my $t = $expr_eval->evaluate_expression( $expr, shift, $active_graph, {} );
# if ($@) { warn "Filter evaluation: $@\n" };
return ($t ? $t->ebv : 0);
});
} elsif ($algebra->isa('Attean::Algebra::OrderBy')) {
local($Attean::API::Binding::ALLOW_IRI_COMPARISON) = 1;
my $iter = $self->evaluate( $child, $active_graph );
my @rows = $iter->elements;
my @cmps = @{ $algebra->comparators };
my @exprs = map { $_->expression } @cmps;
my @dirs = map { $_->ascending } @cmps;
my @sorted = map { $_->[0] } sort {
my ($ar, $avalues) = @$a;
my ($br, $bvalues) = @$b;
my $c = 0;
foreach my $i (0 .. $#cmps) {
my ($av, $bv) = map { $_->[$i] } ($avalues, $bvalues);
# Mirrors code in Attean::Plan::OrderBy->sort_rows
if (blessed($av) and $av->does('Attean::API::Binding') and (not(defined($bv)) or not($bv->does('Attean::API::Binding')))) {
$c = 1;
} elsif (blessed($bv) and $bv->does('Attean::API::Binding') and (not(defined($av)) or not($av->does('Attean::API::Binding')))) {
$c = -1;
} else {
$c = eval { $av ? $av->order($bv) : 1 };
if ($@) {
$c = 1;
}
}
$c *= -1 if ($dirs[$i] == 0);
last unless ($c == 0);
}
$c
} map { my $r = $_; [$r, [map { $expr_eval->evaluate_expression( $_, $r, $active_graph, {} ) } @exprs]] } @rows;
return Attean::ListIterator->new( values => \@sorted, item_type => $iter->item_type, variables => $iter->variables);
} elsif ($algebra->isa('Attean::Algebra::Service')) {
my $endpoint = $algebra->endpoint->value;
my ($pattern) = @{ $algebra->children };
my $sparql = Attean::Algebra::Project->new( variables => [ map { variable($_) } $pattern->in_scope_variables ], children => [ $pattern ] )->as_sparql;
my $silent = $algebra->silent;
my $client = $self->new_service_client($endpoint, $silent);
return $client->query($sparql);
} elsif ($algebra->isa('Attean::Algebra::Graph')) {
my $graph = $algebra->graph;
return $self->evaluate($child, $graph) if ($graph->does('Attean::API::Term'));
my @iters;
my $graphs = $self->model->get_graphs();
my %vars;
while (my $g = $graphs->next) {
next if ($g->value eq $self->default_graph->value);
my $gr = Attean::Result->new( bindings => { $graph->value => $g } );
my $iter = $self->evaluate($child, $g)->map(sub { if (my $result = shift->join($gr)) { return $result } else { return } });
foreach my $v (@{ $iter->variables }) {
$vars{$v}++;
}
push(@iters, $iter);
}
return Attean::IteratorSequence->new( variables => [keys %vars], iterators => \@iters, item_type => 'Attean::API::Result' );
} elsif ($algebra->isa('Attean::Algebra::Group')) {
my @groupby = @{ $algebra->groupby };
my $iter = $self->evaluate($child, $active_graph);
my %groups;
while (my $r = $iter->next) {
my %vars;
my %row_cache;
my @group_terms = map { $expr_eval->evaluate_expression( $_, $r, $active_graph, \%row_cache ) } @groupby;
my $key = join(' ', map { blessed($_) ? $_->as_string : '' } @group_terms);
my %group_bindings;
foreach my $i (0 .. $#group_terms) {
my $v = $groupby[$i];
if (blessed($v) and $v->isa('Attean::ValueExpression') and $v->value->does('Attean::API::Variable') and $group_terms[$i]) {
$group_bindings{$v->value->value} = $group_terms[$i];
}
}
$groups{$key} = [Attean::Result->new( bindings => \%group_bindings ), []] unless (exists($groups{$key}));
push(@{ $groups{$key}[1] }, $r);
}
my @keys = keys %groups;
$groups{''} = [Attean::Result->new( bindings => {} ), []] if (scalar(@keys) == 0);
my $aggs = $algebra->aggregates;
my @results;
my %vars;
foreach my $key (keys %groups) {
my %row_cache;
my ($binding, $rows) = @{ $groups{$key} };
my $count = scalar(@$rows);
my %bindings;
foreach my $i (0 .. $#{ $aggs }) {
my $name = $aggs->[$i]->variable->value;
my $term = $expr_eval->evaluate_expression( $aggs->[$i], $rows, $active_graph, {} );
# warn "AGGREGATE error: $@" if ($@);
$vars{$name}++;
$bindings{ $name } = $term if ($term);
}
push(@results, Attean::Result->new( bindings => \%bindings )->join($binding));
}
return Attean::ListIterator->new(variables => [keys %vars], values => \@results, item_type => 'Attean::API::Result');
} elsif ($algebra->isa('Attean::Algebra::Join')) {
my ($lhs, $rhs) = map { $self->evaluate($_, $active_graph) } @children;
return $lhs->join($rhs);
lib/Attean/SimpleQueryEvaluator.pm view on Meta::CPAN
sub _ALP {
my $self = shift;
my $graph = shift;
my $term = shift;
my $path = shift;
my $v = shift;
return if (exists $v->{ $term->as_string });
$v->{ $term->as_string } = $term;
my $iter = $self->_eval($graph, $term, $path);
while (my $n = $iter->next) {
$self->_ALP($graph, $n, $path, $v);
}
}
sub _eval {
my $self = shift;
my $graph = shift;
my $term = shift;
my $path = shift;
my $pp = Attean::Algebra::Path->new( subject => $term, path => $path, object => variable('o') );
my $iter = $self->evaluate($pp, $graph);
my $terms = $iter->map(sub { shift->value('o') }, 'Attean::API::Term');
my %seen;
return $terms->grep(sub { not $seen{ shift->as_string }++ });
}
sub _zeroLengthPath {
my $self = shift;
my $s = shift;
my $o = shift;
my $graph = shift;
my $s_term = ($s->does('Attean::API::TermOrTriple'));
my $o_term = ($o->does('Attean::API::TermOrTriple'));
if ($s_term and $o_term) {
my @r;
push(@r, Attean::Result->new()) if ($s->equals($o));
return Attean::ListIterator->new(variables => [], values => \@r, item_type => 'Attean::API::Result');
} elsif ($s_term) {
my $name = $o->value;
my $r = Attean::Result->new( bindings => { $name => $s } );
return Attean::ListIterator->new(variables => [$name], values => [$r], item_type => 'Attean::API::Result');
} elsif ($o_term) {
my $name = $s->value;
my $r = Attean::Result->new( bindings => { $name => $o } );
return Attean::ListIterator->new(variables => [$name], values => [$r], item_type => 'Attean::API::Result');
} else {
my @vars = map { $_->value } ($s, $o);
my $nodes = $self->model->graph_nodes( $graph );
return $nodes->map(
sub {
my $term = shift;
Attean::Result->new( bindings => { map { $_ => $term } @vars } );
},
'Attean::API::Result',
variables => \@vars
);
}
}
=item C<< new_service_client( $endpoint, $silent ) >>
Returns a new Attean::SPARQLClient for use in evaluating queries using
the SPARQL Protocol against the given endpoint.
=cut
sub new_service_client {
my $self = shift;
my $endpoint = shift;
my $silent = shift;
my $client = Attean::SPARQLClient->new(
endpoint => $endpoint,
silent => $silent,
user_agent => $self->user_agent,
request_signer => $self->request_signer,
);
return $client;
}
}
package Attean::SimpleQueryEvaluator::ExpressionEvaluator 0.038 {
use Moo;
use Attean::RDF;
use Scalar::Util qw(blessed);
use Types::Standard qw(InstanceOf);
use URI::Escape qw(uri_escape_utf8);
use Encode qw(encode);
use POSIX qw(ceil floor);
use Digest;
use UUID::Tiny ':std';
use DateTime::Format::W3CDTF;
use I18N::LangTags;
use namespace::clean;
has 'evaluator' => (is => 'ro', isa => InstanceOf['Attean::SimpleQueryEvaluator']);
sub evaluate_expression {
my $self = shift;
my $expr = shift;
my $row = shift;
my $active_graph = shift;
my $row_cache = shift || {};
my $impl = $self->impl($expr, $active_graph);
my $result = eval { $impl->($row, row_cache => $row_cache) };
return $result;
}
sub impl {
my $self = shift;
my $expr = shift;
my $active_graph = shift;
my $op = $expr->operator;
my $true = Attean::Literal->true;
my $false = Attean::Literal->false;
if ($expr->isa('Attean::ExistsExpression')) {
my $pattern = $expr->pattern;
return sub {
my $r = shift;
my $table = Attean::Algebra::Table->new( variables => [map { variable($_) } $r->variables], rows => [$r] );
my $join = Attean::Algebra::Join->new( children => [$table, $pattern] );
# TODO: substitute variables at top-level of EXISTS pattern
my $iter = $self->evaluator->evaluate($join, $active_graph);
return ($iter->next) ? $true : $false;
};
} elsif ($expr->isa('Attean::ValueExpression')) {
my $node = $expr->value;
if ($node->does('Attean::API::Variable')) {
return sub { return shift->value($node->value); };
} else {
return sub { return $node };
}
} elsif ($expr->isa('Attean::UnaryExpression')) {
my ($child) = @{ $expr->children };
( run in 0.551 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )