60 private $sort = self::DEFAULT_SORT;
140 return Status::newGood( [] );
187 $resultSetOrStatus = $fn();
194 $resultSet = $resultSetOrStatus;
195 } elseif ( $resultSetOrStatus instanceof
Status &&
198 $resultSet = $resultSetOrStatus->getValue();
201 $resultSet->shrink( $this->limit );
204 return $resultSetOrStatus;
215 switch ( $feature ) {
216 case 'search-update':
218 case 'title-suffix-filter':
231 $this->features[$feature] = $data;
242 return $this->features[$feature] ??
null;
255 return MediaWikiServices::getInstance()->getContentLanguage()->segmentByWord( $string );
265 MediaWikiServices::getInstance()->getContentLanguage(),
275 $services = MediaWikiServices::getInstance();
276 $config = $services->getMainConfig();
277 return $services->newSearchEngine()->getNearMatcher( $config );
287 return "A-Za-z_'.0-9\\x80-\\xFF\\-";
298 $this->limit = intval(
$limit );
299 $this->offset = intval(
$offset );
311 $validNs = MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
313 return $ns < 0 || isset( $validNs[$ns] );
342 return [ self::DEFAULT_SORT ];
355 throw new InvalidArgumentException(
"Invalid sort: $sort. " .
356 "Must be one of: " . implode(
', ', $this->
getValidSorts() ) );
401 $withAllKeyword =
true,
402 $withPrefixSearchExtractNamespaceHook =
false
405 if ( strpos( $query,
':' ) ===
false ) {
408 $extractedNamespace =
null;
411 if ( $withAllKeyword ) {
414 $allkeywords[] =
wfMessage(
'searchall' )->inContentLanguage()->text() .
":";
416 if ( !in_array(
'all:', $allkeywords ) ) {
417 $allkeywords[] =
'all:';
420 foreach ( $allkeywords as $kw ) {
421 if ( strncmp( $query, $kw, strlen( $kw ) ) == 0 ) {
422 $parsed = substr( $query, strlen( $kw ) );
429 if ( !$allQuery && strpos( $query,
':' ) !==
false ) {
430 $prefix = str_replace(
' ',
'_', substr( $query, 0, strpos( $query,
':' ) ) );
431 $index = MediaWikiServices::getInstance()->getContentLanguage()->getNsIndex(
$prefix );
432 if ( $index !==
false ) {
433 $extractedNamespace = [ $index ];
434 $parsed = substr( $query, strlen(
$prefix ) + 1 );
435 } elseif ( $withPrefixSearchExtractNamespaceHook ) {
438 Hooks::runner()->onPrefixSearchExtractNamespace( $hookNamespaces, $hookQuery );
439 if ( $hookQuery !== $query ) {
440 $parsed = $hookQuery;
441 $extractedNamespace = $hookNamespaces;
450 return [ $parsed, $extractedNamespace ];
463 return [ $contextlines, $contextchars ];
515 return $c ? $c->getTextForSearchIndex() :
'';
537 $queryAndNs = self::parseNamespacePrefixes( $search,
false,
true );
538 if ( $queryAndNs !==
false ) {
540 return $queryAndNs[0];
574 $search = trim( $search );
576 if ( !in_array(
NS_SPECIAL, $this->namespaces ) &&
578 $this->namespaces, $search, $this->limit, $results, $this->offset )
597 if ( trim( $search ) ===
'' ) {
613 if ( trim( $search ) ===
'' ) {
619 $fallbackLimit = 1 + $this->limit - $results->getSize();
620 if ( $fallbackLimit > 0 ) {
621 $services = MediaWikiServices::getInstance();
622 $fallbackSearches = $services->getLanguageConverterFactory()
623 ->getLanguageConverter( $services->getContentLanguage() )
624 ->autoConvertToAllVariants( $search );
625 $fallbackSearches = array_diff( array_unique( $fallbackSearches ), [ $search ] );
627 foreach ( $fallbackSearches as $fbs ) {
630 $results->appendAll( $fallbackSearchResult );
631 $fallbackLimit -= $fallbackSearchResult->getSize();
632 if ( $fallbackLimit <= 0 ) {
661 $suggestions->
shrink( $this->limit );
663 $search = trim( $search );
665 $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
666 $lb = $linkBatchFactory->newLinkBatch( $suggestions->
map(
static function (
SearchSuggestion $sugg ) {
669 $lb->setCaller( __METHOD__ );
676 MediaWikiServices::getInstance()->getStatsdDataFactory()
677 ->updateCount(
'search.completion.missing', $diff );
684 if ( $this->offset === 0 ) {
691 $rescoredResults = $rescorer->rescore( $search, $this->namespaces, $results, $this->limit );
696 $rescoredResults = $results;
699 if ( count( $rescoredResults ) > 0 ) {
700 $found = array_search( $rescoredResults[0], $results );
701 if ( $found ===
false ) {
704 $exactMatch = SearchSuggestion::fromTitle( 0, Title::newFromText( $rescoredResults[0] ) );
705 $suggestions->
prepend( $exactMatch );
706 $suggestions->
shrink( $this->limit );
710 $suggestions->
rescore( $found );
724 if ( trim( $search ) ===
'' ) {
741 return $backend->
defaultSearchBackend( $this->namespaces, $search, $this->limit, $this->offset );
786 $models = MediaWikiServices::getInstance()->getContentHandlerFactory()->getContentModels();
788 $seenHandlers =
new SplObjectStorage();
789 foreach ( $models as $model ) {
791 $handler = MediaWikiServices::getInstance()
792 ->getContentHandlerFactory()
793 ->getContentHandler( $model );
800 if ( $seenHandlers->contains( $handler ) ) {
804 $seenHandlers->attach( $handler );
805 $handlerFields = $handler->getFieldsForSearchIndex( $this );
806 foreach ( $handlerFields as $fieldName => $fieldData ) {
807 if ( empty( $fields[$fieldName] ) ) {
808 $fields[$fieldName] = $fieldData;
811 $mergeDef = $fields[$fieldName]->merge( $fieldData );
813 throw new InvalidArgumentException(
"Duplicate field $fieldName for model $model" );
815 $fields[$fieldName] = $mergeDef;
820 $this->
getHookRunner()->onSearchIndexFields( $fields, $this );
832 $this->
getHookRunner()->onSearchResultsAugment( $setAugmentors, $rowAugmentors );
833 if ( !$setAugmentors && !$rowAugmentors ) {
839 foreach ( $rowAugmentors as $name => $row ) {
840 if ( isset( $setAugmentors[$name] ) ) {
841 throw new InvalidArgumentException(
"Both row and set augmentors are defined for $name" );
850 foreach ( $setAugmentors as $name => $augmentor ) {
851 $data = $augmentor->augmentAll( $resultSet );
864 $this->hookContainer = $hookContainer;
865 $this->hookRunner =
new HookRunner( $hookContainer );
875 if ( !$this->hookContainer ) {
879 $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
881 return $this->hookContainer;
893 if ( !$this->hookRunner ) {
894 $this->hookRunner =
new HookRunner( $this->getHookContainer() );
896 return $this->hookRunner;
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(ini_get('mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Exception thrown when an unregistered content model is requested.
Null index field - means search engine does not implement this field.
Perform augmentation of each row and return composite result, indexed by ID.
defaultSearchBackend( $namespaces, $search, $limit, $offset)
Unless overridden by PrefixSearchBackend hook... This is case-sensitive (First character may be autom...
Contain a class for special pages.
completionSearchBackendOverfetch( $search)
Perform an overfetch of completion search results.
makeSearchFieldMapping( $name, $type)
Create a search field definition.
getNearMatcher(Config $config)
Get service class to finding near matches.
getHookRunner()
Get a HookRunner for running core hooks.
searchTitle( $term)
Perform a title-only search query and return a result set.
maybePaginate(Closure $fn)
Performs an overfetch and shrink operation to determine if the next page is available for search engi...
processCompletionResults( $search, SearchSuggestionSet $suggestions)
Process completion search results.
getFeatureData( $feature)
Way to retrieve custom data set by setFeatureData or by the engine itself.
update( $id, $title, $text)
Create or update the search index record for the given page.
setNamespaces( $namespaces)
Set which namespaces the search should include.
static parseNamespacePrefixes( $query, $withAllKeyword=true, $withPrefixSearchExtractNamespaceHook=false)
Parse some common prefixes: all (search everything) or namespace names.
doSearchArchiveTitle( $term)
Perform a title search in the article archive.
array $features
Feature values.
replacePrefixes( $query)
Parse some common prefixes: all (search everything) or namespace names and set the list of namespaces...
textAlreadyUpdatedForIndex()
If an implementation of SearchEngine handles all of its own text processing in getTextFromContent() a...
defaultPrefixSearch( $search)
Simple prefix search for subpages.
augmentSearchResults(ISearchResultSet $resultSet)
Augment search results with extra data.
searchArchiveTitle( $term)
Perform a title search in the article archive.
normalizeText( $string)
When overridden in derived class, performs database-specific conversions on text to be used for searc...
setFeatureData( $feature, $data)
Way to pass custom data for engines.
completionSearchBackend( $search)
Perform a completion search.
getTextFromContent(Title $t, Content $c=null)
Get the raw text for updating the index from a content object Nicer search backends could possibly do...
getProfiles( $profileType, User $user=null)
Get a list of supported profiles.
getSort()
Get the sort direction of the search results.
static defaultNearMatcher()
Get near matcher for default SearchEngine.
getSearchIndexFields()
Get fields for search index.
getValidSorts()
Get the valid sort directions.
static userHighlightPrefs()
Find snippet highlight settings for all users.
updateTitle( $id, $title)
Update a search index record's title only.
completionSearchWithVariants( $search)
Perform a completion search with variants.
doSearchText( $term)
Perform a full text search query and return a result set.
normalizeNamespaces( $search)
Makes search simple string if it was namespaced.
const CHARS_ALL
Integer flag for legalSearchChars: includes all chars allowed in a search query.
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
HookContainer $hookContainer
completionSearch( $search)
Perform a completion search.
setLimitOffset( $limit, $offset=0)
Set the maximum number of results to return and how many to skip before returning the first.
const CHARS_NO_SYNTAX
Integer flag for legalSearchChars: includes all chars allowed in a search term.
setShowSuggestion( $showSuggestion)
Set whether the searcher should try to build a suggestion.
simplePrefixSearch( $search)
Call out to simple search backend.
setSort( $sort)
Set the sort direction of the search results.
const FT_QUERY_INDEP_PROFILE_TYPE
Profile type for query independent ranking features.
setHookContainer(HookContainer $hookContainer)
searchText( $term)
Perform a full text search query and return a result set.
legalSearchChars( $type=self::CHARS_ALL)
Get chars legal for search.
extractTitles(SearchSuggestionSet $completionResults)
Extract titles from completion results.
const COMPLETION_PROFILE_TYPE
Profile type for completionSearch.
doSearchTitle( $term)
Perform a title-only search query and return a result set.
An utility class to rescore search results by looking for an exact match in the db and add the page f...
const DEFAULT_CONTEXT_LINES
const DEFAULT_CONTEXT_CHARS
Implementation of near match title search.
filter( $callback)
Filter the suggestions array.
rescore( $key)
Move the suggestion at index $key to the first position.
shrink( $limit)
Remove any extra elements in the suggestions set.
static fromStrings(array $titles, $hasMoreResults=false)
Builds a new set of suggestion based on a string array.
static fromTitles(array $titles, $hasMoreResults=false)
Builds a new set of suggestion based on a title array.
static emptySuggestionSet()
map( $callback)
Call array_map on the suggestions array.
prepend(SearchSuggestion $suggestion)
Add a new suggestion at the top.
getSuggestedTitle()
Title object in the case this suggestion is based on a title.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Performs prefix search, returning Title objects.
Represents a title within MediaWiki.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Interface for configuration instances.
Base interface for content objects.
A set of SearchEngine results.
setAugmentedData( $name, $data)
Sets augmented data for result set.
Marker class for search engines that can handle their own pagination, by reporting in their ISearchRe...