Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 45 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
MetaNamespaceStore | |
0.00% |
0 / 45 |
|
0.00% |
0 / 7 |
132 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
docId | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
buildIndexProperties | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
reindex | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
find | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
queryFilter | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
buildDocuments | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | namespace CirrusSearch\MetaStore; |
4 | |
5 | use Elastica\Document; |
6 | use Elastica\Index; |
7 | use Elastica\Query\BoolQuery; |
8 | use Elastica\Query\Ids; |
9 | use Elastica\Query\MatchQuery; |
10 | use MediaWiki\WikiMap\WikiMap; |
11 | |
12 | class MetaNamespaceStore implements MetaStore { |
13 | /** @const Value of metastore 'type' field for our documents */ |
14 | public const METASTORE_TYPE = 'namespace'; |
15 | |
16 | /** @var Index */ |
17 | private $index; |
18 | |
19 | /** @var string */ |
20 | private $wikiId; |
21 | |
22 | public function __construct( Index $index, $wikiId = null ) { |
23 | $this->index = $index; |
24 | $this->wikiId = $wikiId ?? WikiMap::getCurrentWikiId(); |
25 | } |
26 | |
27 | /** |
28 | * @param string $wikiId Wiki namespace belongs to |
29 | * @param int $nsId Id of the namespace |
30 | * @return string Metastore document id |
31 | */ |
32 | public static function docId( $wikiId, $nsId ) { |
33 | return implode( '-', [ |
34 | self::METASTORE_TYPE, |
35 | $wikiId, $nsId |
36 | ] ); |
37 | } |
38 | |
39 | /** |
40 | * @return array Custom field mappings for metastore index |
41 | */ |
42 | public function buildIndexProperties() { |
43 | return [ |
44 | 'namespace_name' => [ |
45 | 'type' => 'text', |
46 | 'analyzer' => 'near_match_asciifolding', |
47 | 'norms' => false, |
48 | 'index_options' => 'docs', |
49 | ], |
50 | ]; |
51 | } |
52 | |
53 | /** |
54 | * Delete and re-index all namespaces for current wiki |
55 | * |
56 | * @param \Language $lang Content language of the wiki |
57 | */ |
58 | public function reindex( \Language $lang ) { |
59 | $documents = $this->buildDocuments( $lang ); |
60 | $docIds = []; |
61 | foreach ( $documents as $doc ) { |
62 | $docIds[] = $doc->getId(); |
63 | } |
64 | $this->index->deleteByQuery( \Elastica\Query::create( |
65 | $this->queryFilter()->addMustNot( new Ids( $docIds ) ) ) ); |
66 | $this->index->addDocuments( $documents ); |
67 | } |
68 | |
69 | /** |
70 | * Find namespaces on the current wiki very similar to $name. |
71 | * Invoking from a user request must be gated on a PoolCounter. |
72 | * |
73 | * @param string $name Namespace to search for |
74 | * @param array $queryOptions Query parameters to send to elasticsearch |
75 | * @return \Elastica\ResultSet |
76 | */ |
77 | public function find( $name, array $queryOptions = [] ) { |
78 | $bool = $this->queryFilter(); |
79 | $bool->addMust( ( new MatchQuery() ) |
80 | ->setField( 'namespace_name', $name ) ); |
81 | $query = ( new \Elastica\Query( $bool ) ) |
82 | ->setParam( '_source', [ 'namespace_id' ] ) |
83 | ->setParam( 'stats', [ 'namespace' ] ); |
84 | |
85 | return $this->index->search( $query, $queryOptions ); |
86 | } |
87 | |
88 | private function queryFilter() { |
89 | return ( new BoolQuery() ) |
90 | ->addFilter( new MatchQuery( 'type', self::METASTORE_TYPE ) ) |
91 | ->addFilter( new MatchQuery( 'wiki', $this->wikiId ) ); |
92 | } |
93 | |
94 | private function buildDocuments( \Language $lang ) { |
95 | $namesByNsId = []; |
96 | foreach ( $lang->getNamespaceIds() as $name => $nsId ) { |
97 | if ( $name ) { |
98 | $namesByNsId[$nsId][] = $name; |
99 | } |
100 | } |
101 | $documents = []; |
102 | foreach ( $namesByNsId as $nsId => $names ) { |
103 | $documents[] = new Document( self::docId( $this->wikiId, $nsId ), [ |
104 | 'type' => self::METASTORE_TYPE, |
105 | 'wiki' => $this->wikiId, |
106 | 'namespace_id' => $nsId, |
107 | 'namespace_name' => $names, |
108 | ], '_doc' ); |
109 | } |
110 | return $documents; |
111 | } |
112 | } |