private function decideCluster(SearchConfig $config) { $cluster = $this->getOption('cluster', null); if ($cluster === null) { return null; } if ($config->has('CirrusSearchServers')) { $this->error('Not configured for cluster operations.', 1); } $hosts = $config->getElement('CirrusSearchClusters', $cluster); if ($hosts === null) { $this->error('Unknown cluster.', 1); } return $cluster; }
/** * @param string $query * @param boolean $isRescore * @return \Elastica\Query\Simple */ public function wrapInSaferIfPossible($query, $isRescore) { // @todo: move this code to a common base class when Filters is refactored as non-static $saferQuery = $this->config->getElement('CirrusSearchWikimediaExtraPlugin', 'safer'); if (is_null($saferQuery)) { return $query; } $saferQuery['query'] = $query->toArray(); $tooLargeAction = $isRescore ? 'convert_to_match_all_query' : 'convert_to_term_queries'; $saferQuery['phrase']['phrase_too_large_action'] = $tooLargeAction; return new \Elastica\Query\Simple(array('safer' => $saferQuery)); }
/** * Is there more then one namespace in the provided index type? * @var string $indexType an index type * @return false|integer false if the number of indexes is unknown, an integer if it is known */ public function namespacesInIndexType($indexType) { if ($indexType === self::GENERAL_INDEX_TYPE) { return false; } $mappings = $this->config->get('CirrusSearchNamespaceMappings'); $count = count(array_keys($mappings, $indexType)); if ($indexType === self::CONTENT_INDEX_TYPE) { // The content namespace includes everything set in the mappings to content (count right now) // Plus everything in wgContentNamespaces that isn't already in namespace mappings $contentNamespaces = $this->config->get('ContentNamespaces'); $count += count(array_diff($contentNamespaces, array_keys($mappings))); } return $count; }
/** * Get the weight of a namespace. * @param int $namespace the namespace * @return float the weight of the namespace */ private function getBoostForNamespace($namespace) { if ($this->normalizedNamespaceWeights === null) { $this->normalizedNamespaceWeights = array(); foreach ($this->config->get('CirrusSearchNamespaceWeights') as $ns => $weight) { if (is_string($ns)) { $ns = $this->language->getNsIndex($ns); // Ignore namespaces that don't exist. if ($ns === false) { continue; } } // Now $ns should always be an integer. $this->normalizedNamespaceWeights[$ns] = $weight; } } if (isset($this->normalizedNamespaceWeights[$namespace])) { return $this->normalizedNamespaceWeights[$namespace]; } if (MWNamespace::isSubject($namespace)) { if ($namespace === NS_MAIN) { return 1; } return $this->config->get('CirrusSearchDefaultNamespaceWeight'); } $subjectNs = MWNamespace::getSubject($namespace); if (isset($this->normalizedNamespaceWeights[$subjectNs])) { return $this->config->get('CirrusSearchTalkNamespaceWeight') * $this->normalizedNamespaceWeights[$subjectNs]; } if ($namespace === NS_TALK) { return $this->config->get('CirrusSearchTalkNamespaceWeight'); } return $this->config->get('CirrusSearchDefaultNamespaceWeight') * $this->config->get('CirrusSearchTalkNamespaceWeight'); }
/** * prepare the list of suggest requests used for geo context suggestions * This method will merge $this->config->get( 'CirrusSearchCompletionSettings and * $this->config->get( 'CirrusSearchCompletionGeoContextSettings * @param array $context user's geo context * @return array of suggest request profiles */ private function prepareGeoContextSuggestProfiles() { $profiles = array(); foreach ($this->config->get('CirrusSearchCompletionGeoContextSettings') as $geoname => $geoprof) { foreach ($this->config->get('CirrusSearchCompletionSettings') as $sugname => $sugprof) { if (!in_array($sugname, $geoprof['with'])) { continue; } $profile = $sugprof; $profile['field'] .= $geoprof['field_suffix']; $profile['discount'] *= $geoprof['discount']; $profile['context'] = array('location' => array('lat' => $this->context['geo']['lat'], 'lon' => $this->context['geo']['lon'], 'precision' => $geoprof['precision'])); $profiles["{$sugname}-{$geoname}"] = $profile; } } return $profiles; }
private function searchTextReal($term, SearchConfig $config = null) { global $wgCirrusSearchInterwikiSources; // Convert the unicode character 'idiographic whitespace' into standard // whitespace. Cirrussearch treats them both as normal whitespace, but // the preceding isn't appropriatly trimmed. $term = trim(str_replace(" ", " ", $term)); // No searching for nothing! That takes forever! if (!$term) { return null; } $context = RequestContext::getMain(); $request = $context->getRequest(); $user = $context->getUser(); if ($config) { $this->indexBaseName = $config->getWikiId(); } $searcher = new Searcher($this->connection, $this->offset, $this->limit, $config, $this->namespaces, $user, $this->indexBaseName); // Ignore leading ~ because it is used to force displaying search results but not to effect them if (substr($term, 0, 1) === '~') { $term = substr($term, 1); $searcher->addSuggestPrefix('~'); } // TODO remove this when we no longer have to support core versions without // Ie946150c6796139201221dfa6f7750c210e97166 if (method_exists($this, 'getSort')) { $searcher->setSort($this->getSort()); } $dumpQuery = $request && $request->getVal('cirrusDumpQuery') !== null; $searcher->setReturnQuery($dumpQuery); $dumpResult = $request && $request->getVal('cirrusDumpResult') !== null; $searcher->setDumpResult($dumpResult); $returnExplain = $request && $request->getVal('cirrusExplain') !== null; $searcher->setReturnExplain($returnExplain); // Delegate to either searchText or moreLikeThisArticle and dump the result into $status if (substr($term, 0, strlen(self::MORE_LIKE_THIS_PREFIX)) === self::MORE_LIKE_THIS_PREFIX) { $term = substr($term, strlen(self::MORE_LIKE_THIS_PREFIX)); $status = $this->moreLikeThis($term, $searcher, Searcher::MORE_LIKE_THESE_NONE); } else { if (substr($term, 0, strlen(self::MORE_LIKE_THIS_JUST_WIKIBASE_PREFIX)) === self::MORE_LIKE_THIS_JUST_WIKIBASE_PREFIX) { $term = substr($term, strlen(self::MORE_LIKE_THIS_JUST_WIKIBASE_PREFIX)); $status = $this->moreLikeThis($term, $searcher, Searcher::MORE_LIKE_THESE_ONLY_WIKIBASE); } else { # Namespace lookup should not be done for morelike special syntax (T111244) if ($this->lastNamespacePrefix) { $searcher->addSuggestPrefix($this->lastNamespacePrefix); } else { $searcher->updateNamespacesFromQuery($term); } $highlightingConfig = FullTextResultsType::HIGHLIGHT_ALL; if ($request) { if ($request->getVal('cirrusSuppressSuggest') !== null) { $this->showSuggestion = false; } if ($request->getVal('cirrusSuppressTitleHighlight') !== null) { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_TITLE; } if ($request->getVal('cirrusSuppressAltTitle') !== null) { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_ALT_TITLE; } if ($request->getVal('cirrusSuppressSnippet') !== null) { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_SNIPPET; } if ($request->getVal('cirrusHighlightDefaultSimilarity') === 'no') { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_WITH_DEFAULT_SIMILARITY; } if ($request->getVal('cirrusHighlightAltTitleWithPostings') === 'no') { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_ALT_TITLES_WITH_POSTINGS; } } if ($this->namespaces && !in_array(NS_FILE, $this->namespaces)) { $highlightingConfig ^= FullTextResultsType::HIGHLIGHT_FILE_TEXT; } $searcher->setResultsType(new FullTextResultsType($highlightingConfig, $config ? $config->getWikiCode() : '')); $status = $searcher->searchText($term, $this->showSuggestion); } } if ($dumpQuery || $dumpResult) { // When dumping the query we skip _everything_ but echoing the query. $context->getOutput()->disable(); $request->response()->header('Content-type: application/json; charset=UTF-8'); if ($status->getValue() === null) { echo '{}'; } else { echo json_encode($status->getValue()); } exit; } $this->lastSearchMetrics = $searcher->getSearchMetrics(); // Add interwiki results, if we have a sane result // Note that we have no way of sending warning back to the user. In this case all warnings // are logged when they are added to the status object so we just ignore them here.... if ($status->isOK() && $wgCirrusSearchInterwikiSources && $status->getValue() && method_exists($status->getValue(), 'addInterwikiResults')) { // @todo @fixme: This should absolutely be a multisearch. I knew this when I // wrote the code but Searcher needs some refactoring first. foreach ($wgCirrusSearchInterwikiSources as $interwiki => $index) { $iwSearch = new InterwikiSearcher($this->connection, $this->namespaces, $user, $index, $interwiki); $interwikiResult = $iwSearch->getInterwikiResults($term); if ($interwikiResult) { $status->getValue()->addInterwikiResults($interwikiResult); } } } // For historical reasons all callers of searchText interpret any Status return as an error // so we must unwrap all OK statuses. Note that $status can be "good" and still contain null // since that is interpreted as no results. return $status->isOk() ? $status->getValue() : $status; }