%PDF- %PDF-
Direktori : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/maintenance/ |
Current File : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/maintenance/runSearch.php |
<?php namespace CirrusSearch\Maintenance; use CirrusSearch; use CirrusSearch\SearchConfig; use CirrusSearch\Search\ResultSet; use RequestContext; use SearchSuggestionSet; use Status; /** * Run search queries provided on stdin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html */ $IP = getenv( 'MW_INSTALL_PATH' ); if( $IP === false ) { $IP = __DIR__ . '/../../..'; } require_once( "$IP/maintenance/Maintenance.php" ); require_once( __DIR__ . '/../includes/Maintenance/Maintenance.php' ); class RunSearch extends Maintenance { /** * @var string */ protected $indexBaseName; public function __construct() { parent::__construct(); $this->addDescription( 'Run one or more searches against the specified cluster. ' . 'search queries are read from stdin.' ); $this->addOption( 'baseName', 'What basename to use for all indexes, ' . 'defaults to wiki id', false, true ); $this->addOption( 'type', 'What type of search to run, prefix, suggest or full_text. ' . 'defaults to full_text.', false, true ); $this->addOption( 'options', 'A JSON object mapping from global variable to ' . 'its test value', false, true ); $this->addOption( 'fork', 'Fork multiple processes to run queries from.' . 'defaults to false.', false, true ); $this->addOption( 'decode', 'urldecode() queries before running them', false, false ); $this->addOption( 'explain', 'Include lucene explanation in the results', false, false ); $this->addOption( 'limit', 'Set the max number of results returned by query (defaults to 10)', false, true ); } public function execute() { $this->disablePoolCountersAndLogging(); $this->indexBaseName = $this->getOption( 'baseName', $this->getSearchConfig()->get( SearchConfig::INDEX_BASE_NAME ) ); $this->applyGlobals(); $callback = [ $this, 'consume' ]; $forks = $this->getOption( 'fork', false ); $forks = ctype_digit( $forks ) ? intval( $forks ) : 0; $controller = new OrderedStreamingForkController( $forks, $callback, STDIN, STDOUT ); $controller->start(); } /** * Applies global variables provided as the options CLI argument * to override current settings. */ protected function applyGlobals() { $options = json_decode( $this->getOption( 'options', 'false' ), true ); if ( $options ) { foreach ( $options as $key => $value ) { if ( array_key_exists( $key, $GLOBALS ) ) { $GLOBALS[$key] = $value; } else { $this->error( "\nERROR: $key is not a valid global variable\n" ); exit(); } } } } /** * Transform the search request into a JSON string representing the * search result. * * @param string $query * @return string JSON object */ public function consume( $query ) { if ( $this->getOption( 'decode' ) ) { $query = urldecode( $query ); } $data = [ 'query' => $query ]; $status = $this->searchFor( $query ); if ( $status->isOK() ) { $value = $status->getValue(); if ( $value instanceof ResultSet ) { // these are prefix or full text results $data['totalHits'] = $value->getTotalHits(); $data['rows'] = []; $result = $value->next(); while ( $result ) { $data['rows'][] = [ // use getDocId() rather than asking the title to allow this script // to work when a production index has been imported to a test es instance 'docId' => $result->getDocId(), 'title' => $result->getTitle()->getPrefixedText(), 'score' => $result->getScore(), 'snippets' => [ 'text' => $result->getTextSnippet( $query ), 'title' => $result->getTitleSnippet(), 'redirect' => $result->getRedirectSnippet(), 'section' => $result->getSectionSnippet(), 'category' => $result->getCategorySnippet(), ], 'explanation' => $result->getExplanation(), ]; $result = $value->next(); } } elseif ( $value instanceof SearchSuggestionSet ) { // these are suggestion results $data['totalHits'] = $value->getSize(); foreach ( $value->getSuggestions() as $suggestion ) { $data['rows'][] = [ 'pageId' => $suggestion->getSuggestedTitleID(), 'title' => $suggestion->getSuggestedTitle()->getPrefixedText(), 'snippets' => [], ]; } } else { throw new \RuntimeException( "Unknown result type: " . is_object( $value ) ? get_class( $value ) : gettype( $value ) ); } } else { $data['error'] = $status->getMessage()->text(); } return json_encode( $data ); } /** * Transform the search request into a Status object representing the * search result. Varies based on CLI input argument `type`. * * @param string $query * @return Status<ResultSet> */ protected function searchFor( $query ) { $searchType = $this->getOption( 'type', 'full_text' ); $limit = $this->getOption( 'limit', 10 ); if ( $this->getOption( 'explain' ) ) { RequestContext::getMain()->getRequest()->setVal( 'cirrusExplain', true ); } $engine = new CirrusSearch( $this->indexBaseName ); $engine->setConnection( $this->getConnection() ); $engine->setLimitOffset( $limit ); switch ( $searchType ) { case 'full_text': // @todo pass through $this->getConnection() ? $result = $engine->searchText( $query ); if ( $result instanceof Status ) { return $result; } else { return Status::newGood( $result ); } case 'prefix': $titles = $engine->defaultPrefixSearch( $query ); $resultSet = SearchSuggestionSet::fromTitles( $titles ); return Status::newGood( $resultSet ); case 'suggest': $engine->setFeatureData( CirrusSearch::COMPLETION_SUGGESTER_FEATURE, true ); $result = $engine->completionSearch( $query ); if ( $result instanceof Status ) { return $result; } else { return Status::newGood( $result ); } default: $this->error( "\nERROR: Unknown search type $searchType\n" ); exit( 1 ); } } } $maintClass = RunSearch::class; require_once RUN_MAINTENANCE_IF_MAIN;