/[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 47 by dpavlin, Wed Feb 21 03:04:48 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;
5    
6  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
7  use Lucene;  use KinoSearch::InvIndexer;
8    use KinoSearch::Searcher;
9  use Jifty::Util;  use Jifty::Util;
10    
11  my $index_path = Jifty::Util->app_root . '/var/lucene';  my $debug = 1;
12    
13  my ( $analyzer, $store, $writer );  =head1 NAME
14    
15  my $debug = 0;  Grep::Search::KinoSearch - full text search using L<KinoSearch>
16    
17  sub reopen_index {  =head1 METHODS
         my $self = shift;  
18    
19          $analyzer ||= new Lucene::Analysis::Standard::StandardAnalyzer();  =head2 invindexer
         my $create = 0;  
         if (! -e "$index_path/segments") {  
                 $create = 1;  
                 Jifty->log->debug("creating index $index_path") unless ($store);  
         } else {  
                 Jifty->log->debug("using index: $index_path") unless ($store);  
         }  
         $store ||= Lucene::Store::FSDirectory->getDirectory( $index_path, $create );  
 }  
20    
21  =head2 add  Accessor to call any method defined on L<KinoSearch::InvIndexer>
22    
23    Grep::Search->add( $record );    $search->invindexer->delete_by_term( 'id', 42 );
24    
25  =cut  =cut
26    
27  sub add {  our $indexes;
         my $self = shift;  
   
         my $i = shift or die "no record to add";  
   
         die "record not Jifty::Record but ", ref $i unless ($i->isa('Jifty::Record'));  
   
         $self->reopen_index;  
   
         $writer ||= new Lucene::Index::IndexWriter( $store, $analyzer, 0 );  
   
         my $pk = { $i->primary_keys };  
   
         my $doc = new Lucene::Document;  
28    
29          my @columns = map { $_->name } $i->columns;  sub invindexer {
30            my $self = shift;
31          foreach my $c ( @columns ) {          my $invindexer;
32            my $index_path = Jifty::Util->app_root . '/var/invindex';
                 my $v = $i->$c;  
   
                 if ( ref($v) ne '' ) {  
                         if ($i->$c->can('id')) {  
                                 $v = $i->$c->id;  
                                 warn "  # $c = $v [id]\n" if ($debug);  
                                 $doc->add(Lucene::Document::Field->Keyword( $c, $v ));  
                         } elsif ($v->isa('Jifty::DateTime')) {  
                                 warn "  d $c = $v\n" if ($debug);  
                                 $doc->add(Lucene::Document::Field->Keyword( $c, "$v" ));  
                         } else {  
                                 warn "  s $c = $v [",ref($v),"]\n" if ($debug);  
                         }  
                         next;  
                 }  
   
                 next if (! defined($v) || $v eq '');  
   
                 $v =~ s/<[^>]+>/ /gs;  
33    
34                  if ( defined( $pk->{$c} ) ) {          if ( $invindexer = $indexes->{$index_path} ) {
35                          $doc->add(Lucene::Document::Field->Keyword( $c, $v ));                  $self->log->debug("Using cached index $index_path");
36                          warn "  * $c = $v\n" if ($debug);          } else {
37                    if ( $self->create || -e $index_path ) {
38                            $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 {                  } else {
43                          $doc->add(Lucene::Document::Field->Text( $c, $v ));                          $self->log->debug("Opening index: $index_path");
44                          warn "  + $c = $v\n" if ($debug);                          $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          $writer->addDocument($doc);          return $invindexer;
   
         Jifty->log->debug("added ", $i->id, " to index");  
51  }  }
52    
53  =head2  =head2 add
54    
55    my $ItemCollection = Grep::Search->collection( 'search query' );    $search->add( $doc_hash );
56    
57  =cut  =cut
58    
59  sub collection {  sub add {
60          my $self = shift;          my $self = shift;
61            my $doc = shift;
62            $self->invindexer->add_doc( $doc );
63            return 1;
64    }
65    
66          my $q = shift or die "no q?";  =head2 search
67    
68          $self->reopen_index;    my $fetch_hit_coderef = $self->search('search query');
69    
70          my $searcher = new Lucene::Search::IndexSearcher($store);  =cut
         my $parser = new Lucene::QueryParser("content", $analyzer);  
         my $query = $parser->parse( $q );  
71    
72          Jifty->log->debug("searching for '$q'");  sub search {
73            my $self = shift;
74    
75          my $hits = $searcher->search($query);          my $q = shift or die "no q?";
         my $num_hits = $hits->length();  
76    
77          Jifty->log->debug("found $num_hits results");          my $index_path = Jifty::Util->app_root . '/var/invindex';
78            my $searcher = KinoSearch::Searcher->new(
79                    invindex => Grep::Search::KinoSearch::Schema->open( $index_path ), );
80            $self->log->debug("$searcher created");
81    
82            my $full_q = "($q)";
83    
84            my $uid = Jifty->web->current_user->id;
85            $full_q .= ' AND _owner_id:' . $uid if (defined $uid);
86    
87            $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(
96                    query           => $query,
97    #               offset          => $offset,
98    #               num_wanted      => $hits_per_page,
99            );
100    
101            $self->hits( $hits->total_hits );
102    
103            return sub {
104                    return $hits->fetch_hit;
105            };
106    }
107    
108          my $collection = Grep::Model::ItemCollection->new();  =head2 finish
109    
110          my @results;    $search->finish
111    
112          for ( my $i = 0; $i < $num_hits; $i++ ) {  =cut
113    
114                  my $doc = $hits->doc( $i );  sub finish {
115            my $self = shift;
116            if ($self->invindexer) {
117                    $self->log->debug("closing index");
118                    $self->invindexer->finish;
119            }
120    
121                  my $score = $hits->score($i);          $self->log->debug("finish");
                 my $title = $doc->get("title");  
                 my $id = $doc->get("id");  
122    
123                  warn "## $i $score $title\n";          undef $self;
124    
125                  my $item = Grep::Model::Item->new();          return 1;
126                  my ($ok,$msg) = $item->load_by_cols( id => $id );  }
127    
128                  if ( $ok ) {  package Grep::Search::KinoSearch::KeywordField;
129                          $collection->add_record( $item );  use base qw( KinoSearch::Schema::FieldSpec );
130                  } else {  sub analyzed { 0 }
131                          warn "can't load item $id\n";  #sub indexed { 1 }
132                  }  #sub stored { 1 }
133    sub vectorized { 0 }
134    
135          }  package Grep::Search::KinoSearch::Schema;
136    
137          undef $hits;  =head1 NAME
         undef $query;  
         undef $parser;  
         undef $searcher;  
138    
139          return $collection;  Grep::Search::KinoSearch::Schema - schema definition for full-text search
 }  
140    
141  =head2 finish  =cut
142    
143    Grep::Search->finish  use base 'KinoSearch::Schema';
144    use KinoSearch::Analysis::PolyAnalyzer;
145    
146  =cut  our %fields = (
147            id                              => 'Grep::Search::KinoSearch::KeywordField',
148    
149  sub finish {          in_feed_id              => 'Grep::Search::KinoSearch::KeywordField',
150          my $self = shift;          in_feed_url             => 'Grep::Search::KinoSearch::KeywordField',
151          if ($writer) {          in_feed_title   => 'KinoSearch::Schema::FieldSpec',
152                  warn "closing index\n";          in_feed_owner   => 'Grep::Search::KinoSearch::KeywordField',
153                  $writer->close;          in_feed_created_on      => 'Grep::Search::KinoSearch::KeywordField',
154          }  
155          undef $writer;          title                   => 'KinoSearch::Schema::FieldSpec',
156  }          link                    => 'Grep::Search::KinoSearch::KeywordField',
157            content                 => 'KinoSearch::Schema::FieldSpec',
158            summary                 => 'KinoSearch::Schema::FieldSpec',
159            category                => 'KinoSearch::Schema::FieldSpec',
160            author                  => 'KinoSearch::Schema::FieldSpec',
161            created_on              => 'Grep::Search::KinoSearch::KeywordField',
162            last_update             => 'Grep::Search::KinoSearch::KeywordField',
163    
164  sub _signal {          _owner_id               => 'Grep::Search::KinoSearch::KeywordField',
165          my $s = shift;  );
         warn "catched SIG $s\n";  
         finish();  
         exit(0);  
 }  
166    
167  $SIG{'__DIE__'} = \&_signal;  sub analyzer {
168  $SIG{'INT'} = \&_signal;          return KinoSearch::Analysis::PolyAnalyzer->new( language => 'en' );
169  $SIG{'QUIT'} = \&_signal;  }
170    
171  1;  1;

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

  ViewVC Help
Powered by ViewVC 1.1.26