]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Ticket 2141: bugs with weighted popularity lists across year boundary.
authorBrion Vibber <brion@status.net>
Mon, 4 Jan 2010 21:01:17 +0000 (13:01 -0800)
committerBrion Vibber <brion@status.net>
Mon, 4 Jan 2010 21:01:17 +0000 (13:01 -0800)
Consolidated several separate implementations of the same weighting algorithm into common_sql_weight() and fixed some bugs...
For MySQL, now using timestampdiff() instead of subtraction for the comparison, so we get sane results when the year doesn't match, and utc_timestamp() rather than now() so we don't get negative ages for recent items with local server timezone.
Unknown whether the same problems affect PostgreSQL, but note that it lacks the timestampdiff() SQL function.

actions/favorited.php
actions/publictagcloud.php
lib/grouptagcloudsection.php
lib/personaltagcloudsection.php
lib/popularnoticesection.php
lib/util.php

index 150b67b0b09451f752d226486031de07852e32b7..9ffa5b84454093fde32b98460751b60bbab32745 100644 (file)
@@ -185,11 +185,7 @@ class FavoritedAction extends Action
 
     function showContent()
     {
-        if (common_config('db', 'type') == 'pgsql') {
-            $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))';
-        } else {
-            $weightexpr='sum(exp(-(now() - fave.modified) / %s))';
-        }
+        $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
 
         $qry = 'SELECT notice.*, '.
           $weightexpr . ' as weight ' .
@@ -207,7 +203,7 @@ class FavoritedAction extends Action
         }
 
         $notice = Memcached_DataObject::cachedQuery('Notice',
-                                                    sprintf($qry, common_config('popular', 'dropoff')),
+                                                    $qry,
                                                     600);
 
         $nl = new NoticeList($notice, $this);
index e7f6ee36c736552bc33817bf5018940ea0e1d254..9e4478dbb13165e1e908e9dbc02114f137e496ee 100644 (file)
@@ -105,12 +105,8 @@ class PublictagcloudAction extends Action
 
         #Add the aggregated columns...
         $tags->selectAdd('max(notice_id) as last_notice_id');
-        if(common_config('db','type')=='pgsql') {
-            $calc='sum(exp(-extract(epoch from (now()-created))/%s)) as weight';
-        } else {
-            $calc='sum(exp(-(now() - created)/%s)) as weight';
-        }
-        $tags->selectAdd(sprintf($calc, common_config('tag', 'dropoff')));
+        $calc = common_sql_weight('created', common_config('tag', 'dropoff'));
+        $tags->selectAdd($calc . ' as weight');
         $tags->groupBy('tag');
         $tags->orderBy('weight DESC');
 
@@ -136,7 +132,12 @@ class PublictagcloudAction extends Action
             $this->elementStart('dd');
             $this->elementStart('ul', 'tags xoxo tag-cloud');
             foreach ($tw as $tag => $weight) {
-                $this->showTag($tag, $weight, $weight/$sum);
+                if ($sum) {
+                    $weightedSum = $weight/$sum;
+                } else {
+                    $weightedSum = 0.5;
+                }
+                $this->showTag($tag, $weight, $weightedSum);
             }
             $this->elementEnd('ul');
             $this->elementEnd('dd');
index 091cf48457ce0bdb9330d62d78b9ff7363ef1944..14ceda0850b09b6918c4da00517370f6b31bad42 100644 (file)
@@ -58,11 +58,7 @@ class GroupTagCloudSection extends TagCloudSection
 
     function getTags()
     {
-        if (common_config('db', 'type') == 'pgsql') {
-            $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))';
-        } else {
-            $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))';
-        }
+        $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
 
         $names = $this->group->getAliases();
 
@@ -99,7 +95,6 @@ class GroupTagCloudSection extends TagCloudSection
 
         $tag = Memcached_DataObject::cachedQuery('Notice_tag',
                                                  sprintf($qry,
-                                                         common_config('tag', 'dropoff'),
                                                          $this->group->id,
                                                          $namestring),
                                                  3600);
index 0b29d58ca60386b9331de6ad7a330cab9191ca14..091425f926d296f8959322e63c2a3ac770bae41d 100644 (file)
@@ -58,13 +58,9 @@ class PersonalTagCloudSection extends TagCloudSection
 
     function getTags()
     {
-        if (common_config('db', 'type') == 'pgsql') {
-            $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))';
-        } else {
-            $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))';
-        }
-       $qry = 'SELECT notice_tag.tag, '.
+        $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
+
+        $qry = 'SELECT notice_tag.tag, '.
           $weightexpr . ' as weight ' .
           'FROM notice_tag JOIN notice ' .
           'ON notice_tag.notice_id = notice.id ' .
@@ -83,7 +79,6 @@ class PersonalTagCloudSection extends TagCloudSection
 
         $tag = Memcached_DataObject::cachedQuery('Notice_tag',
                                                  sprintf($qry,
-                                                         common_config('tag', 'dropoff'),
                                                          $this->user->id),
                                                  3600);
         return $tag;
index 9fbc9d2ddd0c779079ba3b75a154cd44fac12846..fbf9a60ab8112395156ffa26b9a5021293f816b6 100644 (file)
@@ -48,17 +48,17 @@ class PopularNoticeSection extends NoticeSection
 {
     function getNotices()
     {
+        // @fixme there should be a common func for this
         if (common_config('db', 'type') == 'pgsql') {
-            $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))';
             if (!empty($this->out->tag)) {
                 $tag = pg_escape_string($this->out->tag);
             }
         } else {
-            $weightexpr='sum(exp(-(now() - fave.modified) / %s))';
             if (!empty($this->out->tag)) {
                  $tag = mysql_escape_string($this->out->tag);
             }
         }
+        $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
         $qry = "SELECT notice.*, $weightexpr as weight ";
         if(isset($tag)) {
             $qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' .
@@ -78,7 +78,7 @@ class PopularNoticeSection extends NoticeSection
         $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
 
         $notice = Memcached_DataObject::cachedQuery('Notice',
-                                                    sprintf($qry, common_config('popular', 'dropoff')),
+                                                    $qry,
                                                     1200);
         return $notice;
     }
index ed81aeba16ceffde2a25c84c1229f7c26dca7358..fdcc87677b08011829c0b77c62e2cf44e8f6244d 100644 (file)
@@ -908,6 +908,26 @@ function common_sql_date($datetime)
     return strftime('%Y-%m-%d %H:%M:%S', $datetime);
 }
 
+/**
+ * Return an SQL fragment to calculate an age-based weight from a given
+ * timestamp or datetime column.
+ *
+ * @param string $column name of field we're comparing against current time
+ * @param integer $dropoff divisor for age in seconds before exponentiation
+ * @return string SQL fragment
+ */
+function common_sql_weight($column, $dropoff)
+{
+    if (common_config('db', 'type') == 'pgsql') {
+        // PostgreSQL doesn't support timestampdiff function.
+        // @fixme will this use the right time zone?
+        // @fixme does this handle cross-year subtraction correctly?
+        return "sum(exp(-extract(epoch from (now() - $column)) / $dropoff))";
+    } else {
+        return "sum(exp(timestampdiff(second, utc_timestamp(), $column) / $dropoff))";
+    }
+}
+
 function common_redirect($url, $code=307)
 {
     static $status = array(301 => "Moved Permanently",