Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
InterwikiSearcher
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 3
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getInterwikiResults
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
72
 getQueryCacheStatsKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace CirrusSearch;
4
5use CirrusSearch\Fallbacks\FallbackRunner;
6use CirrusSearch\Parser\BasicQueryClassifier;
7use CirrusSearch\Parser\NamespacePrefixParser;
8use CirrusSearch\Search\CrossProjectBlockScorerFactory;
9use CirrusSearch\Search\FullTextResultsType;
10use CirrusSearch\Search\MSearchRequests;
11use CirrusSearch\Search\SearchContext;
12use CirrusSearch\Search\SearchQuery;
13use CirrusSearch\Search\SearchQueryBuilder;
14use CirrusSearch\Search\TitleHelper;
15use MediaWiki\MediaWikiServices;
16use MediaWiki\Status\Status;
17use MediaWiki\User\User;
18
19/**
20 * Performs searches using Elasticsearch -- on interwikis!
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License along
33 * with this program; if not, write to the Free Software Foundation, Inc.,
34 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 * http://www.gnu.org/copyleft/gpl.html
36 */
37class InterwikiSearcher extends Searcher {
38
39    /**
40     * @param Connection $connection
41     * @param SearchConfig $config
42     * @param int[]|null $namespaces Namespace numbers to search, or null for all of them
43     * @param User|null $user
44     * @param CirrusDebugOptions|null $debugOptions
45     * @param NamespacePrefixParser|null $namespacePrefixParser
46     * @param InterwikiResolver|null $interwikiResolver
47     * @param TitleHelper|null $titleHelper
48     * @param CirrusSearchHookRunner|null $cirrusSearchHookRunner
49     */
50    public function __construct(
51        Connection $connection,
52        SearchConfig $config,
53        array $namespaces = null,
54        User $user = null,
55        CirrusDebugOptions $debugOptions = null,
56        NamespacePrefixParser $namespacePrefixParser = null,
57        InterwikiResolver $interwikiResolver = null,
58        TitleHelper $titleHelper = null,
59        CirrusSearchHookRunner $cirrusSearchHookRunner = null
60    ) {
61        $maxResults = $config->get( 'CirrusSearchNumCrossProjectSearchResults' );
62        parent::__construct( $connection, 0, $maxResults, $config, $namespaces, $user, false,
63            $debugOptions, $namespacePrefixParser, $interwikiResolver, $titleHelper, $cirrusSearchHookRunner );
64    }
65
66    /**
67     * Fetch search results, from caches, if there's any
68     * @param SearchQuery $query original search query
69     * @return Status
70     */
71    public function getInterwikiResults( SearchQuery $query ): Status {
72        $sources = MediaWikiServices::getInstance()
73            ->getService( InterwikiResolver::SERVICE )
74            ->getSisterProjectConfigs();
75        if ( !$sources ) {
76            // Nothing to search for
77            return Status::newGood( [] );
78        }
79
80        $iwQueries = [];
81        foreach ( $sources as $interwiki => $config ) {
82            $iwQueries[$interwiki] = SearchQueryBuilder::forCrossProjectSearch( $config, $query )
83                ->build();
84        }
85
86        $blockScorer = CrossProjectBlockScorerFactory::load( $this->config );
87        $msearches = new MSearchRequests();
88        foreach ( $iwQueries as $interwiki => $iwQuery ) {
89            $context = SearchContext::fromSearchQuery( $iwQuery,
90                FallbackRunner::create( $iwQuery, $this->interwikiResolver ), $this->cirrusSearchHookRunner );
91            $this->searchContext = $context;
92            $this->setResultsType( new FullTextResultsType(
93                $this->searchContext->getFetchPhaseBuilder(),
94                $query->getParsedQuery()->isQueryOfClass( BasicQueryClassifier::COMPLEX_QUERY ),
95                $this->titleHelper, [], $this->searchContext->getConfig()->getElement( 'CirrusSearchDeduplicateInMemory' ) === true ) );
96            $this->config = $context->getConfig();
97            $this->limit = $iwQuery->getLimit();
98            $this->offset = $iwQuery->getOffset();
99            $this->buildFullTextSearch( $query->getParsedQuery()->getQueryWithoutNsHeader() );
100            $this->indexBaseName = $context->getConfig()->get( 'CirrusSearchIndexBaseName' );
101            $search = $this->buildSearch();
102            if ( $this->searchContext->areResultsPossible() ) {
103                $msearches->addRequest( $interwiki, $search );
104            }
105        }
106
107        $searchDescription = "{$this->searchContext->getSearchType()} search for '{$this->searchContext->getOriginalSearchTerm()}'";
108        if ( $this->searchContext->getDebugOptions()->isCirrusDumpQuery() ) {
109            return $msearches->dumpQuery( $searchDescription );
110        }
111        $mresponses = $this->searchMulti( $msearches );
112        if ( $mresponses->hasFailure() ) {
113            return $mresponses->getFailure();
114        }
115
116        if ( $this->searchContext->getDebugOptions()->isReturnRaw() ) {
117            return $mresponses->dumpResults( $searchDescription );
118        }
119
120        return $mresponses->transformAndGetMulti( $this->searchContext->getResultsType(), array_keys( $iwQueries ),
121            static function ( array $v ) use ( $blockScorer ) {
122                return $blockScorer->reorder( $v );
123            } );
124    }
125
126    /**
127     * @return string The stats key used for reporting hit/miss rates of the
128     *  application side query cache.
129     */
130    protected function getQueryCacheStatsKey() {
131        return 'CirrusSearch.query_cache.interwiki';
132    }
133}