| Plucene documentation | Contained in the Plucene distribution. |
Plucene::Search::BooleanScorer - A boolean scorer
# isa Plucene::Search::Scorer $bool_scorer->add($scorer, $required, $prohibited); $bool_scorer->score($results, $max_doc);
This is a scoring class for boolean scorers.
my $bool_scorer = Plucene::Search::BooleanScorer->new;
Create a new Plucene::Search::BooleanScorer object.
Get / set these attributes
$bool_scorer->add($scorer, $required, $prohibited);
$bool_scorer->score($results, $max_doc);
| Plucene documentation | Contained in the Plucene distribution. |
package Plucene::Search::BooleanScorer;
use strict; use warnings; use List::Util qw(min); use Plucene::Search::Similarity; use base qw(Plucene::Search::Scorer Class::Accessor::Fast); __PACKAGE__->mk_accessors( qw(next_mask required_mask prohibited_mask max_coord scorers bucket_table coord_factors current_doc) );
sub new { my $self = shift->SUPER::new(@_); $self->max_coord(1); $self->next_mask(1); $self->current_doc(0); $self->required_mask(0); $self->prohibited_mask(0); $self->scorers([]); $self->bucket_table(Plucene::Search::BucketTable->new({ scorer => $self })); return $self; }
sub add { my ($self, $scorer, $required, $prohibited) = @_; my $mask = 0; if ($required || $prohibited) { $mask = $self->next_mask; $self->{next_mask} <<= 1; } $self->{max_coord}++ unless $prohibited; $self->{prohibited_mask} |= $mask if $prohibited; $self->{required_mask} |= $mask if $required; push @{ $self->{scorers} }, { scorer => $scorer, required => $required, prohibited => $prohibited, collector => $self->bucket_table->new_collector($mask) }; } sub _compute_coord_factors { my $self = shift; $self->coord_factors([ map Plucene::Search::Similarity->coord($_, $self->max_coord), 0 .. $self->max_coord ]); }
sub score { my ($self, $results, $max_doc) = @_; $self->_compute_coord_factors if not defined $self->coord_factors; while ($self->current_doc < $max_doc) { $self->current_doc( min( $self->{current_doc} + $Plucene::Search::BucketTable::SIZE, $max_doc )); for my $t (@{ $self->{scorers} }) { $t->{scorer}->score($t->{collector}, $self->current_doc); } $self->bucket_table->collect_hits($results); } } package Plucene::Search::BucketTable; our $SIZE = 1 << 10; our $MASK = $SIZE - 1; use base 'Class::Accessor::Fast'; __PACKAGE__->mk_accessors(qw(buckets first scorer)); sub new { my $self = shift->SUPER::new(@_); $self->buckets([]); $self; } sub collect_hits { my ($self, $results) = @_; my $scorer = $self->scorer; my $required = $scorer->required_mask; my $prohibited = $scorer->prohibited_mask; my @coord = @{ $scorer->coord_factors }; for (my $bucket = $self->{first} ; $bucket ; $bucket = $bucket->{next}) { if ( ($bucket->{bits} & $prohibited) == 0 and ($bucket->{bits} & $required) == $required) { $results->collect($bucket->{doc}, $bucket->{score} * $coord[ $bucket->{coord} ]); } } undef $self->{first}; } sub new_collector { my ($self, $mask) = @_; return Plucene::Search::BucketCollector->new({ bucket_table => $self, mask => $mask }); } package Plucene::Search::BucketCollector; use base (qw(Class::Accessor::Fast Plucene::Search::HitCollector)); __PACKAGE__->mk_accessors(qw(bucket_table mask)); sub collect { my ($self, $doc, $score) = @_; my $table = $self->{bucket_table}; my $i = $doc & $Plucene::Search::BucketTable::MASK; my $bucket = $table->buckets->[$i]; $table->buckets->[$i] = $bucket = {} unless $bucket; if (not defined $bucket->{doc} or $bucket->{doc} != $doc) { @{$bucket}{qw(doc score bits coord)} = ($doc, $score, $self->{mask}, 1); $bucket->{next} = $table->first; $table->first($bucket); } else { $bucket->{score} += $score; $bucket->{bits} |= $self->{mask}; $bucket->{coord}++; } } 1;