X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FSearch.pm;h=b739faf1a50c7eae1ae781078a0621fa71e648c4;hb=6e0659d2ae455fb28d433fd8c71b563210a3997a;hp=c18e19d4d4b45a3804c2d6f779ba5c8adcfe48d0;hpb=5301a9d1b07ad5af1b62df870b7181461603f460;p=public-inbox.git diff --git a/lib/PublicInbox/Search.pm b/lib/PublicInbox/Search.pm index c18e19d4..b739faf1 100644 --- a/lib/PublicInbox/Search.pm +++ b/lib/PublicInbox/Search.pm @@ -18,9 +18,9 @@ use constant { # added for public-inbox 1.6.0+ BYTES => 3, # IMAP RFC822.SIZE UID => 4, # IMAP UID == NNTP article number == Xapian docid + THREADID => 5, # RFC 8474, RFC 8621 # TODO - # THREADID => ? # REPLYCNT => ?, # IMAP ANSWERED # SCHEMA_VERSION history @@ -47,26 +47,40 @@ use constant { # public-inbox v1.5.0 adds (still SCHEMA_VERSION=15): # * "lid:" and "l:" for List-Id searches # - # v1.6.0 adds BYTES and UID values + # v1.6.0 adds BYTES, UID and THREADID values SCHEMA_VERSION => 15, }; use PublicInbox::Smsg; use PublicInbox::Over; my $QP_FLAGS; -our %X = map { $_ => 0 } qw(BoolWeight Database Enquire - NumberValueRangeProcessor QueryParser Stem); +our %X = map { $_ => 0 } qw(BoolWeight Database Enquire QueryParser Stem); our $Xap; # 'Search::Xapian' or 'Xapian' +my $NVRP; # '$Xap::'.('NumberValueRangeProcessor' or 'NumberRangeProcessor') my $ENQ_ASCENDING; sub load_xapian () { return 1 if defined $Xap; - for my $x (qw(Search::Xapian Xapian)) { + # n.b. PI_XAPIAN is intended for development use only. We still + # favor Search::Xapian since that's what's available in current + # Debian stable (10.x) and derived distros. + for my $x (($ENV{PI_XAPIAN} // 'Search::Xapian'), 'Xapian') { eval "require $x"; next if $@; $x->import(qw(:standard)); $Xap = $x; + + # `version_string' was added in Xapian 1.1 + my $xver = eval('v'.eval($x.'::version_string()')) // + eval('v'.eval($x.'::xapian_version_string()')); + + # NumberRangeProcessor was added in Xapian 1.3.6, + # NumberValueRangeProcessor was removed for 1.5.0+, + # favor the older /Value/ variant since that's what our + # (currently) preferred Search::Xapian supports + $NVRP = $x.'::'.($x eq 'Xapian' && $xver ge v1.5 ? + 'NumberRangeProcessor' : 'NumberValueRangeProcessor'); $X{$_} = $Xap.'::'.$_ for (keys %X); # ENQ_ASCENDING doesn't seem exported by SWIG Xapian.pm, @@ -311,6 +325,12 @@ sub _do_enquire { retry_reopen($self, \&_enquire_once, [ $self, $query, $opts ]); } +# returns true if all docs have the THREADID value +sub has_threadid ($) { + my ($self) = @_; + (xdb($self)->get_metadata('has_threadid') // '') eq '1'; +} + sub _enquire_once { # retry_reopen callback my ($self, $query, $opts) = @{$_[0]}; my $xdb = xdb($self); @@ -326,6 +346,12 @@ sub _enquire_once { # retry_reopen callback } else { $enquire->set_sort_by_value_then_relevance(TS, $desc); } + + # `mairix -t / --threads' or JMAP collapseThreads + if ($opts->{thread} && has_threadid($self)) { + $enquire->set_collapse_key(THREADID); + } + my $offset = $opts->{offset} || 0; my $limit = $opts->{limit} || 50; my $mset = $enquire->get_mset($offset, $limit); @@ -352,15 +378,18 @@ sub qparse_new ($) { $qp->set_database($xdb); $qp->set_stemmer(stemmer($self)); $qp->set_stemming_strategy(STEM_SOME()); - $qp->set_max_wildcard_expansion(100); - my $nvrp = $X{NumberValueRangeProcessor}; - $qp->add_valuerangeprocessor($nvrp->new(YYYYMMDD, 'd:')); - $qp->add_valuerangeprocessor($nvrp->new(DT, 'dt:')); + my $cb = $qp->can('set_max_wildcard_expansion') // + $qp->can('set_max_expansion'); # Xapian 1.5.0+ + $cb->($qp, 100); + $cb = $qp->can('add_valuerangeprocessor') // + $qp->can('add_rangeprocessor'); # Xapian 1.5.0+ + $cb->($qp, $NVRP->new(YYYYMMDD, 'd:')); + $cb->($qp, $NVRP->new(DT, 'dt:')); # for IMAP, undocumented for WWW and may be split off go away - $qp->add_valuerangeprocessor($nvrp->new(BYTES, 'bytes:')); - $qp->add_valuerangeprocessor($nvrp->new(TS, 'ts:')); - $qp->add_valuerangeprocessor($nvrp->new(UID, 'uid:')); + $cb->($qp, $NVRP->new(BYTES, 'bytes:')); + $cb->($qp, $NVRP->new(TS, 'ts:')); + $cb->($qp, $NVRP->new(UID, 'uid:')); while (my ($name, $prefix) = each %bool_pfx_external) { $qp->add_boolean_prefix($name, $_) foreach split(/ /, $prefix);