1 |
package CouchDB::Estraier; |
2 |
|
3 |
use strict; |
4 |
use warnings; |
5 |
|
6 |
use Search::Estraier; |
7 |
use Data::Dump qw/dump/; |
8 |
|
9 |
=head1 NAME |
10 |
|
11 |
CouchDB::Estraier - Hyper Estraier full-text search for CouchDB |
12 |
|
13 |
=head1 METHODS |
14 |
|
15 |
=cut |
16 |
|
17 |
our $c = { |
18 |
node_url => 'http://localhost:1978/node/', |
19 |
debug => 0, |
20 |
estuser => 'admin', |
21 |
estpasswd => 'admin', |
22 |
quiet => 0, |
23 |
FullTextSearchQueryServer => 0, |
24 |
DbUpdateNotificationProcess => 0, |
25 |
}; |
26 |
|
27 |
|
28 |
=head2 run |
29 |
|
30 |
Process command line options and start helper |
31 |
|
32 |
CouchDB::Estraier->run; |
33 |
|
34 |
=cut |
35 |
|
36 |
sub run { |
37 |
my $self = shift; |
38 |
GetOptions($c, qw/node_url=s debug+ quiet+ estuser=s estpasswd=s dbuser=s dbpasswd=s/) or die $!; |
39 |
warn "# c: ", dump($c) if ($c->{debug}); |
40 |
if ( $c->{FullTextSearchQueryServer} ) { |
41 |
while ( 1 ) { |
42 |
my $database = <>; |
43 |
my $query_string = <>; |
44 |
chomp $database; |
45 |
chomp $query_string; |
46 |
$self->search( $database, $query_string ); |
47 |
} |
48 |
} else { |
49 |
while ( 1 ) { |
50 |
my $database = <>; |
51 |
my $query_string = <>; |
52 |
chomp $database; |
53 |
chomp $query_string; |
54 |
$self->add( $database, $query_string ); |
55 |
} |
56 |
} |
57 |
} |
58 |
|
59 |
|
60 |
=head2 add |
61 |
|
62 |
CouchDB::Estraier->add( $database, $data ); |
63 |
|
64 |
=cut |
65 |
|
66 |
sub add { |
67 |
my ( $self, $database, $data ) = @_; |
68 |
|
69 |
# create and configure node |
70 |
my $node = new Search::Estraier::Node( |
71 |
url => $c->{node_url} . $database, |
72 |
user => $c->{estuser}, |
73 |
passwd => $c->{estpasswd}, |
74 |
croak_on_error => 1, |
75 |
create => 1, |
76 |
debug => $c->{debug} >= 4 ? 1 : 0, |
77 |
); |
78 |
|
79 |
# create document |
80 |
my $doc = new Search::Estraier::Document; |
81 |
|
82 |
if (my $id = $data->{_id}) { |
83 |
$doc->add_attr('@uri', $id); |
84 |
} else { |
85 |
die "can't find pk_col column _id in results\n"; |
86 |
} |
87 |
|
88 |
while (my ($col,$val) = each %{$data}) { |
89 |
|
90 |
if ($val) { |
91 |
# add attributes (make column usable from attribute search) |
92 |
$doc->add_attr($col, $val); |
93 |
|
94 |
# add body text to document (make it searchable using full-text index) |
95 |
$doc->add_text($val); |
96 |
} |
97 |
|
98 |
} |
99 |
|
100 |
warn "# doc draft: ",$doc->dump_draft, "\n" if ($c->{debug} >= 2); |
101 |
|
102 |
die "error: ", $node->status,"\n" unless (eval { $node->put_doc($doc) }); |
103 |
|
104 |
} |
105 |
|
106 |
=head2 search |
107 |
|
108 |
Implementation specification: L<http://wiki.apache.org/couchdb/FullTextSearch> |
109 |
|
110 |
CouchDB::Estraier->search( $database, $query ); |
111 |
|
112 |
=cut |
113 |
|
114 |
sub search { |
115 |
my ( $self, $database, $query ) = @_; |
116 |
|
117 |
# create and configure node |
118 |
my $node = new Search::Estraier::Node( |
119 |
url => $c->{node_url} . $database, |
120 |
user => $c->{estuser}, |
121 |
passwd => $c->{estpasswd}, |
122 |
croak_on_error => 1, |
123 |
create => 1, |
124 |
debug => $c->{debug} >= 4 ? 1 : 0, |
125 |
); |
126 |
|
127 |
my $cond = new Search::Estraier::Condition; |
128 |
$cond->set_phrase( $query ); |
129 |
my $nres = $node->search($cond, 0); |
130 |
|
131 |
if ( defined($nres) ) { |
132 |
|
133 |
print "ok\n"; |
134 |
for my $i ( 0 ... $nres->doc_num - 1 ) { |
135 |
my $rdoc = $nres->get_doc($i); |
136 |
print $rdoc->attr('@uri'),"\n",$i,"\n"; |
137 |
} |
138 |
print "\n\n"; |
139 |
|
140 |
} else { |
141 |
print "error\n", $node->status, "\n"; |
142 |
} |
143 |
|
144 |
|
145 |
} |
146 |
|
147 |
|
148 |
1; |