/** * Check if we need to make a job and inject one if so. * @param Title[] $titles The title we might update * @param string|null $cluster The name of the cluster to write * to, or null for all clusters. */ public static function queueIfRequired($titles, $cluster) { $titlesToUpdate = array(); foreach ($titles as $title) { if (OtherIndexes::getExternalIndexes($title)) { $titlesToUpdate[] = array($title->getNamespace(), $title->getText()); } } if ($titlesToUpdate) { // Note that we're updating a bunch of titles but we have to pick one to // attach to the job so we pick the first one. JobQueueGroup::singleton()->push(new self($titles[0], array('titles' => $titlesToUpdate, 'cluster' => $cluster))); } }
/** * Update the indexes for other wiki that also store information about $titles. * @param Title[] $titles array of titles in other indexes to update */ public function updateOtherIndex($titles) { global $wgCirrusSearchWikimediaExtraPlugin; if (!isset($wgCirrusSearchWikimediaExtraPlugin['super_detect_noop'])) { $this->logFailure($titles, 'super_detect_noop plugin not enabled'); return; } $updates = array(); // Build multisearch to find ids to update $findIdsMultiSearch = new \Elastica\Multi\Search($this->connection->getClient()); $findIdsClosures = array(); foreach ($titles as $title) { foreach (OtherIndexes::getExternalIndexes($title) as $otherIndex) { if ($otherIndex === null) { continue; } $type = $this->connection->getPageType($otherIndex); $bool = new \Elastica\Filter\Bool(); // Note that we need to use the keyword indexing of title so the analyzer gets out of the way. $bool->addMust(new \Elastica\Filter\Term(array('title.keyword' => $title->getText()))); $bool->addMust(new \Elastica\Filter\Term(array('namespace' => $title->getNamespace()))); $filtered = new \Elastica\Query\Filtered(new \Elastica\Query\MatchAll(), $bool); $query = new \Elastica\Query($filtered); $query->setFields(array()); // We only need the _id so don't load the _source $query->setSize(1); $findIdsMultiSearch->addSearch($type->createSearch($query)); $findIdsClosures[] = function ($id) use($otherIndex, &$updates, $title) { $updates[$otherIndex][] = array('id' => $id, 'ns' => $title->getNamespace(), 'dbKey' => $title->getDBkey()); }; } } $findIdsClosuresCount = count($findIdsClosures); if ($findIdsClosuresCount === 0) { // No other indexes to check. return; } // Look up the ids and run all closures to build the list of updates $this->start("searching for {numIds} ids in other indexes", array('numIds' => $findIdsClosuresCount)); $findIdsMultiSearchResult = $findIdsMultiSearch->search(); try { $this->success(); for ($i = 0; $i < $findIdsClosuresCount; $i++) { $results = $findIdsMultiSearchResult[$i]->getResults(); if (count($results) === 0) { continue; } $result = $results[0]; call_user_func($findIdsClosures[$i], $result->getId()); } } catch (\Elastica\Exception\ExceptionInterface $e) { $this->failure($e); return; } if (!$updates) { return; } // These are split into a job per index so one index // being frozen doesn't block updates to other indexes // in the same update. foreach ($updates as $indexName => $actions) { $job = new Job\ElasticaWrite(reset($titles), array('clientSideTimeout' => false, 'method' => 'sendOtherIndexUpdates', 'arguments' => array($this->localSite, $indexName, $actions), 'cluster' => $this->writeToClusterName)); $job->run(); } }