Changeset 2556


Ignore:
Timestamp:
02/28/10 22:57:46 (2 years ago)
Author:
karpet
Message:

add docs and prelim tests

Location:
Search-Query-Dialect-KSx/trunk
Files:
5 added
3 edited

Legend:

Unmodified
Added
Removed
  • Search-Query-Dialect-KSx/trunk/Makefile.PL

    r2552 r2556  
    33use ExtUtils::MakeMaker; 
    44 
     5my $MM_Version = $ExtUtils::MakeMaker::VERSION; 
     6 
     7if ( $MM_Version =~ /_/ )    # dev version 
     8{ 
     9    $MM_Version = eval $MM_Version; 
     10    die $@ if ($@); 
     11} 
     12 
    513WriteMakefile( 
    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.3002 
    11       ? ('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  => {}, 
    1422    PREREQ_PM => { 
    15         'Test::More' => 0, 
     23        'Test::More'    => 0, 
     24        'Search::Query' => 0.08, 
     25        'KinoSearch'    => 0.30_082, 
    1626    }, 
    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 
    1945); 
  • Search-Query-Dialect-KSx/trunk/lib/Search/Query/Dialect/KSx.pm

    r2552 r2556  
    66use Data::Dump qw( dump ); 
    77use Search::Query::Field::KSx; 
     8use KinoSearch::Search::ANDQuery; 
     9use KinoSearch::Search::NoMatchQuery; 
     10use KinoSearch::Search::NOTQuery; 
     11use KinoSearch::Search::ORQuery; 
     12use KinoSearch::Search::PhraseQuery; 
     13use KinoSearch::Search::RangeQuery; 
     14use KinoSearch::Search::TermQuery; 
     15use Search::Query::Dialect::KSx::NOTWildcardQuery; 
     16use Search::Query::Dialect::KSx::WildcardQuery; 
    817 
    918our $VERSION = '0.01'; 
     
    2433 my $query = Search::Query->parser( dialect => 'KSx' )->parse('foo'); 
    2534 print $query; 
     35 my $ks_query = $query->as_ks_query(); 
     36 my $hits = $ks_searcher->hits( query => $ks_query ); 
    2637 
    2738=head1 DESCRIPTION 
    2839 
    29 Search::Query::Dialect::KSx supports the KinoSearch::QueryParser syntax. 
     40Search::Query::Dialect::KSx extends the KinoSearch::QueryParser syntax 
     41to support wildcards, proximity and ranges, in addition to the standard 
     42Search::Query features. 
    3043 
    3144=head1 METHODS 
     
    149162        = $clause->{field} 
    150163        ? ( $clause->{field} ) 
    151         : ( @{ $default_field ? @$default_field : [] } ); 
     164        : ( defined $default_field ? @$default_field : () ); 
    152165 
    153166    # what value 
     
    256269} 
    257270 
     271=head2 as_ks_query 
     272 
     273Returns the Dialect object as a KinoSearch::Search::Query-based object. 
     274The Dialect object is walked and converted to a  
     275KinoSearch::Searcher-compatible tree. 
     276 
     277=cut 
     278 
     279sub 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 
     305sub _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; 
     354NAME: 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 
    258450=head2 field_class 
    259451 
  • Search-Query-Dialect-KSx/trunk/t/01-parser.t

    r2553 r2556  
    33use strict; 
    44use warnings; 
    5 use Test::More tests => 47; 
     5use Test::More tests => 53; 
    66use Data::Dump qw( dump ); 
    77 
     
    2222 
    2323is( $query1, qq/foo:bar/, "query1 string" ); 
     24 
     25ok( my $ks_query1 = $query1->as_ks_query(), "as_ks_query" ); 
     26ok( $ks_query1->isa('KinoSearch::Search::TermQuery'), 
     27    "ks_query isa TermQuery" ); 
    2428 
    2529ok( my $query2 = $parser->parse('foo:bar'), "query2" ); 
     
    181185); 
    182186is( $query_alias_for2, qq/foo/, "query expanded omits aliases" ); 
     187 
     188# wildcards 
     189ok( my $fuzzy_parser = Search::Query->parser( 
     190        dialect          => 'KSx', 
     191        query_class_opts => { default_field => 'field1' } 
     192    ), 
     193    "new fuzzy parser" 
     194); 
     195ok( my $fuzzy_query = $fuzzy_parser->parse('foo*'), "parse foo*" ); 
     196ok( my $fuzzy_ks    = $fuzzy_query->as_ks_query,    "fuzzy as_ks_query" ); 
     197is( $fuzzy_ks->to_string, $fuzzy_query->stringify, 
     198    "stringification matches" ); 
Note: See TracChangeset for help on using the changeset viewer.