MediaWiki  master
rebuildtextindex.php
Go to the documentation of this file.
1 <?php
28 require_once __DIR__ . '/Maintenance.php';
29 
33 
40  private const RTI_CHUNK_SIZE = 500;
41 
42  public function __construct() {
43  parent::__construct();
44  $this->addDescription( 'Rebuild search index table from scratch' );
45  }
46 
47  public function getDbType() {
48  return Maintenance::DB_ADMIN;
49  }
50 
51  public function execute() {
52  // Shouldn't be needed for Postgres
53  $dbw = $this->getDB( DB_PRIMARY );
54  if ( $dbw->getType() == 'postgres' ) {
55  $this->fatalError( "This script is not needed when using Postgres.\n" );
56  }
57 
58  if ( $dbw->getType() == 'sqlite' ) {
59  if ( !DatabaseSqlite::getFulltextSearchModule() ) {
60  $this->fatalError( "Your version of SQLite module for PHP doesn't "
61  . "support full-text search (FTS3).\n" );
62  }
63  }
64 
65  if ( $dbw->getType() == 'mysql' ) {
66  $this->dropMysqlTextIndex();
67  $this->clearSearchIndex();
68  $this->populateSearchIndex();
69  $this->createMysqlTextIndex();
70  } else {
71  $this->clearSearchIndex();
72  $this->populateSearchIndex();
73  }
74 
75  $this->output( "Done.\n" );
76  }
77 
81  protected function populateSearchIndex() {
82  $dbw = $this->getDB( DB_PRIMARY );
83  $res = $dbw->select( 'page', 'MAX(page_id) AS count', [], __METHOD__ );
84  $s = $res->fetchObject();
85  $count = $s->count;
86  $this->output( "Rebuilding index fields for {$count} pages...\n" );
87  $n = 0;
88 
89  $revStore = MediaWikiServices::getInstance()->getRevisionStore();
90  $revQuery = $revStore->getQueryInfo( [ 'page' ] );
91 
92  while ( $n < $count ) {
93  if ( $n ) {
94  $this->output( $n . "\n" );
95  }
96  $end = $n + self::RTI_CHUNK_SIZE - 1;
97 
98  $res = $dbw->select(
99  $revQuery['tables'],
100  $revQuery['fields'],
101  [ "page_id BETWEEN $n AND $end", 'page_latest = rev_id' ],
102  __METHOD__,
103  [],
104  $revQuery['joins']
105  );
106 
107  foreach ( $res as $s ) {
108 
109  // T268673 Prevent failure of WikiPage.php: Invalid or virtual namespace -1 given
110  if ( $s->page_namespace < 0 ) {
111  continue;
112  }
113 
114  $title = Title::makeTitle( $s->page_namespace, $s->page_title );
115  try {
116  $revRecord = $revStore->newRevisionFromRow( $s );
117  $content = $revRecord->getContent( SlotRecord::MAIN );
118 
119  $u = new SearchUpdate( $s->page_id, $title, $content );
120  $u->doUpdate();
121  } catch ( MWContentSerializationException $ex ) {
122  $this->output( "Failed to deserialize content of revision {$s->rev_id} of page "
123  . "`" . $title->getPrefixedDBkey() . "`!\n" );
124  }
125  }
126  $n += self::RTI_CHUNK_SIZE;
127  }
128  }
129 
133  private function dropMysqlTextIndex() {
134  $dbw = $this->getDB( DB_PRIMARY );
135  $searchindex = $dbw->tableName( 'searchindex' );
136  if ( $dbw->indexExists( 'searchindex', 'si_title', __METHOD__ ) ) {
137  $this->output( "Dropping index...\n" );
138  $sql = "ALTER TABLE $searchindex DROP INDEX si_title, DROP INDEX si_text";
139  $dbw->query( $sql, __METHOD__ );
140  }
141  }
142 
146  private function createMysqlTextIndex() {
147  $dbw = $this->getDB( DB_PRIMARY );
148  $searchindex = $dbw->tableName( 'searchindex' );
149  $this->output( "\nRebuild the index...\n" );
150  foreach ( [ 'si_title', 'si_text' ] as $field ) {
151  $sql = "ALTER TABLE $searchindex ADD FULLTEXT $field ($field)";
152  $dbw->query( $sql, __METHOD__ );
153  }
154  }
155 
159  private function clearSearchIndex() {
160  $dbw = $this->getDB( DB_PRIMARY );
161  $this->output( 'Clearing searchindex table...' );
162  $dbw->delete( 'searchindex', '*', __METHOD__ );
163  $this->output( "Done\n" );
164  }
165 }
166 
167 $maintClass = RebuildTextIndex::class;
168 require_once RUN_MAINTENANCE_IF_MAIN;
Exception representing a failure to serialize or unserialize a content object.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:66
getDB( $db, $groups=[], $dbDomain=false)
Returns a database to be used by current maintenance script.
output( $out, $channel=null)
Throw some output to the user.
const DB_ADMIN
Definition: Maintenance.php:73
addDescription( $text)
Set the description text.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Service locator for MediaWiki core services.
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
Maintenance script that rebuilds search index table from scratch.
execute()
Do the actual work.
getDbType()
Does the script need different DB access? By default, we give Maintenance scripts normal rights to th...
__construct()
Default constructor.
populateSearchIndex()
Populates the search index with content from all pages.
Database independent search index updater.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:638
This is the SQLite database abstraction layer.
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
const DB_PRIMARY
Definition: defines.php:28
$content
Definition: router.php:76
$revStore
$revQuery