Mailing List Archive

r3783 - trunk/perl/lib/KinoSearch/Docs/Cookbook
Author: creamyg
Date: 2008-08-28 15:20:16 -0700 (Thu, 28 Aug 2008)
New Revision: 3783

Modified:
trunk/perl/lib/KinoSearch/Docs/Cookbook/CustomQuery.pod
Log:
Refix CustomQuery Cookbook entry. Use $$self instead of refaddr($self) for
clarity, since $$self will soon be documented as part of the public API for
Obj.


Modified: trunk/perl/lib/KinoSearch/Docs/Cookbook/CustomQuery.pod
===================================================================
--- trunk/perl/lib/KinoSearch/Docs/Cookbook/CustomQuery.pod 2008-08-28 22:18:51 UTC (rev 3782)
+++ trunk/perl/lib/KinoSearch/Docs/Cookbook/CustomQuery.pod 2008-08-28 22:20:16 UTC (rev 3783)
@@ -7,13 +7,17 @@
Explore KinoSearch's support for custom query types by creating a
"PrefixQuery" class to handle trailing wildcards.

+ my $prefix_query = PrefixQuery->new(
+ field => 'content',
+ query_string => 'foo*',
+ );
+ my $hits = $searcher->search( query => $prefix_query );
+ ...
+
=head1 Query, Compiler, and Scorer

-To add our new query type, we need three classes in total: PrefixQuery,
-PrefixCompiler, and PrefixScorer. PrefixQuery on its own isn't enough because
-Query objects are mainly containers for metadata describing what to search
-for, and as such they can't do much -- they merely express a spec and leave
-the implementation of that spec to their companion classes.
+To add support for a new query type, we need three classes: a Query, a
+Compiler, and a Scorer.

=over

@@ -35,6 +39,11 @@

=back

+PrefixQuery on its own isn't enough because Query objects are mainly
+containers for metadata describing what to search for, and as such they can't
+do much -- they merely express a spec and leave the implementation of that
+spec to their companion classes.
+
Here's a simplified sketch illustrating how a Searcher's search() method ties
together the three classes.

@@ -53,14 +62,13 @@

package PrefixQuery;
use base qw( KinoSearch::Search::Query );
- use Scalar::Util qw( refaddr );
- use Carp qw( confess );
+ use Carp;

# Inside-out member vars and hand-rolled accessors.
my %query_string;
my %field;
- sub get_query_string { return $query_string{ refaddr($_[0]) }
- sub get_field { return $field{ refaddr($_[0]) }
+ sub get_query_string { my $self = shift; return $query_string{$$self} }
+ sub get_field { my $self = shift; return $field{$$self} }

PrefixQuery's constructor collects and validates the attributes.

@@ -69,15 +77,14 @@
my $query_string = delete $args{query_string};
my $field = delete $args{field};
my $self = $class->SUPER::new(%args);
- my $id = refaddr($self);

# Validate and assign required parameters.
- confess("'query_string' param is required")
+ confess("'query_string' param is required")
unless defined $query_string;
- confess("'field' param is required")
+ confess("'field' param is required")
unless defined $field;
- $query_string{$id} = $query_string;
- $field{$id} = $field;
+ $query_string{$$self} = $query_string;
+ $field{$$self} = $field;

# Only support trailing wildcards, i.e. "hous*" but not "hou*s".
confess("Invalid query_string: '$query_string'")
@@ -90,9 +97,8 @@

sub DESTROY {
my $self = shift;
- my $id = refaddr($self);
- delete $query_string{$id};
- delete $field{$id};
+ delete $query_string{$$self};
+ delete $field{$$self};
$self->SUPER::DESTROY;
}

@@ -128,15 +134,14 @@
term => 'foo',
);

-Such information can be used by the Compiler to assign more or less heft to
-individual queries or sub-queries. However, we're not going to bother with
-weighting for this demo; we'll just assign a fixed score of 1.0 to
-each matching document.
+Such information can be used by sophisticated Compiler implementations to
+assign more or less heft to individual queries or sub-queries. However, we're
+not going to bother with weighting for this demo; we'll just assign a fixed
+score of 1.0 to each matching document.

-We can inherit KinoSearch::Search::Compiler's constructor new(), as it will
-bless() the object into the supplied package name "PrefixCompiler" and we
-don't have any additional members or processing to add. The only method we
-need to implement for PrefixCompiler is make_scorer().
+We don't need to write a constructor, as it will suffice to inherit new() from
+KinoSearch::Search::Compiler. The only method we need to implement for
+PrefixCompiler is make_scorer().

package PrefixCompiler;
use base qw( KinoSearch::Search::Compiler );
@@ -185,7 +190,6 @@

package PrefixScorer;
use base qw( KinoSearch::Search::Scorer );
- use Scalar::Util qw( refaddr );

# Inside-out member vars.
my %doc_nums;
@@ -196,7 +200,6 @@
my ( $class, %args ) = @_;
my $posting_lists = delete $args{posting_lists};
my $self = $class->SUPER::new(%args);
- my $id = refaddr($self);

# Cheesy but simple way of interleaving PostingList doc sets.
my %all_doc_nums;
@@ -206,21 +209,20 @@
}
}
my @doc_nums = sort { $a <=> $b } keys %all_doc_nums;
- $doc_nums{$id} = \@doc_nums;
+ $doc_nums{$$self} = \@doc_nums;

- $tick{$id} = -1;
- $tally{$id} = KinoSearch::Search::Tally->new;
- $tally{$id}->set_score(1.0); # fixed score of 1.0
+ $tick{$$self} = -1;
+ $tally{$$self} = KinoSearch::Search::Tally->new;
+ $tally{$$self}->set_score(1.0); # fixed score of 1.0

return $self;
}

sub DESTROY {
my $self = shift;
- my $id = refaddr($self);
- delete $posting_lists{$id};
- delete $tick{$id};
- delete $tally{$id};
+ delete $posting_lists{$$self};
+ delete $tick{$$self};
+ delete $tally{$$self};
$self->SUPER::DESTROY;
}

@@ -231,21 +233,20 @@

sub next {
my $self = shift;
- my $id = refaddr($self);
- my $doc_nums = $doc_nums{$id};
- my $tick = ++$tick{$id};
+ my $doc_nums = $doc_nums{$$self};
+ my $tick = ++$tick{$$self};
return 0 if $tick >= scalar @$doc_nums;
return $doc_nums[$tick];
}

get_doc_num() returns the current document number, or 0 if the Scorer is
-exhausted. (Document numbers start at 1, so 0 is a sentinel.)
+exhausted. (L<Document numbers|KinoSearch::Docs::DocNums> start at 1, so 0 is
+a sentinel.)

sub get_doc_num {
my $self = shift;
- my $id = refaddr($self);
- my $tick = $tick{$id};
- my $doc_nums = $doc_nums{$id};
+ my $tick = $tick{$$self};
+ my $doc_nums = $doc_nums{$$self};
return $tick < scalar @doc_nums ? $doc_nums[$tick] : 0;
}

@@ -255,23 +256,18 @@

sub tally {
my $self = shift;
- my $id = refaddr($self);
- return $tally{$id};
+ return $tally{$$self};
}

=head1 CONCLUSION

-Using PrefixQuery is straightforward:
+To see PrefixQuery action, try feeding it the query string in the sample US
+constitution search.cgi app.

- my $prefix_query = PrefixQuery->new(
- field => 'content',
- query_string => 'foo*',
- );
- my $hits = $searcher->search( query => $prefix_query );
+If you're feeling ambitious, you can also try extending
+KinoSearch::QueryParser to support PrefixQuery, as described in
+L<KinoSearch::Docs::Cookbook::CustomQueryParser>.

-To see it in action, try feeding the query string in the sample US
-Constitution search app to PrefixQuery.
-
=head1 COPYRIGHT

Copyright 2008 Marvin Humphrey


_______________________________________________
kinosearch-commits mailing list
kinosearch-commits@rectangular.com
http://www.rectangular.com/mailman/listinfo/kinosearch-commits