LP#1549505: Scale popularity adjustment to relevance differently
authorMike Rylander <mrylander@gmail.com>
Sat, 19 Mar 2016 20:31:04 +0000 (16:31 -0400)
committerMike Rylander <mrylander@gmail.com>
Sat, 19 Mar 2016 20:31:04 +0000 (16:31 -0400)
From code comments:

$max_mult below is the value of the newly introduced global flag
called search.max_popularity_importance_multiplier.

$adjusted_scale below is the converted badge score scaling value
after accounting for the administrator-supplied $max_mult value.

This will cale the 0-5 effect of popularity badges by providing a
divisor for the badge average that is the inverse of the maximum
multiplier.  Two examples, comparing the effect to the default
$max_mult value of 2.0, which causes a $adjusted_scale value
of 5.0:

 * Given a $max_mult of 1.1, the value of $adjusted_scale
   will be 50.0, meaning that the average badge value will be
   /divided/ by 50.0 rather than 5.0, then added to 1.0 and
   used as a multiplier against the base relevance.  Thus a
   change of at most 10% to the base relevance for a record
   with a 5.0 average badge score. This will allow records
   that are naturally very relevant to avoid being pushed
   below badge-heavy records.

 * Given a $max_mult of 3.0, the value of $adjusted_scale
   will be 2.5, meaning that the average badge value will be
   /divided/ by 2.5 rather than 5.0, then added to 1.0 and
   used as a multiplier against the base relevance. Thus a
   change of as much as 200% to (or three times the size of)
   the base relevance for a record with a 5.0 average badge
   score.  This in turn will cause badges to outweigh
   relevance to a very large degree.

Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm

index fd2da63..27da463 100644 (file)
@@ -884,7 +884,38 @@ sub toSQL {
         $rank = "FIRST((SELECT edit_date FROM biblio.record_entry rbr WHERE rbr.id = m.source))";
     } elsif ($sort_filter eq 'poprel') {
         my $max_mult = $self->QueryParser->max_popularity_importance_multiplier() // 2.0;
-        $rank = '1.0/((' . $rel . ') * (' . $max_mult .' - 1.0) * (1.0 + AVG(COALESCE(pop_with.total_score::NUMERIC,0.0)) / 5.0))::NUMERIC';
+
+        if ( $max_mult == 1.0 ) { # no adjustment requested by the configuration
+            $rank = "1.0/($rel)::NUMERIC";
+        } else { # calculate adjustment
+
+            # Scale the 0-5 effect of popularity badges by providing a divisor
+            # for the badge average that is the inverse of the maximum
+            # multiplier.  Two examples, comparing the effect to the default
+            # $max_mult value of 2.0, which causes a $adjusted_scale value
+            # of 5.0:
+            #
+            #  * Given a $max_mult of 1.1, the value of $adjusted_scale
+            #    will be 50.0, meaning that the average badge value will be
+            #    /divided/ by 50.0 rather than 5.0, then added to 1.0 and
+            #    used as a multiplier against the base relevance.  Thus a
+            #    change of at most 10% to the base relevance for a record
+            #    with a 5.0 average badge score. This will allow records
+            #    that are naturally very relevant to avoid being pushed
+            #    below badge-heavy records.
+            #
+            #  * Given a $max_mult of 3.0, the value of $adjusted_scale
+            #    will be 2.5, meaning that the average badge value will be
+            #    /divided/ by 2.5 rather than 5.0, then added to 1.0 and
+            #    used as a multiplier against the base relevance. Thus a
+            #    change of as much as 200% to (or three times the size of)
+            #    the base relevance for a record with a 5.0 average badge
+            #    score.  This in turn will cause badges to outweigh
+            #    relevance to a very large degree.
+
+            my $adjusted_scale = 5.0 / ( $max_mult - 1.0 );
+            $rank = "1.0/(( $rel ) * (1.0 + (AVG(COALESCE(pop_with.total_score::NUMERIC,0.0)) / $adjusted_scale)))::NUMERIC";
+        }
     } elsif ($sort_filter =~ /^pop/) {
         $rank = '1.0/(AVG(COALESCE(pop_with.total_score::NUMERIC,0.0)) + 5.0)::NUMERIC';
         my $pop_desc = $desc eq 'ASC' ? 'DESC' : 'ASC';