use strict;
use warnings;
package KinoSearch::Search::RangeFilter;
use KinoSearch::Util::ToolSet;
use base qw( KinoSearch::Util::Class );
BEGIN {
__PACKAGE__->init_instance_vars(
# constructor params / members
field => undef,
lower_term => undef,
upper_term => undef,
include_lower => undef,
include_upper => undef,
);
}
use KinoSearch::Search::HitCollector;
sub init_instance {
my $self = shift;
for (qw( field lower_term upper_term include_lower include_upper )) {
confess("Missing required parameter $_")
unless defined $self->{$_};
}
}
sub make_collector {
my ( $self, $inner_coll, $searcher ) = @_;
confess("Can't get an ix_reader") unless $searcher->can('get_ix_reader');
my $ix_reader = $searcher->get_ix_reader;
my $sort_cache = $ix_reader->fetch_sort_cache( $self->{field} );
my $low_term
= KinoSearch::Index::Term->new( $self->{field}, $self->{lower_term} );
my $low_list = $ix_reader->field_terms($low_term);
my $lower = -2; # outside the range of IntMap's -1 default
if ( defined $low_list ) {
my $low_found = $low_list->get_term;
if ( defined $low_found ) {
$lower = $low_list->get_term_num;
if ( $low_term->equals($low_found) ) {
if ( !$self->{include_lower} ) {
$lower += 1;
}
}
}
}
my $high_term
= KinoSearch::Index::Term->new( $self->{field}, $self->{upper_term} );
my $high_list = $ix_reader->field_terms($high_term);
my $upper = -2;
if ( defined $high_list ) {
my $hi_found = $high_list->get_term;
if ( defined $hi_found ) {
$upper = $high_list->get_term_num;
if ( $high_term->equals($hi_found) ) {
if ( !$self->{include_upper} ) {
$upper -= 1;
}
}
else {
if ( !$self->{include_upper} ) {
$upper -= 1;
}
else {
$upper += 1;
}
}
}
}
return KinoSearch::Search::HitCollector->new_range_coll(
lower_bound => $lower,
upper_bound => $upper,
sort_cache => $sort_cache,
hit_collector => $inner_coll,
);
}
1;
__END__
=head1 NAME
KinoSearch::Search::RangeFilter - Filter search results by range of values.
=head1 SYNOPSIS
my $filter = KinoSearch::Search::RangeFilter->new(
field => 'date',
lower_term => '2000-01-01',
upper_term => '9999-01-01',
include_lower => 1,
include_upper => 1,
);
my $hits = $searcher->search(
query => $query,
filter => $filter,
);
=head1 DESCRIPTION
Range filter allows you to limit search results to documents where the value
for a particular field falls within a given range.
=head1 METHODS
=head2 new
my $filter = KinoSearch::Search::RangeFilter->new(
field => 'product_number', # required
lower_term => '003', # required
upper_term => '060', # required
include_lower => 1, # required
include_upper => 1, # required
);
Constructor. Takes 5 hash-style parameters, all of which are required.
=over
=item *
B<field> - The name of a field which is C<indexed> but not C<analyzed>.
=item *
B<lower_term> - Text string for the lower bound.
=item *
B<lower_term> - Text string for the upper bound.
=item *
B<include_lower> - indicate whether docs which match the lower bound should be
included in the results.
=item *
B<include_upper> - indicate whether docs which match the upper bound should be
included in the results.
=back
=head1 COPYRIGHT
Copyright 2007 Marvin Humphrey
=head1 LICENSE, DISCLAIMER, BUGS, etc.
See L<KinoSearch> version 0.20.
=cut