Андрей (andy) wrote in changelog,
Андрей
andy
changelog

[livejournal] r19282: LJSUP-8584 (ONTD: Top tags for month)

Committer: ailyin
LJSUP-8584 (ONTD: Top tags for month)
U   trunk/cgi-bin/taglib.pl
Modified: trunk/cgi-bin/taglib.pl
===================================================================
--- trunk/cgi-bin/taglib.pl	2011-06-14 07:45:01 UTC (rev 19281)
+++ trunk/cgi-bin/taglib.pl	2011-06-15 04:26:30 UTC (rev 19282)
@@ -253,6 +253,46 @@
     return $res;
 }
 
+sub filter_accessible_tags {
+    my ( $journalu, $remote, $tags_info ) = @_;
+
+    # never going to cull anything if you control it, so just return
+    return if $remote && $remote->can_manage($journalu);
+
+    # setup helper variables from journalu to remote
+    my ($is_friend, $grpmask) = (0, 0);
+    if ($remote) {
+        $is_friend = LJ::is_friend( $journalu, $remote );
+        $grpmask   = LJ::get_groupmask( $journalu, $remote );
+    }
+
+    # figure out what we need to purge
+    my @purge;
+
+    foreach my $tagid ( keys %$tags_info ) {
+        my $tag_info = $tags_info->{$tagid};
+        my $sec = $tag_info->{'security_level'};
+
+        if ( $sec eq 'public' ) {
+            next;
+        } elsif ( $sec eq 'friends' ) {
+            delete $tags_info->{$tagid} unless $is_friend;
+            next;
+        } elsif ( $sec eq 'group' ) {
+            my @groups = keys %{ $tag_info->{'security'}->{'groups'} };
+
+            my $accessible = 0;
+            foreach my $grpid (@groups) {
+                $accessible ||= ( $grpmask & ( 1 << $grpid ) );
+            }
+
+            delete $tags_info->{$tagid} unless $accessible;
+        }
+    }
+
+    return;
+}
+
 # <LJFUNC>
 # name: LJ::Tags::get_usertags
 # class: tags
@@ -277,37 +317,157 @@
     my $res = $tags->{$u->{userid}} || {};
     return {} unless %$res;
 
-    # now if they provided a remote, remove the ones they don't want to see; note that
-    # remote may be undef so we have to check exists
-    if (exists $opts->{remote}) {
-        # never going to cull anything if you control it, so just return
-        my $remote = $opts->{remote};
-        return $res if $remote && $remote->can_manage($u);
+    # now if they provided a remote, remove the ones they don't want to see;
+    # note that remote may be undef so we have to check exists
+    if ( exists $opts->{'remote'} ) {
+        filter_accessible_tags( $u, $opts->{'remote'}, $res );
+    }
 
-        # setup helper variables from u to remote
-        my ($is_friend, $grpmask) = (0, 0);
-        if ($opts->{remote}) {
-            $is_friend = LJ::is_friend($u, $opts->{remote});
-            $grpmask = LJ::get_groupmask($u, $opts->{remote});
+    return $res;
+}
+
+sub get_recent_logtags {
+    my ( $journalu, $days, $opts ) = @_;
+
+    $days = int $days || 30;
+    $opts ||= {};
+
+    my $memkey = [
+        $journalu->userid,
+        'logtagtrends:' . $journalu->userid . ':' . $days
+    ];
+
+    my $tags_info;
+
+    unless ( $tags_info = LJ::MemCache::get($memkey) ) {
+        $tags_info = calculate_recent_logtags( $journalu, $days );
+        LJ::MemCache::set( $memkey => $tags_info );
+    }
+
+    # now if they provided a remote, remove the ones they don't want to see;
+    # note that remote may be undef so we have to check exists
+    if ( exists $opts->{'remote'} ) {
+        filter_accessible_tags( $journalu, $opts->{'remote'}, $tags_info );
+    }
+
+    return $tags_info;
+}
+
+sub calculate_recent_logtags {
+    my ( $journalu, $days ) = @_;
+
+    my $dbr = LJ::get_cluster_reader($journalu);
+
+    # step 1: acquire information about entries in the last month
+    my $rlogtime_max = $LJ::EndOfTime - time + 86400 * $days;
+    my $entries_rows = $dbr->selectall_arrayref(
+        qq{
+            SELECT jitemid, security, allowmask FROM log2
+            WHERE journalid=$journalu->{userid} AND rlogtime < $rlogtime_max
+        },
+        { 'Slice' => {} }
+    );
+
+    my ( @jitemids, %security );
+    foreach my $row ( @$entries_rows ) {
+        my $jitemid = $row->{'jitemid'};
+
+        push @jitemids, $jitemid;
+
+        $security{$jitemid} = {
+            'level'     => $row->{'security'},
+            'allowmask' => $row->{'allowmask'},
         }
+    }
 
-        # figure out what we need to purge
-        my @purge;
-TAG:    foreach my $tagid (keys %$res) {
-            my $sec = $res->{$tagid}->{security_level};
-            next TAG if $sec eq 'public';
-            next TAG if $is_friend && $sec eq 'friends';
-            if ($grpmask && $sec eq 'group') {
-                foreach my $grpid (keys %{$res->{$tagid}->{security}->{groups}}) {
-                    next TAG if $grpmask & (1 << $grpid);
+    return {} unless @jitemids;
+
+    # step 2: acquire information and collect statistics
+    # about tags to these entries, in terms of kwids
+    my $tags_info = {};
+    my @jitemids_copy = @jitemids;
+    while ( my @jitemids_chunk = splice @jitemids, 0, 1000 ) {
+        my $jitemids_in = join( ',', @jitemids_chunk );
+        my $tags_info_rows = $dbr->selectall_arrayref(
+            qq{
+                SELECT jitemid, kwid FROM logtags
+                WHERE journalid=? AND jitemid IN ($jitemids_in)
+            },
+            { 'Slice' => {} }, $journalu->userid,
+        );
+
+        foreach my $row (@$tags_info_rows) {
+            my $jitemid = $row->{'jitemid'};
+            my $kwid = $row->{'kwid'};
+
+            unless ( exists $tags_info->{$kwid} ) {
+                $tags_info->{$kwid} = {
+                    'security' => {
+                        'public'  => 0,
+                        'groups'  => {},
+                        'private' => 0,
+                        'friends' => 0
+                    },
+                    'security_level' => 'private',
+                    'uses' => 0,
+                };
+            }
+
+            $tags_info->{$kwid}->{'uses'}++;
+
+            my $security = $security{$jitemid}->{'level'};
+            my $allowmask = $security{$jitemid}->{'allowmask'};
+
+            if ( $security eq 'public' ) {
+                $tags_info->{$kwid}->{'security'}->{'public'}++;
+                $tags_info->{$kwid}->{'security_level'} = 'public';
+            }
+
+            elsif ( $security eq 'usemask' && ( $allowmask & 1 ) ) {
+                $tags_info->{$kwid}->{'security'}->{'friends'}++;
+                $tags_info->{$kwid}->{'security_level'} = 'friends'
+                    unless $tags_info->{$kwid}->{'security_level'} eq 'public';
+            }
+
+            elsif ( $security eq 'usemask' ) {
+                my @grpids = LJ::bit_breakdown($allowmask);
+                my $groups = $tags_info->{$kwid}->{'security'}->{'groups'};
+                foreach my $grpid (@grpids) {
+                    unless ( exists $groups->{$grpid} ) {
+                        $groups->{$grpid} = 0;
+                    }
+
+                    $groups->{$grpid}++;
                 }
+
+                $tags_info->{$kwid}->{'security_level'} = 'group'
+                    if $tags_info->{$kwid}->{'security_level'} eq 'private';
             }
-            push @purge, $tagid;
+
+            elsif ( $security eq 'private' ) {
+                $tags_info->{$kwid}->{'security'}->{'private'}++;
+            }
         }
-        delete $res->{$_} foreach @purge;
     }
 
-    return $res;
+    # step 3: fetch names for the keywords
+    my @kwids = keys %$tags_info;
+    return {} unless @kwids;
+    my $kwid_in = join( ',', keys %$tags_info );
+    my $kwrows = $dbr->selectall_arrayref(
+        qq{
+            SELECT kwid, keyword FROM userkeywords
+            WHERE userid=? AND kwid IN ($kwid_in)
+        },
+        { 'Slice' => {} },
+        $journalu->userid,
+    );
+
+    foreach my $kwrow (@$kwrows) {
+        $tags_info->{ $kwrow->{'kwid'} }->{'name'} = $kwrow->{'keyword'};
+    }
+
+    return $tags_info;
 }
 
 # <LJFUNC>

Tags: andy, livejournal, pl
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments