[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
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;
}
--------------------------------------------------------------------------------
