package KinoSearch::Search::Scorer; use strict; use warnings; use KinoSearch::Util::ToolSet; use base qw( KinoSearch::Util::CClass Exporter ); BEGIN { __PACKAGE__->init_instance_vars( # constructor params similarity => undef, ); } our %instance_vars; our @EXPORT_OK = qw( %score_batch_args ); sub new { my $class = shift; verify_args( \%instance_vars, @_ ); my %args = ( %instance_vars, @_ ); $class = ref($class) || $class; my $self = _construct_parent($class); if ( defined $args{similarity} ) { $self->set_similarity( $args{similarity} ); } return $self; } our %score_batch_args = ( hit_collector => undef, start => 0, end => 2**31, ); =begin comment my $explanation = $scorer->explain($doc_num); Provide an Explanation for how this scorer rates a given doc. =end comment =cut sub explain { shift->abstract_death } 1; __END__ __XS__ MODULE = KinoSearch PACKAGE = KinoSearch::Search::Scorer void _construct_parent(class) char *class; PREINIT: Scorer *scorer; PPCODE: scorer = Kino_Scorer_new(); ST(0) = sv_newmortal(); sv_setref_pv(ST(0), class, (void*)scorer); XSRETURN(1); SV* _scorer_set_or_get(scorer, ...) Scorer *scorer; ALIAS: set_similarity = 1 get_similarity = 2 CODE: { KINO_START_SET_OR_GET_SWITCH case 1: SvREFCNT_dec(scorer->similarity_sv); scorer->similarity_sv = newSVsv( ST(1) ); Kino_extract_struct( scorer->similarity_sv, scorer->sim, Similarity*, "KinoSearch::Search::Similarity" ); /* fall through */ case 2: RETVAL = newSVsv(scorer->similarity_sv); break; KINO_END_SET_OR_GET_SWITCH } OUTPUT: RETVAL =begin comment my $score = $scorer->score; Calculate and return a score for the scorer's current document. =end comment =cut float score(scorer) Scorer* scorer; CODE: RETVAL = scorer->score(scorer); OUTPUT: RETVAL =begin comment my $valid_state = $scorer->next; Move the internal state of the scorer to the next document. Return false when there are no more documents to score. =end comment =cut bool next(scorer) Scorer* scorer; CODE: RETVAL = scorer->next(scorer); OUTPUT: RETVAL =begin comment $scorer->score_batch( hit_collector => $collector, start => $start, end => $end, ); Execute the scoring number crunching, accumulating results via the $hit_collector. TODO: Doesn't actually pay any attention to start/end at present. =end comment =cut void score_batch(scorer, ...) Scorer *scorer; PREINIT: HV *args_hash; U32 start, end; HitCollector *hc; PPCODE: /* process hash-style params */ Kino_Verify_build_args_hash(args_hash, "KinoSearch::Search::Scorer::score_batch_args", 1); Kino_extract_struct_from_hv(args_hash, hc, "hit_collector", 13, HitCollector*, "KinoSearch::Search::HitCollector"); start = (U32)SvUV( Kino_Verify_extract_arg(args_hash, "start", 5) ); end = (U32)SvUV( Kino_Verify_extract_arg(args_hash, "end", 3) ); /* execute scoring loop */ while (scorer->next(scorer)) { hc->collect( hc, scorer->doc(scorer), scorer->score(scorer) ); } =begin comment Not implemented yet. =end comment =cut bool skip_to(scorer, target_doc_num) Scorer* scorer; U32 target_doc_num; CODE: RETVAL = scorer->skip_to(scorer, target_doc_num); OUTPUT: RETVAL void DESTROY(scorer) Scorer *scorer; PPCODE: Kino_Scorer_destroy(scorer); __H__ #ifndef H_KINO_SCORER #define H_KINO_SCORER 1 #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "KinoSearchSearchSimilarity.h" #include "KinoSearchUtilMemManager.h" #include "KinoSearchUtilCarp.h" typedef struct scorer { void *child; Similarity *sim; float (*score)(struct scorer*); bool (*next)(struct scorer*); U32 (*doc)(struct scorer*); bool (*skip_to)(struct scorer*, U32); SV *similarity_sv; } Scorer; Scorer* Kino_Scorer_new(); float Kino_Scorer_score_death(Scorer*); bool Kino_Scorer_next_death(Scorer*); U32 Kino_Scorer_doc_death(Scorer*); bool Kino_Scorer_skip_to_death(Scorer*, U32); void Kino_Scorer_destroy(Scorer*); #endif /* include guard */ __C__ #include "KinoSearchSearchScorer.h" Scorer* Kino_Scorer_new() { Scorer* scorer; Kino_New(0, scorer, 1, Scorer); scorer->child = NULL; scorer->sim = NULL; scorer->next = Kino_Scorer_next_death; scorer->score = Kino_Scorer_score_death; scorer->skip_to = Kino_Scorer_skip_to_death; scorer->similarity_sv = &PL_sv_undef; return scorer; } float Kino_Scorer_score_death(Scorer* scorer) { Kino_confess("scorer->score must be defined in a subclass"); return 1.0; } bool Kino_Scorer_next_death(Scorer* scorer) { Kino_confess("scorer->next must be defined in a subclass"); return 1; } U32 Kino_Scorer_doc_death(Scorer* scorer) { Kino_confess("scorer->doc must be defined in a subclass"); return 1; } bool Kino_Scorer_skip_to_death(Scorer* scorer, U32 target_doc_num) { Kino_confess("scorer->skip_to must be defined in a subclass"); return 1; } void Kino_Scorer_destroy(Scorer* scorer) { SvREFCNT_dec(scorer->similarity_sv); Kino_Safefree(scorer); } __POD__ =begin devdocs =head1 NAME KinoSearch::Search::Scorer - score documents against a Query =head1 DESCRIPTION Abstract base class for scorers. Scorers iterate through a list of documents, producing score/doc_num pairs for further processing, typically by a HitCollector. =head1 COPYRIGHT Copyright 2005-2006 Marvin Humphrey =head1 LICENSE, DISCLAIMER, BUGS, etc. See L version 0.15. =end devdocs =cut