Problem/Motivation

There are currently several open issues reporting problems in the function search_update_totals() in search.module. This function runs at the end of Search cron, and updates the overall word scores for each word that has been indexed, so that when search queries run, this overall word score can be used to rank results. I am making a meta issue here to clarify what is going on, and possibly we can fix them all at the same time.

The underlying problem is that if you have a site with lots of nodes, depending on your search settings, you can run out of memory or have database exceptions when this code is run. And even if you don't, the calculation is not very optimal.

The current Drupal 8 code for this function is:

function search_update_totals() {
  // Update word IDF (Inverse Document Frequency) counts for new/changed words.
  foreach (search_dirty() as $word => $dummy) {
    // Get total count
    $total = db_query("SELECT SUM(score) FROM {search_index} WHERE word = :word", array(':word' => $word), array('target' => 'replica'))->fetchField();
    // Apply Zipf's law to equalize the probability distribution.
    $total = log10(1 + 1/(max(1, $total)));
    db_merge('search_total')
      ->key('word', $word)
      ->fields(array('count' => $total))
      ->execute();
  }
  // Find words that were deleted from search_index, but are still in
  // search_total. We use a LEFT JOIN between the two tables and keep only the
  // rows which fail to join.
  $result = db_query("SELECT t.word AS realword, i.word FROM {search_total} t LEFT JOIN {search_index} i ON t.word = i.word WHERE i.word IS NULL", array(), array('target' => 'replica'));
  $or = db_or();
  foreach ($result as $word) {
    $or->condition('word', $word->realword);
  }
  if (count($or) > 0) {
    db_delete('search_total')
      ->condition($or)
      ->execute();
  }
}

Here are the currently-reported problems with this code:

  1. #1189484: ER_TOO_BIG_SELECT in search_update_totals() is about the join in the "SELECT t.word as realword..." query. This join on a site with too many nodes can be too big and trigger a ER_TOO_BIG_SELECT exception in MySQL.
  2. #1365786: The OR query in SearchIndex::updateWordWeights() can exceed SQL select limits / PHP memory limit, change to an IN() is about the creation of the db_or() in the loop running out of memory when adding all the words to be deleted to the condition object.
  3. #1763914: Uncaught exception thrown in shutdown function due to SQL Server max of 2100 parameters is about the db_delete('search_total') query running out of parameters in SQL Server and triggering a database exception if it has a lot of words to delete. Although this issue is reported against SQL Server, it could occur in other databases as well, since all databases have parameter limits on DELETE queries.
  4. #257916: Improve performance of search totals calculation is about optimizing the calculation of totals at the top so that it processes a chunk of words together instead of doing each word separately. This one is not so much of a bug as a "could be more optimal" task.

Proposed resolution

Fix the three bugs, and probably the "could be more optimal" task as well.

Remaining tasks

All issues still need resolution. Some have patches, but probably the approaches on the 3 bugs should be combined.

User interface changes

None.

API changes

None.

Comments

jhodgdon’s picture

Priority: Normal » Major

Actually, given that there are 3 bugs that can cause fatal errors in some sites and some database servers, I think this one is at least Major.

jhodgdon’s picture

So... talked to pwolanin about this at DDD today...

Fundamentally, we need to change how this functionality works. And as a note, this is functionality for normalizing scores for sorting results to prioritize overall less frequent words over overall more frequent words.

a) We need to use something like
http://weblogs.sqlteam.com/peterl/archive/2007/09/20/Finding-records-in-...
to figure out if records from one table do not exist in another, not a left join followed by a db_or() too many conditions delete.

Or maybe a different query like
SELECT t.word AS realword, i.word FROM search_total t LEFT JOIN (select distinct word from search_index) as i ON t.word = i.word WHERE i.word IS NULL;

b) We need to make sure the search_totals normalization table is done per type and maybe per language, not combining every search plugin's index together.

c) The "dirty" process itself is not really right. What it's currently doing during indexing is that when a word is added to the index, it is marked as "dirty", so that all the words in a node (for example) that is being indexed are marked as "dirty". These ones are renormalized. However, if you are reindexing an existing node that was updated, the old words from the previous version are *not* renormalized unless they happen to also exist in the new node (or another one that is indexed in the same cron run). So, that is wrong.

Also when a node gets deleted, the words there are no mechanisms for renormalizing the words that had been in that node (which is only important if the words also exist in another node).

So... we need a better way to track "this normalization score needs to be updated", and we need to track it between cron runs (nodes are deleted from indexing when they're deleted, not just during cron runs).

d) The db_or() part is probably silly. Should be using an IN query instead, should be more efficient. Still would need to be chunked.

e) The loop at the top of the function that does foreach (search_dirty() ... should be using fewer queries with chunking. There's a patch on #257916: Improve performance of search totals calculation that does this.

f) There were questions on #257916: Improve performance of search totals calculation about whether log functions were available in all databases. It looks like the function LN is pretty universal (natural log), except in SQLite (but we can define one in PHP) -- even in databases that we don't officially support (SQLServer, Oracle, etc.) -- so that should be fine -- and we don't really care which log function we use as long as it's a log [as long as we always use the same log function]. Database drivers for other databases should be able to substitute something in to convert from one log to another if necessary.

hanoii’s picture

I just added one odd bug, It's not related to the rest, and its quite hard to reproduce/follow. It could even be a php issue.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jhodgdon’s picture

As a note, this function is now being moved to a service, but most likely all these problems remain.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

catch’s picture

Issue tags: +Bug Smash Initiative

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

quietone’s picture

Status: Active » Postponed

The Search Module was approved for removal in #3476883: [Policy, no patch] Move Search module to contrib .

This is Postponed. The status is set according to two policies. The Remove a core extension and move it to a contributed project and the Extensions approved for removal policies.

The deprecation work is in #3565780: [meta] Tasks to deprecate the Search module and the removal work in #3565783: [meta] Tasks to remove the Search module.

Search will be moved to a contributed project before Drupal 12.0.0 is released.

quietone’s picture

Project: Drupal core » Search (from core)
Version: main » 1.0.0
Component: search.module » Code

The Search Module has moved from core to contrib,

quietone’s picture

Status: Postponed » Active