[dw-free] Search for several interests at once
[commit: http://hg.dwscoalition.org/dw-free/rev/21d02a514f23]
http://bugs.dwscoalition.org/show_bug.cgi?id=2821
Refactoring for backend to facilitate multiple interests search. (No
functional change)
Patch by
kareila.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=2821
Refactoring for backend to facilitate multiple interests search. (No
functional change)
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- cgi-bin/DW/Controller/Search/Interests.pm
- cgi-bin/LJ/Keywords.pm
-------------------------------------------------------------------------------- diff -r d7de4e60ea79 -r 21d02a514f23 cgi-bin/DW/Controller/Search/Interests.pm --- a/cgi-bin/DW/Controller/Search/Interests.pm Tue Mar 08 13:42:11 2011 +0800 +++ b/cgi-bin/DW/Controller/Search/Interests.pm Tue Mar 08 14:33:42 2011 +0800 @@ -291,41 +291,45 @@ sub interest_handler { $rv->{intid} = $intid; $rv->{intcount} = $intcount; - my $dbr = LJ::get_db_reader(); - my $int_query = sub { - my $i = shift; # comminterests or userinterests - my $LIMIT = 500; - my $q = "SELECT $i.userid FROM $i, userusage - WHERE $i.intid = ? AND $i.userid = userusage.userid - ORDER BY userusage.timeupdate DESC LIMIT $LIMIT"; - my $uref = $dbr->selectall_arrayref( $q, undef, $intid ); - return LJ::load_userids( map { $_->[0] } @$uref ); - # can't trust LJ::load_userids to maintain sort order - }; - # filtering by account type $rv->{type_list} = [ 'none', 'P', 'C', 'I' ]; my $type = $args->{type}; $type = 'none' unless $type && $type =~ /^[PCI]$/; - my $typefilter = sub { return $type eq 'none' ? 1 : - $_[0]->journaltype eq $type }; - # get top 500 user and/or community results - my $us = {}; + # constructor for filter links + $rv->{type_link} = sub { + return '' if $type eq $_[0]; # no link for active selection + my $typearg = $_[0] eq 'none' ? '' : $_[0]; + return LJ::page_change_getargs( type => $typearg ); + }; - unless ( $type eq 'C' ) { # unless no users needed - $us = $int_query->( "userinterests" ); - $rv->{comm_count} = 1; # reset later if comms loaded + # determine which account types we need to search for + my $type_opts = {}; + my %opt_map = ( C => 'nousers', P => 'nocomms', I => 'nocomms' ); + $type_opts = { $opt_map{$type} => 1 } if defined $opt_map{$type}; + + my @uids = LJ::users_with_all_ints( [$intid], $type_opts ); + + # limit results to 500 most recently updated journals + if ( scalar @uids > 500 ) { + my $dbr = LJ::get_db_reader(); + my $qs = join ',', map { '?' } @uids; + my $uref = $dbr->selectall_arrayref( + "SELECT userid FROM userusage WHERE userid IN ($qs) + ORDER BY timeupdate DESC LIMIT 500", undef, @uids ); + die $dbr->errstr if $dbr->err; + @uids = map { $_->[0] } @$uref; } - unless ( $type =~ /^[PI]$/ ) { # unless no comms needed - my $cus = $int_query->( "comminterests" ); - $rv->{comm_count} = scalar values %$cus; + my $us = LJ::load_userids( @uids ); - # combine the two sets of results - @{ $us }{ keys %$cus } = values %$cus; - } + # prepare to filter and sort the results into @ul + + my $typefilter = sub { + $rv->{comm_count}++ if $_[0]->is_community; + return $type eq 'none' ? 1 : $_[0]->journaltype eq $type; + }; my $should_show = sub { return $_[0]->should_show_in_search_results( for => $remote ); @@ -339,13 +343,7 @@ sub interest_handler { grep { $_ && $typefilter->( $_ ) && $should_show->( $_ ) } values %$us; $rv->{type_count} = scalar @ul if $intcount != scalar @ul; - - # construct filter links - $rv->{type_link} = sub { - return '' if $type eq $_[0]; # no link for active selection - my $typearg = $_[0] eq 'none' ? '' : $_[0]; - return LJ::page_change_getargs( type => $typearg ); - }; + $rv->{comm_count} = 1 if $type_opts->{nocomms}; # doesn't count if ( @ul ) { # pagination diff -r d7de4e60ea79 -r 21d02a514f23 cgi-bin/LJ/Keywords.pm --- a/cgi-bin/LJ/Keywords.pm Tue Mar 08 13:42:11 2011 +0800 +++ b/cgi-bin/LJ/Keywords.pm Tue Mar 08 14:33:42 2011 +0800 @@ -102,6 +102,47 @@ sub interest_string_to_list { # final list is ,-sep return grep { length } split (/\s*,\s*/, $intstr); +} + + +# This function takes a list of intids and returns the list of uids +# for accounts interested in ALL of the given interests. +# +# Args: arrayref of intids, hashref of opts +# Returns: array of uids +# +# Valid opts: nousers => 1, nocomms => 1 +# +sub users_with_all_ints { + my ( $ints, $opts ) = @_; + $opts ||= {}; + return unless defined $ints && ref $ints eq 'ARRAY'; + + my @intids = grep /^\d+$/, @$ints; # numeric only + return unless @intids; + + my @tables; + push @tables, 'userinterests' unless $opts->{nousers}; + push @tables, 'comminterests' unless $opts->{nocomms}; + return unless @tables; + + my $dbr = LJ::get_db_reader(); + my $qs = join ',', map { '?' } @intids; + my @uids; + + foreach ( @tables ) { + my $q = "SELECT userid FROM $_ WHERE intid IN ($qs)"; + my $uref = $dbr->selectall_arrayref( $q, undef, @intids ); + die $dbr->errstr if $dbr->err; + + # Count the number of times the uid appears. + # If it's the same as the number of interests, it has all of them. + my %ucount; + $ucount{$_}++ foreach map { $_->[0] } @$uref; + push @uids, grep { $ucount{$_} == scalar @intids } keys %ucount; + } + + return @uids; } --------------------------------------------------------------------------------