MediaWiki  REL1_24
SearchOracle.php
Go to the documentation of this file.
00001 <?php
00031 class SearchOracle extends SearchDatabase {
00032     private $reservedWords = array(
00033         'ABOUT' => 1,
00034         'ACCUM' => 1,
00035         'AND' => 1,
00036         'BT' => 1,
00037         'BTG' => 1,
00038         'BTI' => 1,
00039         'BTP' => 1,
00040         'FUZZY' => 1,
00041         'HASPATH' => 1,
00042         'INPATH' => 1,
00043         'MINUS' => 1,
00044         'NEAR' => 1,
00045         'NOT' => 1,
00046         'NT' => 1,
00047         'NTG' => 1,
00048         'NTI' => 1,
00049         'NTP' => 1,
00050         'OR' => 1,
00051         'PT' => 1,
00052         'RT' => 1,
00053         'SQE' => 1,
00054         'SYN' => 1,
00055         'TR' => 1,
00056         'TRSYN' => 1,
00057         'TT' => 1,
00058         'WITHIN' => 1,
00059     );
00060 
00067     function searchText( $term ) {
00068         if ( $term == '' ) {
00069             return new SqlSearchResultSet( false, '' );
00070         }
00071 
00072         $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), true ) );
00073         return new SqlSearchResultSet( $resultSet, $this->searchTerms );
00074     }
00075 
00082     function searchTitle( $term ) {
00083         if ( $term == '' ) {
00084             return new SqlSearchResultSet( false, '' );
00085         }
00086 
00087         $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), false ) );
00088         return new SqlSearchResultSet( $resultSet, $this->searchTerms );
00089     }
00090 
00095     function queryNamespaces() {
00096         if ( is_null( $this->namespaces ) ) {
00097             return '';
00098         }
00099         if ( !count( $this->namespaces ) ) {
00100             $namespaces = '0';
00101         } else {
00102             $namespaces = $this->db->makeList( $this->namespaces );
00103         }
00104         return 'AND page_namespace IN (' . $namespaces . ')';
00105     }
00106 
00114     function queryLimit( $sql ) {
00115         return $this->db->limitResult( $sql, $this->limit, $this->offset );
00116     }
00117 
00126     function queryRanking( $filteredTerm, $fulltext ) {
00127         return ' ORDER BY score(1)';
00128     }
00129 
00137     function getQuery( $filteredTerm, $fulltext ) {
00138         return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
00139             $this->queryNamespaces() . ' ' .
00140             $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
00141     }
00142 
00148     function getIndexField( $fulltext ) {
00149         return $fulltext ? 'si_text' : 'si_title';
00150     }
00151 
00159     function queryMain( $filteredTerm, $fulltext ) {
00160         $match = $this->parseQuery( $filteredTerm, $fulltext );
00161         $page = $this->db->tableName( 'page' );
00162         $searchindex = $this->db->tableName( 'searchindex' );
00163         return 'SELECT page_id, page_namespace, page_title ' .
00164             "FROM $page,$searchindex " .
00165             'WHERE page_id=si_page AND ' . $match;
00166     }
00167 
00175     function parseQuery( $filteredText, $fulltext ) {
00176         global $wgContLang;
00177         $lc = $this->legalSearchChars();
00178         $this->searchTerms = array();
00179 
00180         # @todo FIXME: This doesn't handle parenthetical expressions.
00181         $m = array();
00182         $searchon = '';
00183         if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
00184                 $filteredText, $m, PREG_SET_ORDER ) ) {
00185             foreach ( $m as $terms ) {
00186                 // Search terms in all variant forms, only
00187                 // apply on wiki with LanguageConverter
00188                 $temp_terms = $wgContLang->autoConvertToAllVariants( $terms[2] );
00189                 if ( is_array( $temp_terms ) ) {
00190                     $temp_terms = array_unique( array_values( $temp_terms ) );
00191                     foreach ( $temp_terms as $t ) {
00192                         $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $t );
00193                     }
00194                 }
00195                 else {
00196                     $searchon .= ( $terms[1] == '-' ? ' ~' : ' & ' ) . $this->escapeTerm( $terms[2] );
00197                 }
00198                 if ( !empty( $terms[3] ) ) {
00199                     $regexp = preg_quote( $terms[3], '/' );
00200                     if ( $terms[4] ) {
00201                         $regexp .= "[0-9A-Za-z_]+";
00202                     }
00203                 } else {
00204                     $regexp = preg_quote( str_replace( '"', '', $terms[2] ), '/' );
00205                 }
00206                 $this->searchTerms[] = $regexp;
00207             }
00208         }
00209 
00210         $searchon = $this->db->addQuotes( ltrim( $searchon, ' &' ) );
00211         $field = $this->getIndexField( $fulltext );
00212         return " CONTAINS($field, $searchon, 1) > 0 ";
00213     }
00214 
00215     private function escapeTerm( $t ) {
00216         global $wgContLang;
00217         $t = $wgContLang->normalizeForSearch( $t );
00218         $t = isset( $this->reservedWords[strtoupper( $t )] ) ? '{' . $t . '}' : $t;
00219         $t = preg_replace( '/^"(.*)"$/', '($1)', $t );
00220         $t = preg_replace( '/([-&|])/', '\\\\$1', $t );
00221         return $t;
00222     }
00223 
00232     function update( $id, $title, $text ) {
00233         $dbw = wfGetDB( DB_MASTER );
00234         $dbw->replace( 'searchindex',
00235             array( 'si_page' ),
00236             array(
00237                 'si_page' => $id,
00238                 'si_title' => $title,
00239                 'si_text' => $text
00240             ), 'SearchOracle::update' );
00241 
00242         // Sync the index
00243         // We need to specify the DB name (i.e. user/schema) here so that
00244         // it can work from the installer, where
00245         //     ALTER SESSION SET CURRENT_SCHEMA = ...
00246         // was used.
00247         $dbw->query( "CALL ctx_ddl.sync_index(" .
00248             $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_text_idx', 'raw' ) ) . ")" );
00249         $dbw->query( "CALL ctx_ddl.sync_index(" .
00250             $dbw->addQuotes( $dbw->getDBname() . '.' . $dbw->tableName( 'si_title_idx', 'raw' ) ) . ")" );
00251     }
00252 
00260     function updateTitle( $id, $title ) {
00261         $dbw = wfGetDB( DB_MASTER );
00262 
00263         $dbw->update( 'searchindex',
00264             array( 'si_title' => $title ),
00265             array( 'si_page' => $id ),
00266             'SearchOracle::updateTitle',
00267             array() );
00268     }
00269 
00270     public static function legalSearchChars() {
00271         return "\"" . parent::legalSearchChars();
00272     }
00273 }