Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Searcher
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 4
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 performSearch
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
20
 newLog
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getRelevanceRescoreConfigurations
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace GeoData;
4
5use CirrusSearch\Connection;
6use CirrusSearch\ElasticsearchIntermediary;
7use CirrusSearch\Search\SearchContext;
8use CirrusSearch\SearchConfig;
9use CirrusSearch\SearchRequestLog;
10use CirrusSearch\Util;
11use Elastica\Exception\ExceptionInterface;
12use Elastica\Exception\ResponseException;
13use Elastica\Query;
14use Elastica\ResultSet;
15use Elastica\Search;
16use MediaWiki\Config\ConfigException;
17use MediaWiki\MediaWikiServices;
18use MediaWiki\User\UserIdentity;
19use MediaWiki\WikiMap\WikiMap;
20use StatusValue;
21
22/**
23 * Performs ES searches via CirrusSearch infrastructure
24 */
25class Searcher extends ElasticsearchIntermediary {
26
27    private SearchConfig $config;
28
29    /**
30     * @param UserIdentity|null $user
31     * @throws ConfigException
32     */
33    public function __construct( ?UserIdentity $user = null ) {
34        /** @var SearchConfig $config */
35        $config = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'CirrusSearch' );
36        '@phan-var SearchConfig $config';
37        $this->config = $config;
38        $connection = new Connection( $config );
39
40        parent::__construct( $connection, $user, 0 );
41    }
42
43    /**
44     * Perform search
45     *
46     * @param Query $query
47     * @param int[] $namespaces Namespaces used
48     * @param string $queryType Query description for logging
49     * @return StatusValue<ResultSet>
50     * @throws ExceptionInterface
51     */
52    public function performSearch( Query $query, array $namespaces, string $queryType ): StatusValue {
53        $indexSuffix = $this->connection->pickIndexSuffixForNamespaces( $namespaces );
54        $index = $this->connection->getIndex( WikiMap::getCurrentWikiId(), $indexSuffix );
55        $search = $index->createSearch( $query );
56
57        $this->connection->setTimeout( $this->getClientTimeout( $queryType ) );
58        $search->setOption( Search::OPTION_TIMEOUT, $this->getTimeout( $queryType ) );
59
60        $work = function () use ( $search, $queryType, $namespaces ) {
61            try {
62                $log = $this->newLog( 'performing {queryType}', $queryType, [], $namespaces );
63                $this->start( $log );
64                $result = $search->search();
65                if ( !$result->getResponse()->isOk() ) {
66                    $req = $this->connection->getClient()->getLastRequest();
67                    // Not really the right exception, this is probably a status code problem.
68                    // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
69                    throw new ResponseException( $req, $result->getResponse() );
70                }
71                $this->success();
72                $status = StatusValue::newGood( $result );
73                if ( $result->getResponse()->getData()['timed_out'] ?? false ) {
74                    // only partial results returned
75                    $status->warning( 'geodata-search-timeout' );
76                }
77                return $status;
78            } catch ( ExceptionInterface $ex ) {
79                return $this->failure( $ex );
80            }
81        };
82        return Util::doPoolCounterWork( $queryType, $this->user, $work );
83    }
84
85    /**
86     * @param string $description
87     * @param string $queryType
88     * @param string[] $extra
89     * @param array|null $namespaces
90     * @return SearchRequestLog
91     */
92    protected function newLog(
93        $description,
94        $queryType,
95        array $extra = [],
96        ?array $namespaces = null
97    ): SearchRequestLog {
98        return new SearchRequestLog(
99            $this->connection->getClient(),
100            $description,
101            $queryType,
102            $extra,
103            $namespaces
104        );
105    }
106
107    /**
108     * @param int[] $namespaces
109     * @return array[] Rescore configurations as used by elasticsearch.
110     */
111    public function getRelevanceRescoreConfigurations( array $namespaces ): array {
112        $searchContext = new SearchContext( $this->config, $namespaces );
113        return $searchContext->getRescore();
114    }
115}