diff options
author | David Rothstein <drothstein@gmail.com> | 2013-12-27 15:18:38 -0500 |
---|---|---|
committer | David Rothstein <drothstein@gmail.com> | 2013-12-27 15:18:38 -0500 |
commit | 66a58e46111f1a1104ab8dec9f74199c61eb1822 (patch) | |
tree | d79282a7b5df43c606387baefb2b8151f52aab82 /modules/search/search.extender.inc | |
parent | 18d4eaaef88f5397de926f67bf8e6f8d61bb3345 (diff) | |
download | brdo-66a58e46111f1a1104ab8dec9f74199c61eb1822.tar.gz brdo-66a58e46111f1a1104ab8dec9f74199c61eb1822.tar.bz2 |
Issue #2016497 by naxoc, jhodgdon | plachance: Search query extender should not use floats directly.
Diffstat (limited to 'modules/search/search.extender.inc')
-rw-r--r-- | modules/search/search.extender.inc | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/modules/search/search.extender.inc b/modules/search/search.extender.inc index ad4b86e89..67094666e 100644 --- a/modules/search/search.extender.inc +++ b/modules/search/search.extender.inc @@ -105,6 +105,8 @@ class SearchQuery extends SelectQueryExtender { * Stores score expressions. * * @var array + * + * @see addScore() */ protected $scores = array(); @@ -116,7 +118,7 @@ class SearchQuery extends SelectQueryExtender { protected $scoresArguments = array(); /** - * Total value of all the multipliers. + * Stores multipliers for score expressions. * * @var array */ @@ -391,21 +393,39 @@ class SearchQuery extends SelectQueryExtender { /** * Adds a custom score expression to the search query. * - * Each score expression can optionally use a multiplier, and multiple - * expressions are combined. + * Score expressions are used to order search results. If no calls to + * addScore() have taken place, a default keyword relevance score will be + * used. However, if at least one call to addScore() has taken place, the + * keyword relevance score is not automatically added. + * + * Also note that if you call orderBy() directly on the query, search scores + * will not automatically be used to order search results. Your orderBy() + * expression can reference 'calculated_score', which will be the total + * calculated score value. * * @param $score - * The score expression. + * The score expression, which should evaluate to a number between 0 and 1. + * The string 'i.relevance' in a score expression will be replaced by a + * measure of keyword relevance between 0 and 1. * @param $arguments - * Custom query arguments for that expression. + * Query arguments needed to provide values to the score expression. * @param $multiply - * If set, the score is multiplied with that value. Search query ensures - * that the search scores are still normalized. + * If set, the score is multiplied with this value. However, all scores + * with multipliers are then divided by the total of all multipliers, so + * that overall, the normalization is maintained. + * + * @return object + * The updated query object. */ public function addScore($score, $arguments = array(), $multiply = FALSE) { if ($multiply) { $i = count($this->multiply); + // Modify the score expression so it is multiplied by the multiplier, + // with a divisor to renormalize. $score = "CAST(:multiply_$i AS DECIMAL) * COALESCE(( " . $score . "), 0) / CAST(:total_$i AS DECIMAL)"; + // Add an argument for the multiplier. The :total_$i argument is taken + // care of in the execute() method, which is when the total divisor is + // calculated. $arguments[':multiply_' . $i] = $multiply; $this->multiply[] = $multiply; } @@ -446,8 +466,9 @@ class SearchQuery extends SelectQueryExtender { } if (count($this->multiply)) { - // Add the total multiplicator as many times as requested to maintain - // normalization as far as possible. + // Re-normalize scores with multipliers by dividing by the total of all + // multipliers. The expressions were altered in addScore(), so here just + // add the arguments for the total. $i = 0; $sum = array_sum($this->multiply); foreach ($this->multiply as $total) { @@ -456,13 +477,20 @@ class SearchQuery extends SelectQueryExtender { } } - // Replace i.relevance pseudo-field with the actual, normalized value. - $this->scores = str_replace('i.relevance', '(' . (1.0 / $this->normalize) . ' * i.score * t.count)', $this->scores); - // Convert scores to an expression. + // Replace the pseudo-expression 'i.relevance' with a measure of keyword + // relevance in all score expressions, using string replacement. Careful + // though! If you just print out a float, some locales use ',' as the + // decimal separator in PHP, while SQL always uses '.'. So, make sure to + // set the number format correctly. + $relevance = number_format((1.0 / $this->normalize), 10, '.', ''); + $this->scores = str_replace('i.relevance', '(' . $relevance . ' * i.score * t.count)', $this->scores); + + // Add all scores together to form a query field. $this->addExpression('SUM(' . implode(' + ', $this->scores) . ')', 'calculated_score', $this->scoresArguments); + // If an order has not yet been set for this query, add a default order + // that sorts by the calculated sum of scores. if (count($this->getOrderBy()) == 0) { - // Add default order after adding the expression. $this->orderBy('calculated_score', 'DESC'); } |