Changeset 2556
- Timestamp:
- 02/28/10 22:57:46 (2 years ago)
- Location:
- Search-Query-Dialect-KSx/trunk
- Files:
-
- 5 added
- 3 edited
-
Makefile.PL (modified) (1 diff)
-
lib/Search/Query/Dialect/KSx (added)
-
lib/Search/Query/Dialect/KSx.pm (modified) (4 diffs)
-
lib/Search/Query/Dialect/KSx/Compiler.pm (added)
-
lib/Search/Query/Dialect/KSx/NOTWildcardQuery.pm (added)
-
lib/Search/Query/Dialect/KSx/Scorer.pm (added)
-
lib/Search/Query/Dialect/KSx/WildcardQuery.pm (added)
-
t/01-parser.t (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
Search-Query-Dialect-KSx/trunk/Makefile.PL
r2552 r2556 3 3 use ExtUtils::MakeMaker; 4 4 5 my $MM_Version = $ExtUtils::MakeMaker::VERSION; 6 7 if ( $MM_Version =~ /_/ ) # dev version 8 { 9 $MM_Version = eval $MM_Version; 10 die $@ if ($@); 11 } 12 5 13 WriteMakefile( 6 NAME => 'Search::Query::Dialect::KSx',7 AUTHOR => q{Peter Karman <karman@cpan.org>},8 VERSION_FROM => 'lib/Search/Query/Dialect/KSx.pm',9 ABSTRACT_FROM => 'lib/Search/Query/Dialect/KSx.pm',10 ( $ExtUtils::MakeMaker::VERSION >= 6.300211 ? ('LICENSE'=> 'perl')12 : ()),13 PL_FILES => {},14 NAME => 'Search::Query::Dialect::KSx', 15 AUTHOR => q{Peter Karman <karman@cpan.org>}, 16 VERSION_FROM => 'lib/Search/Query/Dialect/KSx.pm', 17 ABSTRACT_FROM => 'lib/Search/Query/Dialect/KSx.pm', 18 ( $ExtUtils::MakeMaker::VERSION >= 6.3002 19 ? ( 'LICENSE' => 'perl' ) 20 : () ), 21 PL_FILES => {}, 14 22 PREREQ_PM => { 15 'Test::More' => 0, 23 'Test::More' => 0, 24 'Search::Query' => 0.08, 25 'KinoSearch' => 0.30_082, 16 26 }, 17 dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, 18 clean => { FILES => 'Search-Query-Dialect-KSx-*' }, 27 dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, 28 clean => { FILES => 'Search-Query-Dialect-KSx-*' }, 29 ( $MM_Version >= 6.48 ? ( MIN_PERL_VERSION => '5.8.3' ) : () ), 30 ( $MM_Version >= 6.31 ? ( LICENSE => 'perl' ) : () ), 31 ( $MM_Version <= 6.44 ? () 32 : ( META_MERGE => { 33 resources => { 34 license => 'http://dev.perl.org/licenses/', 35 homepage => 'http://perl.peknet.com/wiki/SearchTools', 36 bugtracker => 37 'http://rt.cpan.org/NoAuth/Bugs.html?Dist=Search-Query-Dialect-KSx', 38 repository => 39 'http://svn.peknet.com/perl/Search-Query-Dialect-KSx', 40 }, 41 } 42 ) 43 ), 44 19 45 ); -
Search-Query-Dialect-KSx/trunk/lib/Search/Query/Dialect/KSx.pm
r2552 r2556 6 6 use Data::Dump qw( dump ); 7 7 use Search::Query::Field::KSx; 8 use KinoSearch::Search::ANDQuery; 9 use KinoSearch::Search::NoMatchQuery; 10 use KinoSearch::Search::NOTQuery; 11 use KinoSearch::Search::ORQuery; 12 use KinoSearch::Search::PhraseQuery; 13 use KinoSearch::Search::RangeQuery; 14 use KinoSearch::Search::TermQuery; 15 use Search::Query::Dialect::KSx::NOTWildcardQuery; 16 use Search::Query::Dialect::KSx::WildcardQuery; 8 17 9 18 our $VERSION = '0.01'; … … 24 33 my $query = Search::Query->parser( dialect => 'KSx' )->parse('foo'); 25 34 print $query; 35 my $ks_query = $query->as_ks_query(); 36 my $hits = $ks_searcher->hits( query => $ks_query ); 26 37 27 38 =head1 DESCRIPTION 28 39 29 Search::Query::Dialect::KSx supports the KinoSearch::QueryParser syntax. 40 Search::Query::Dialect::KSx extends the KinoSearch::QueryParser syntax 41 to support wildcards, proximity and ranges, in addition to the standard 42 Search::Query features. 30 43 31 44 =head1 METHODS … … 149 162 = $clause->{field} 150 163 ? ( $clause->{field} ) 151 : ( @{ $default_field ? @$default_field : [] });164 : ( defined $default_field ? @$default_field : () ); 152 165 153 166 # what value … … 256 269 } 257 270 271 =head2 as_ks_query 272 273 Returns the Dialect object as a KinoSearch::Search::Query-based object. 274 The Dialect object is walked and converted to a 275 KinoSearch::Searcher-compatible tree. 276 277 =cut 278 279 sub as_ks_query { 280 my $self = shift; 281 my $tree = shift || $self; 282 283 my @q; 284 foreach my $prefix ( '+', '', '-' ) { 285 my @clauses; 286 my $joiner = $op_map{$prefix}; 287 next unless exists $tree->{$prefix}; 288 for my $clause ( @{ $tree->{$prefix} } ) { 289 push( @clauses, $self->_ks_clause( $clause, $prefix ) ); 290 } 291 next if !@clauses; 292 293 my $ks_class = 'KinoSearch::Search::' . $joiner . 'Query'; 294 295 push @q, @clauses == 1 296 ? $clauses[0] 297 : $ks_class->new( children => [ grep {defined} @clauses ] ); 298 } 299 300 return @q == 1 301 ? $q[0] 302 : KinoSearch::Search::ANDQuery->new( children => \@q ); 303 } 304 305 sub _ks_clause { 306 my $self = shift; 307 my $clause = shift; 308 my $prefix = shift; 309 310 #warn dump $clause; 311 #warn "prefix = '$prefix'"; 312 313 if ( $clause->{op} eq '()' ) { 314 return $self->as_ks_query( $clause->{value} ); 315 } 316 317 # make sure we have a field 318 my $default_field = $self->default_field || $self->parser->default_field; 319 my @fields 320 = $clause->{field} 321 ? ( $clause->{field} ) 322 : ( defined $default_field ? @$default_field : () ); 323 324 # what value 325 my $value 326 = ref $clause->{value} 327 ? $clause->{value} 328 : $self->_doctor_value($clause); 329 330 # if we have no fields, we can't proceed, because KS 331 # requires a field for every term. 332 if ( !@fields ) { 333 croak 334 "No field specified for term '$value' -- set a default_field in Parser or Dialect"; 335 } 336 337 my $wildcard = $self->wildcard; 338 339 # normalize operator 340 my $op = $clause->{op} || ":"; 341 if ( $op eq '=' ) { 342 $op = ':'; 343 } 344 if ( $prefix eq '-' ) { 345 $op = '!' . $op; 346 } 347 if ( $value =~ m/\%/ ) { 348 $op = $prefix eq '-' ? '!~' : '~'; 349 } 350 351 my $quote = $clause->quote || ''; 352 353 my @buf; 354 NAME: for my $name (@fields) { 355 my $field = $self->_get_field($name); 356 357 if ( defined $field->callback ) { 358 push( @buf, $field->callback->( $field, $op, $value ) ); 359 next NAME; 360 } 361 362 #warn dump [ $name, $op, $quote, $value ]; 363 364 # invert fuzzy 365 if ( $op eq '!~' || ( $op eq '!:' and $value =~ m/[$wildcard\*\?]/ ) ) 366 { 367 $value .= $wildcard unless $value =~ m/\Q$wildcard/; 368 369 push( 370 @buf, 371 Search::Query::Dialect::KSx::NOTWildcardQuery->new( 372 field => $name, 373 term => $value, 374 ) 375 ); 376 } 377 378 # fuzzy 379 elsif ( $op eq '~' 380 || ( $op eq ':' and $value =~ m/[$wildcard\*\?]/ ) ) 381 { 382 $value .= $wildcard unless $value =~ m/\Q$wildcard/; 383 384 push( 385 @buf, 386 Search::Query::Dialect::KSx::WildcardQuery->new( 387 field => $name, 388 term => $value, 389 ) 390 ); 391 } 392 393 # invert 394 elsif ( $op eq '!:' ) { 395 push( 396 @buf, 397 KinoSearch::Search::NOTQuery->new( 398 field => $name, 399 term => $value, 400 ) 401 ); 402 } 403 404 # range 405 elsif ( $op eq '..' ) { 406 if ( ref $value ne 'ARRAY' or @$value != 2 ) { 407 croak "range of values must be a 2-element ARRAY"; 408 } 409 410 my $range_query = KinoSearch::Search::RangeQuery->new( 411 field => $name, 412 lower_term => $value->[0], 413 upper_term => $value->[1], 414 include_lower => 1, 415 include_upper => 1, 416 ); 417 418 push( @buf, $range_query ); 419 420 } 421 422 # invert range 423 elsif ( $op eq '!..' ) { 424 if ( ref $value ne 'ARRAY' or @$value != 2 ) { 425 croak "range of values must be a 2-element ARRAY"; 426 } 427 428 croak "NOT Range query not yet supported"; 429 } 430 431 # standard 432 else { 433 push( 434 @buf, 435 KinoSearch::Search::TermQuery->new( 436 field => $name, 437 term => $value, 438 ) 439 ); 440 } 441 } 442 if ( @buf == 1 ) { 443 return $buf[0]; 444 } 445 my $joiner = $prefix eq '-' ? 'AND' : 'OR'; 446 my $ks_class = 'KinoSearch::Search::' . $joiner . 'Query'; 447 return $ks_class->new( children => \@buf ); 448 } 449 258 450 =head2 field_class 259 451 -
Search-Query-Dialect-KSx/trunk/t/01-parser.t
r2553 r2556 3 3 use strict; 4 4 use warnings; 5 use Test::More tests => 47;5 use Test::More tests => 53; 6 6 use Data::Dump qw( dump ); 7 7 … … 22 22 23 23 is( $query1, qq/foo:bar/, "query1 string" ); 24 25 ok( my $ks_query1 = $query1->as_ks_query(), "as_ks_query" ); 26 ok( $ks_query1->isa('KinoSearch::Search::TermQuery'), 27 "ks_query isa TermQuery" ); 24 28 25 29 ok( my $query2 = $parser->parse('foo:bar'), "query2" ); … … 181 185 ); 182 186 is( $query_alias_for2, qq/foo/, "query expanded omits aliases" ); 187 188 # wildcards 189 ok( my $fuzzy_parser = Search::Query->parser( 190 dialect => 'KSx', 191 query_class_opts => { default_field => 'field1' } 192 ), 193 "new fuzzy parser" 194 ); 195 ok( my $fuzzy_query = $fuzzy_parser->parse('foo*'), "parse foo*" ); 196 ok( my $fuzzy_ks = $fuzzy_query->as_ks_query, "fuzzy as_ks_query" ); 197 is( $fuzzy_ks->to_string, $fuzzy_query->stringify, 198 "stringification matches" );
Note: See TracChangeset
for help on using the changeset viewer.