28 require_once __DIR__ .
'/Maintenance.php';
40 private const RTI_CHUNK_SIZE = 500;
43 parent::__construct();
44 $this->
addDescription(
'Rebuild search index table from scratch' );
54 if ( $dbw->getType() ==
'postgres' ) {
55 $this->
fatalError(
"This script is not needed when using Postgres.\n" );
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" );
65 if ( $dbw->getType() ==
'mysql' ) {
66 $this->dropMysqlTextIndex();
67 $this->clearSearchIndex();
69 $this->createMysqlTextIndex();
71 $this->clearSearchIndex();
75 $this->
output(
"Done.\n" );
83 $res = $dbw->newSelectQueryBuilder()
84 ->select(
'MAX(page_id) AS count' )
86 ->caller( __METHOD__ )->fetchResultSet();
87 $s = $res->fetchObject();
89 $this->
output(
"Rebuilding index fields for {$count} pages...\n" );
93 $queryBuilderTemplate = $revStore->newSelectQueryBuilder( $dbw )
96 while ( $n < $count ) {
98 $this->
output( $n .
"\n" );
100 $end = $n + self::RTI_CHUNK_SIZE - 1;
101 $queryBuilder = clone $queryBuilderTemplate;
102 $res = $queryBuilder->where( [
"page_id BETWEEN $n AND $end",
'page_latest = rev_id' ] )
103 ->caller( __METHOD__ )->fetchResultSet();
105 foreach ( $res as $s ) {
108 if ( $s->page_namespace < 0 ) {
112 $title = Title::makeTitle( $s->page_namespace, $s->page_title );
114 $revRecord = $revStore->newRevisionFromRow( $s );
115 $content = $revRecord->getContent( SlotRecord::MAIN );
120 $this->
output(
"Failed to deserialize content of revision {$s->rev_id} of page "
121 .
"`" . $title->getPrefixedDBkey() .
"`!\n" );
124 $n += self::RTI_CHUNK_SIZE;
131 private function dropMysqlTextIndex() {
133 $searchindex = $dbw->tableName(
'searchindex' );
134 if ( $dbw->indexExists(
'searchindex',
'si_title', __METHOD__ ) ) {
135 $this->
output(
"Dropping index...\n" );
136 $sql =
"ALTER TABLE $searchindex DROP INDEX si_title, DROP INDEX si_text";
137 $dbw->query( $sql, __METHOD__ );
144 private function createMysqlTextIndex() {
146 $searchindex = $dbw->tableName(
'searchindex' );
147 $this->
output(
"\nRebuild the index...\n" );
148 foreach ( [
'si_title',
'si_text' ] as $field ) {
149 $sql =
"ALTER TABLE $searchindex ADD FULLTEXT $field ($field)";
150 $dbw->query( $sql, __METHOD__ );
157 private function clearSearchIndex() {
159 $this->
output(
'Clearing searchindex table...' );
160 $dbw->delete(
'searchindex',
'*', __METHOD__ );
161 $this->
output(
"Done\n" );
166 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...
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.
getServiceContainer()
Returns the main service container.
addDescription( $text)
Set the description text.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
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.