Commit 5e8a82a2 authored by Michaël Dupont's avatar Michaël Dupont Committed by Thomas Seiber
Browse files

Issue #3225675 by mdupont, drunken monkey: Fixed score calculation in DB...

Issue #3225675 by mdupont, drunken monkey: Fixed score calculation in DB backend when multiple fields have the same score.
parent ca48d0ff
Loading
Loading
Loading
Loading
+2 −0
Changes for CHANGELOG.txt: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
Search API 1.x, dev (xxxx-xx-xx):
---------------------------------
- #3225675 by mdupont, drunken monkey: Fixed score calculation in DB backend
  when multiple fields have the same score.
- #3253738 by mkalkbrenner, alexpott, drunken monkey: Fixed deprecation
  warnings in PHP 8.1.
- #3091198 by alexpott, drunken monkey: Fixed problems on MySQL 5.6/5.7.
+6 −2
Changes for modules/search_api_db/src/Plugin/search_api/backend/Database.php: 6 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -2013,17 +2013,21 @@ class Database extends BackendPluginBase implements PluginFormInterface {
      $field = reset($fields);
      $db_query = $this->database->select($field['table'], 't');
      $mul_words = ($word_count > 1);
      // Depending on several factors, a different set of columns is expected to
      // be returned in this query (that will potentially be nested later).
      // Also, grouping might be added for some combinations, in which case we
      // need to SUM() the score so it doesn't get grouped as well.
      if ($neg_nested) {
        $db_query->fields('t', ['item_id', 'word']);
      }
      elseif ($neg) {
        $db_query->fields('t', ['item_id']);
      }
      elseif ($not_nested && $match_parts) {
      elseif ($match_parts) {
        $db_query->fields('t', ['item_id']);
        $db_query->addExpression('SUM(t.score)', 'score');
      }
      elseif ($not_nested || $match_parts) {
      elseif ($not_nested) {
        $db_query->fields('t', ['item_id', 'score']);
      }
      else {
+36 −0
Changes for modules/search_api_db/tests/src/Kernel/BackendTest.php: 36 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ class BackendTest extends BackendTestBase {
    $this->regressionTest2916534();
    $this->regressionTest2873023();
    $this->regressionTest3199355();
    $this->regressionTest3225675();
  }

  /**
@@ -850,6 +851,41 @@ class BackendTest extends BackendTestBase {
    unset($this->entities[$entity_id]);
  }

  /**
   * Tests whether scoring is correct when multiple fields have the same boost.
   *
   * @see https://www.drupal.org/node/3225675
   */
  protected function regressionTest3225675() {
    // Set match mode to "partial" and the same field boost for both "body" and
    // "name".
    $this->setServerMatchMode();
    $index = $this->getIndex();
    $index->getField('name')->setBoost(1.0);
    $index->getField('body')->setBoost(1.0);
    $index->save();
    $this->indexItems($this->indexId);

    // Item 2 has "test" in both name and body, item 3 has it only in body, so
    // 2 should have a greater score. If the bug is present, both would have
    // same score.
    $results = $this->buildSearch('test', [], NULL, FALSE)
      ->addCondition('id', [2, 3], 'IN')
      ->sort('search_api_relevance', QueryInterface::SORT_DESC)
      ->execute();

    $resultItems = array_values($results->getResultItems());
    $this->assertLessThan($resultItems[0]->getScore(), $resultItems[1]->getScore());

    // Reset match mode and field boosts.
    $this->setServerMatchMode('words');
    $index = $this->getIndex();
    $index->getField('name')->setBoost(5);
    $index->getField('body')->setBoost(0.8);
    $index->save();
    $this->indexItems($this->indexId);
  }

  /**
   * {@inheritdoc}
   */