/[Grep]/lib/Grep/Search/KinoSearch.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /lib/Grep/Search/KinoSearch.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

lib/Grep/Search.pm revision 151 by dpavlin, Sat Jun 9 10:27:03 2007 UTC lib/Grep/Search/KinoSearch.pm revision 190 by dpavlin, Fri May 23 21:05:42 2008 UTC
# Line 1  Line 1 
1  package Grep::Search;  package Grep::Search::KinoSearch;
2    
3  use strict;  use strict;
4  use warnings;  use warnings;
 use base qw( Class::Accessor );  
 Grep::Search->mk_accessors( qw( invindexer create index_path hits ) );  
5    
6  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
7  use KinoSearch::InvIndexer;  use KinoSearch::InvIndexer;
8  use KinoSearch::Searcher;  use KinoSearch::Searcher;
9  use Jifty::Util;  use Jifty::Util;
10    
11  my $debug = 0;  my $debug = 1;
12    
13  =head1 NAME  =head1 NAME
14    
15  Grep::Search - full text search using L<KinoSearch>  Grep::Search::KinoSearch - full text search using L<KinoSearch>
16    
17  =head1 METHODS  =head1 METHODS
18    
 =head2 new  
   
   my $search = Grep::Search->new();  
   
   my $search = Grep::Search->new( create => 1 );  
   
19  =head2 invindexer  =head2 invindexer
20    
21  Accessor to call any method defined on L<KinoSearch::InvIndexer>  Accessor to call any method defined on L<KinoSearch::InvIndexer>
# Line 32  Accessor to call any method defined on L Line 24  Accessor to call any method defined on L
24    
25  =cut  =cut
26    
27  sub log { Jifty->web->log }  our $indexes;
   
 sub new {  
         my $class = shift;          
         my $self = $class->SUPER::new(@_);  
28    
29    sub invindexer {
30            my $self = shift;
31            my $invindexer;
32          my $index_path = Jifty::Util->app_root . '/var/invindex';          my $index_path = Jifty::Util->app_root . '/var/invindex';
33    
34          $self->index_path( $index_path );          if ( $invindexer = $indexes->{$index_path} ) {
35                    $self->log->debug("Using cached index $index_path");
         if ( ! -e "$index_path" || $self->create ) {  
                 $self->log->debug("Creating new index $index_path");  
                 $self->invindexer( KinoSearch::InvIndexer->new( invindex => Grep::Search::Schema->clobber( $index_path ) ) );  
36          } else {          } else {
37                  $self->log->debug("Opening index: $index_path");                  if ( $self->create || -e $index_path ) {
38                  $self->invindexer( KinoSearch::InvIndexer->new( invindex => Grep::Search::Schema->open( $index_path ) ) );                          $self->log->debug("Creating new index $index_path");
39                            $invindexer = KinoSearch::InvIndexer->new( invindex => Grep::Search::KinoSearch::Schema->clobber( $index_path ) )
40                                    or die "can't create index $index_path: $!";
41                            $self->create( 0 );
42                    } else {
43                            $self->log->debug("Opening index: $index_path");
44                            $invindexer = KinoSearch::InvIndexer->new( invindex => Grep::Search::KinoSearch::Schema->open( $index_path ) )
45                                    or die "can't open index $index_path: $!";
46                    }
47                    $indexes->{$index_path} = $invindexer;
48          }          }
49    
50          return $self;          return $invindexer;
51  }  }
52    
53  =head2 add  =head2 add
54    
55    $search->add( $record, $owner_id );    $search->add( $doc_hash );
56    
57  =cut  =cut
58    
59  sub add {  sub add {
60          my $self = shift;          my $self = shift;
61            my $doc = shift;
         my $i = shift or die "no record to add";  
         my $uid = shift;  
   
         die "record not Jifty::Record but ", ref $i unless ($i->isa('Jifty::Record'));  
   
         my $pk = { $i->primary_keys };  
   
         my $doc;  
   
         my @columns = map { $_->name } $i->columns;  
   
         foreach my $c ( @columns ) {  
   
                 my $v = $i->$c;  
   
                 if ( ref($v) ne '' ) {  
   
                         foreach my $f_c ( qw/id name title/ ) {  
                                 if ( $i->$c->can( $f_c ) ) {  
                                         my $f_v = $i->$c->$f_c || $i->$c->{values}->{ $f_c };  
                                         my $col = $c . '_' . $f_c;  
                                         if ( $f_v ) {  
                                                 warn "  # $col = $f_v\n" if ($debug);  
                                                 $doc->{ $col } = $f_v;  
                                         } else {  
                                                 warn "  . $col is NULL\n" if ($debug);  
                                         }  
                                 }  
                         }  
   
                         if ($v->isa('Jifty::DateTime')) {  
                                 warn "  d $c = $v\n" if ($debug);  
                                 $doc->{$c} = $v;  
                         } else {  
                                 warn "  s $c = $v [",ref($v),"]\n" if ($debug);  
                         }  
                         next;  
                 }  
   
                 next if (! defined($v) || $v eq '');  
   
                 $v =~ s/<[^>]+>/ /gs;  
   
                 if ( defined( $pk->{$c} ) ) {  
                         $doc->{ $c } = $v;  
                         warn "  * $c = $v\n" if ($debug);  
                 } else {  
                         $doc->{ $c } = $v;  
                         warn "  + $c = ", $self->snippet( 50, $v ), "\n" if ($debug);  
                 }  
         }  
   
         # add _owner_id to speed up filtering of search results  
         $uid ||= Jifty->web->current_user->id;  
         $doc->{ '_owner_id' } = $uid;  
   
62          $self->invindexer->add_doc( $doc );          $self->invindexer->add_doc( $doc );
   
         $self->log->debug("added ", $i->id, " for user $uid to index");  
   
63          return 1;          return 1;
64  }  }
65    
66  =head2 collection  =head2 search
   
 Return C<Grep::Model::ItemCollection> which is result of C<search query>  
   
   my $ItemCollection = $search->collection( 'search query' );  
   
 =head2 hits  
   
 Return number of results from last C<collection> call  
67    
68    my $num_results = $search->hits;    my $fetch_hit_coderef = $self->search('search query');
69    
70  =cut  =cut
71    
72  sub collection {  sub search {
73          my $self = shift;          my $self = shift;
74    
75          my $q = shift or die "no q?";          my $q = shift or die "no q?";
76    
77            my $index_path = Jifty::Util->app_root . '/var/invindex';
78          my $searcher = KinoSearch::Searcher->new(          my $searcher = KinoSearch::Searcher->new(
79                  invindex => Grep::Search::Schema->open( $self->index_path ), );                  invindex => Grep::Search::KinoSearch::Schema->open( $index_path ), );
80          $self->log->debug("$searcher created");          $self->log->debug("$searcher created");
81    
82          my $full_q = "($q)";          my $full_q = "($q)";
83    
84          my $uid = Jifty->web->current_user->id;          my $uid = Jifty->web->current_user->id;
85          $full_q .= ' AND _owner_id:' . $uid if ($uid);          $full_q .= ' AND _owner_id:' . $uid if (defined $uid);
86    
87          $self->log->debug("searching for '$q' using $full_q");          $self->log->debug("searching for '$q' using $full_q");
88    
89            my $query_parser = KinoSearch::QueryParser->new(
90                    schema => Grep::Search::KinoSearch::Schema->new,
91                    fields => [ qw/ title link content summary category author / ],
92            );
93            $query_parser->set_heed_colons(1);       # enable field:value AND/OR/NOT syntax
94            my $query = $query_parser->parse( $full_q );
95          my $hits = $searcher->search(          my $hits = $searcher->search(
96                  query           => $full_q,                  query           => $query,
97  #               offset          => $offset,  #               offset          => $offset,
98  #               num_wanted      => $hits_per_page,  #               num_wanted      => $hits_per_page,
99          );          );
100    
101          $self->hits( $hits->total_hits );          $self->hits( $hits->total_hits );
102    
103          $self->log->debug("found ", $self->hits, " results");          return sub {
104                    return $hits->fetch_hit;
105          my $collection = Grep::Model::ItemCollection->new();          };
   
         my @results;  
   
         my $i = 0;  
         while ( my $hit = $hits->fetch_hit_hashref ) {  
   
                 my $score = $hit->{score};  
                 my $title = $hit->{title};  
                 my $id = $hit->{id};  
   
                 $self->log->debug("result $i [$id] $title $score");  
   
                 my $item = Grep::Model::Item->new();  
                 my ($ok,$msg) = $item->load_by_cols( id => $id );  
   
                 if ( $ok ) {  
                         $collection->add_record( $item );  
                 } else {  
                         warn "can't load item $id\n";  
                 }  
   
         }  
   
         $self->log->debug("finished search");  
   
         return $collection;  
106  }  }
107    
108  =head2 finish  =head2 finish
# Line 213  sub finish { Line 125  sub finish {
125          return 1;          return 1;
126  }  }
127    
128  =head2 snippet  package Grep::Search::KinoSearch::KeywordField;
   
   my $short = $self->snippet( 50, $text );  
   
 =cut  
   
 sub snippet {  
         my $self = shift;  
   
         my $len = shift or die "no len?";  
         my $m = join(" ", @_);  
   
         $m =~ s/\s+/ /gs;  
   
         if (length($m) > $len) {  
                 return substr($m,0,$len) . '...';  
         } else {  
                 return $m;  
         }  
 }  
   
 package Grep::Search::KeywordField;  
129  use base qw( KinoSearch::Schema::FieldSpec );  use base qw( KinoSearch::Schema::FieldSpec );
130  sub analyzed { 0 }  sub analyzed { 0 }
131    #sub indexed { 1 }
132    #sub stored { 1 }
133    sub vectorized { 0 }
134    
135  package Grep::Search::Schema;  package Grep::Search::KinoSearch::Schema;
136    
137  =head1 NAME  =head1 NAME
138    
139  Grep::Search::Schema - schema definition for full-text search  Grep::Search::KinoSearch::Schema - schema definition for full-text search
140    
141  =cut  =cut
142    
# Line 250  use base 'KinoSearch::Schema'; Line 144  use base 'KinoSearch::Schema';
144  use KinoSearch::Analysis::PolyAnalyzer;  use KinoSearch::Analysis::PolyAnalyzer;
145    
146  our %fields = (  our %fields = (
147          id                              => 'Grep::Search::KeywordField',          id                              => 'Grep::Search::KinoSearch::KeywordField',
148    
149          in_feed_id              => 'Grep::Search::KeywordField',          in_feed_id              => 'Grep::Search::KinoSearch::KeywordField',
150          in_feed_url             => 'Grep::Search::KeywordField',          in_feed_url             => 'Grep::Search::KinoSearch::KeywordField',
151          in_feed_title   => 'KinoSearch::Schema::FieldSpec',          in_feed_title   => 'KinoSearch::Schema::FieldSpec',
152          in_feed_owner   => 'Grep::Search::KeywordField',          in_feed_owner   => 'Grep::Search::KinoSearch::KeywordField',
153          in_feed_created_on      => 'Grep::Search::KeywordField',          in_feed_created_on      => 'Grep::Search::KinoSearch::KeywordField',
154    
155          title                   => 'KinoSearch::Schema::FieldSpec',          title                   => 'KinoSearch::Schema::FieldSpec',
156          link                    => 'Grep::Search::KeywordField',          link                    => 'Grep::Search::KinoSearch::KeywordField',
157          content                 => 'KinoSearch::Schema::FieldSpec',          content                 => 'KinoSearch::Schema::FieldSpec',
158          summary                 => 'KinoSearch::Schema::FieldSpec',          summary                 => 'KinoSearch::Schema::FieldSpec',
159          category                => 'KinoSearch::Schema::FieldSpec',          category                => 'KinoSearch::Schema::FieldSpec',
160          author                  => 'KinoSearch::Schema::FieldSpec',          author                  => 'KinoSearch::Schema::FieldSpec',
161          issued                  => 'Grep::Search::KeywordField',          created_on              => 'Grep::Search::KinoSearch::KeywordField',
162          modified                => 'Grep::Search::KeywordField',          last_update             => 'Grep::Search::KinoSearch::KeywordField',
163    
164          _owner_id               => 'Grep::Search::KeywordField',          _owner_id               => 'Grep::Search::KinoSearch::KeywordField',
165  );  );
166    
167  sub analyzer {  sub analyzer {

Legend:
Removed from v.151  
changed lines
  Added in v.190

  ViewVC Help
Powered by ViewVC 1.1.26