jenkins-bot has submitted this change and it was merged. Change subject: API for _suggest for Elasticsearch ......................................................................
API for _suggest for Elasticsearch Task: T106129 Aggregate and resolve suggestions This merges together all the suggest results, sorts by score, takes the top $limit results and resolves those into a final result of the page title and suggestion score. I think the scores themselves arn't working right yet, always getting either 1 or 0. But this code should all work right once that starts returning a proper score. Not sure if we will need a more complicated merge or not, tbd. Change-Id: I9c36b9c02a23c30038b1f0d8e8b8a9e310829e7e --- M CirrusSearch.php M autoload.php M i18n/en.json M i18n/qqq.json A includes/Api/Suggest.php A includes/Api/SuggestIndex.php M includes/Searcher.php M maintenance/runSearch.php M maintenance/updateSuggesterIndex.php M tests/browser/features/step_definitions/search_steps.rb A tests/browser/features/suggest_api.feature M tests/browser/features/support/cirrus_search_api_helper.rb M tests/browser/features/support/hooks.rb M tests/jenkins/Jenkins.php 14 files changed, 391 insertions(+), 4 deletions(-) Approvals: EBernhardson: Looks good to me, approved jenkins-bot: Verified Objections: Cindy-the-browser-test-bot: There's a problem with this change, please improve diff --git a/CirrusSearch.php b/CirrusSearch.php index da85959..4caf7ce 100644 --- a/CirrusSearch.php +++ b/CirrusSearch.php @@ -785,6 +785,22 @@ */ $wgCirrusSearchUserTesting = array(); +/** + * Settings for completion suggestion options. + * See CirrusSearch\BuildDocument\SuggestBuilder and CirrusSearch\Searcher + * fields - set of suggestion fields to use + * fuzzy - fuzziness configuration (false for no fuzziness) + * See also: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html + */ +$wgCirrusSearchCompletionSettings = array( + "fields" => array( + "suggest", "suggest-stop" + ), + "fuzzy" => array( + "fuzziness" => 2 + ), +); + $includes = __DIR__ . "/includes/"; $apiDir = $includes . 'Api/'; $buildDocument = $includes . 'BuildDocument/'; @@ -849,6 +865,7 @@ $wgAPIModules['cirrus-config-dump'] = 'CirrusSearch\Api\ConfigDump'; $wgAPIModules['cirrus-mapping-dump'] = 'CirrusSearch\Api\MappingDump'; $wgAPIModules['cirrus-settings-dump'] = 'CirrusSearch\Api\SettingsDump'; +$wgAPIModules['cirrus-suggest'] = 'CirrusSearch\Api\Suggest'; /** * Jenkins configuration required to get all the browser tests passing cleanly. diff --git a/autoload.php b/autoload.php index f40c246..df5da06 100644 --- a/autoload.php +++ b/autoload.php @@ -9,6 +9,8 @@ 'CirrusSearch\\Api\\FreezeWritesToCluster' => __DIR__ . '/includes/Api/FreezeWritesToCluster.php', 'CirrusSearch\\Api\\MappingDump' => __DIR__ . '/includes/Api/MappingDump.php', 'CirrusSearch\\Api\\SettingsDump' => __DIR__ . '/includes/Api/SettingsDump.php', + 'CirrusSearch\\Api\\Suggest' => __DIR__ . '/includes/Api/Suggest.php', + 'CirrusSearch\\Api\\SuggestIndex' => __DIR__ . '/includes/Api/SuggestIndex.php', 'CirrusSearch\\BuildDocument\\Builder' => __DIR__ . '/includes/BuildDocument/Builder.php', 'CirrusSearch\\BuildDocument\\FileDataBuilder' => __DIR__ . '/includes/BuildDocument/FileDataBuilder.php', 'CirrusSearch\\BuildDocument\\IncomingsLinksScoringMethod' => __DIR__ . '/includes/BuildDocument/SuggestScoring.php', diff --git a/i18n/en.json b/i18n/en.json index b8e7f72..28ec5c6 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -19,6 +19,10 @@ "apihelp-cirrus-config-dump-description": "Dump of CirrusSearch configuration.", "apihelp-cirrus-mapping-dump-description": "Dump of CirrusSearch mapping for this wiki.", "apihelp-cirrus-settings-dump-description": "Dump of CirrusSearch settings for this wiki.", + "apihelp-cirrus-suggest-description": "Suggest completions for search term.", + "apihelp-cirrus-suggest-param-text": "Search term to provide completions for.", + "apihelp-cirrus-suggest-param-limit": "How many results to return.", + "apihelp-cirrus-suggest-param-context": "Search context limiting the search, e.g. geo or category.", "cirrussearch-give-feedback": "Give us your feedback", "cirrussearch-morelikethis-settings": " #<!-- leave this line exactly as it is --> <pre>\n# This message lets you configure the settings of the \"more like this\" feature.\n# Changes to this take effect immediately.\n# The syntax is as follows:\n# * Everything from a \"#\" character to the end of the line is a comment.\n# * Every non-blank line is the setting name followed by a \":\" character followed by the setting value\n# The settings are:\n# * min_doc_freq (integer): Minimum number of documents (per shard) that need a term for it to be considered.\n# * max_doc_freq (integer): Maximum number of documents (per shard) that have a term for it to be considered.\n# High frequency terms are generally \"stop words\".\n# * max_query_terms (integer): Maximum number of terms to be considered. This value is limited to $wgCirrusSearchMoreLikeThisMaxQueryTermsLimit (100).\n# * min_term_freq (integer): Minimum number of times the term appears in the input to doc to be considered. For small fields (title) this value should be 1.\n# * percent_terms_to_match (float 0 to 1): The percentage of terms to match on. Defaults to 0.3 (30 percent).\n# * min_word_len (integer): Minimal length of a term to be considered. Defaults to 0.\n# * max_word_len (integer): The maximum word length above which words will be ignored. Defaults to unbounded (0).\n# * fields (comma separated list of values): These are the fields to use. Allowed fields are title, text, auxiliary_text, opening_text, headings and all.\n# * use_fields (true|false) : Tell the \"more like this\" query to use only the field data. Defaults to false: the system will extract the content of the text field to build the query.\n# Examples of good lines:\n# min_doc_freq:2\n# max_doc_freq:20000\n# max_query_terms:25\n# min_term_freq:2\n# percent_terms_to_match:0.3\n# min_word_len:2\n# max_word_len:40\n# fields:text,opening_text\n# use_fields:true\n# </pre> <!-- leave this line exactly as it is -->", "cirrussearch-didyoumean-settings": " #<!-- leave this line exactly as it is --> <pre>\n# This message lets you configure the settings of the \"Did you mean\" suggestions.\n# See also https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html\n# Changes to this take effect immediately.\n# The syntax is as follows:\n# * Everything from a \"#\" character to the end of the line is a comment.\n# * Every non-blank line is the setting name followed by a \":\" character followed by the setting value\n# The settings are :\n# * max_errors (integer): the maximum number of terms that will be considered misspelled in order to be corrected. 1 or 2.\n# * confidence (float): The confidence level defines a factor applied to the input phrases score which is used as a threshold for other suggestion candidates. Only candidates that score higher than the threshold will be included in the result. For instance a confidence level of 1.0 will only return suggestions that score higher than the input phrase. If set to 0.0 the best candidate are returned.\n# * min_doc_freq (float 0 to 1): The minimal threshold in number of documents a suggestion should appear in.\n# High frequency terms are generally \"stop words\".\n# * max_term_freq (float 0 to 1): The maximum threshold in number of documents in which a term can exist in order to be included.\n# * prefix_length (integer): The minimal number of prefix characters that must match a term in order to be a suggestion.\n# * suggest_mode (missing, popular, always): The suggest mode controls the way suggestions are included.\n# Examples of good lines:\n# max_errors:2\n# confidence:2.0\n# max_term_freq:0.5\n# min_doc_freq:0.01\n# prefix_length:2\n# suggest_mode:always\n#\n# </pre> <!-- leave this line exactly as it is -->", diff --git a/i18n/qqq.json b/i18n/qqq.json index 83707f9..f65074c 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -27,6 +27,10 @@ "apihelp-cirrus-config-dump-description": "{{doc-apihelp-description|cirrus-config-dump}}", "apihelp-cirrus-mapping-dump-description": "{{doc-apihelp-description|cirrus-mapping-dump}}", "apihelp-cirrus-settings-dump-description": "{{doc-apihelp-description|cirrus-settings-dump}}", + "apihelp-cirrus-suggest-description": "{{doc-apihelp-description|cirrus-suggest}}", + "apihelp-cirrus-suggest-param-text": "{{doc-apihelp-param|cirrus-suggest|text}}", + "apihelp-cirrus-suggest-param-context": "{{doc-apihelp-param|cirrus-suggest|context}}", + "apihelp-cirrus-suggest-param-limit": "{{doc-apihelp-param|cirrus-suggest|limit}}", "cirrussearch-give-feedback": "Used as text for an feedback link shown at the end of Special:Search result ([[mw:Extension:CirrusSearch|$wgCirrusSearchFeedbackLink]])", "cirrussearch-morelikethis-settings": "Settings for the More Like This query.\n\n\"More Like This\" is the English name of the feature. The feature is described at [[:mw:Help:CirrusSearch#Special prefixes]]. The prefix \"morelike\" cannot be translated anywhere, but the full name of the feature \"More Like This\" can be translated.\n\nDon't translate technical names like min_doc_freq, max_query_terms, true|false, field names title, text, auxiliary_text, opening_text, headings, all etc.\n\nFor a definition of \"stopwords\" see [[:w:en:Stop words|Stop words in Wikipedia]].", "cirrussearch-didyoumean-settings": "Settings for the \"Did You Mean?\" suggestions.\n\n\"Did You Mean?\" is the English name of the feature and can be translated. This feature is described at [[:mw:Help:CirrusSearch#Did_you_mean]].\n\nDon't translate technical names like max_errors, confidence, max_term_freq, min_doc_freq and suggest_mode.\n\n\"Stop words\" are words that are explicitly excluded from searching and statistics, usually because they are too frequent to be useful and meaningful. See [[:w:en:Stop words|stop words]] in the English Wikipedia.", diff --git a/includes/Api/Suggest.php b/includes/Api/Suggest.php new file mode 100644 index 0000000..8d5d056 --- /dev/null +++ b/includes/Api/Suggest.php @@ -0,0 +1,87 @@ +<?php +namespace CirrusSearch\Api; + +use ApiBase; +use CirrusSearch\Searcher; +use RequestContext; + +/** + * Use ElasticSearch suggestion API + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ +class Suggest extends ApiBase { + + public function execute() { + $context = RequestContext::getMain(); + $user = $context->getUser(); + $searcher = new Searcher( 0, $this->getParameter( 'limit' ), null, $user ); + + $queryText = $this->getParameter( 'text' ); + if ( !$queryText ) { + return; + } + + $contextString = $this->getParameter( 'context' ); + if( $contextString ) { + $context = @json_decode( $contextString, true ); + /* + * Validate the context, must be in the form of: + * { + * name: { foo: bar, baz: qux } + * name2: { foo: bar, baz: qux } + * } + * + */ + if( !is_array( $context )) { + $context = null; + } else { + foreach( $context as $name => $ctx ) { + if ( !is_array( $ctx ) ) { + $this->dieUsage( "Bad context element $name", 'cirrus-badcontext' ); + } + } + } + } else { + $context = null; + } + + // TODO: add passing context here, + // see https://www.elastic.co/guide/en/elasticsearch/reference/current/suggester-context.html + $result = $searcher->suggest( $queryText, $context ); + if($result->isOK()) { + $this->getResult()->addValue( null, 'suggest', $result->getValue() ); + } else { + $this->getResult()->addValue( null, "error", $result->getErrorsArray()); + } + } + + public function getAllowedParams() { + return array( + 'text' => array( + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_REQUIRED => true, + ), + 'context' => array( + ApiBase::PARAM_TYPE => 'string', + ), + 'limit' => array( + ApiBase::PARAM_TYPE => 'integer', + ApiBase::PARAM_DFLT => 5, + ), + ); + } +} diff --git a/includes/Api/SuggestIndex.php b/includes/Api/SuggestIndex.php new file mode 100644 index 0000000..7e84891 --- /dev/null +++ b/includes/Api/SuggestIndex.php @@ -0,0 +1,34 @@ +<?php +namespace CirrusSearch\Api; + +use ApiBase; + +/** + * Update ElasticSearch suggestion index + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ +class SuggestIndex extends ApiBase { + + public function execute() { + // FIXME: This is horrible, no good, very bad hack. Only for testing, + // and probably should be eventually replaced with something more sane. + $updaterScript = "extensions/CirrusSearch/maintenance/updateSuggesterIndex.php"; + $this->getResult()->addValue( null, 'result', + wfShellExecWithStderr( "unset REQUEST_METHOD; /usr/local/bin/mwscript $updaterScript --wiki " . wfWikiID() ) + ); + } +} \ No newline at end of file diff --git a/includes/Searcher.php b/includes/Searcher.php index 3a79d1d..341c804 100644 --- a/includes/Searcher.php +++ b/includes/Searcher.php @@ -1,6 +1,7 @@ <?php namespace CirrusSearch; + use Elastica; use Category; use CirrusSearch; @@ -18,6 +19,7 @@ use Title; use UsageException; use User; +use Elastica\Request; /** * Performs searches using Elasticsearch. Note that each instance of this class @@ -773,6 +775,132 @@ } /** + * Produce a set of completion suggestions for text using _suggest + * See https://www.elastic.co/guide/en/elasticsearch/reference/1.6/search-suggesters-completion.html + * @param string $text Search term + * @param array $context Context, see https://www.elastic.co/guide/en/elasticsearch/reference/current/suggester-context.html + * @return Status + */ + public function suggest( $text, $context = null ) { + global $wgCirrusSearchCompletionSettings, $wgCirrusSearchSearchShardTimeout; + + $this->term = $text; + + $suggest = array( 'text' => $text ); + foreach ( $wgCirrusSearchCompletionSettings[ 'fields' ] as $field ) { + $suggest[$field] = array( + 'completion' => array( + 'field' => $field, + ) + ); + if ( $context ) { + $suggest[$field]['completion']['context'] = $context; + } + + if( is_array( $wgCirrusSearchCompletionSettings[ 'fuzzy' ] ) ) { + $suggest[$field."-fuzzy"] = array( + 'completion' => array( + 'field' => $field, + 'fuzzy' => $wgCirrusSearchCompletionSettings[ 'fuzzy' ], + ) + ); + if ( $context ) { + $suggest[$field."-fuzzy"]['completion']['context'] = $context; + } + } + } + + $queryOptions = array(); + $queryOptions[ 'timeout' ] = $wgCirrusSearchSearchShardTimeout[ 'default' ]; + Connection::setTimeout( $wgCirrusSearchSearchShardTimeout[ 'default' ] ); + + $index = Connection::getIndex( $this->indexBaseName, Connection::TITLE_SUGGEST_TYPE ); + $description = "completion suggest query for {query}"; + $logContext = array( + 'query' => $text, + ); + $searcher = $this; + $result = Util::doPoolCounterWork( + 'CirrusSearch-Search', + $this->user, + function() use( $searcher, $index, $description, $suggest, $logContext, $queryOptions ) { + $searcher->start( $description, $logContext ); + try { + return $index->request( "_suggest", Request::POST, $suggest, $queryOptions ); + } catch ( \Elastica\Exception\ExceptionInterface $e ) { + return $searcher->failure( $e ); + } + } + ); + if( $result->isOk() ) { + $result = $this->postProcessSuggest( $result, $this->limit ); + return $this->success( $result ); + } + return $result; + } + + /** + * merge top level multi-queries and resolve returned pageIds into Title objects. + * + * @param \Elastica\Response $response Response from elasticsearch _suggest api + * @param int $limit Maximum suggestions to return, -1 for unlimited + * @return Title[] List of suggested titles + */ + protected function postProcessSuggest( \Elastica\Response $response, $limit = -1 ) { + $data = $response->getData(); + unset( $data['_shards'] ); + + $suggestions = array(); + foreach ( $data as $name => $results ) { + foreach ( $results as $suggested ) { + foreach ( $suggested['options'] as $suggest ) { + $pageId = $suggest['text']; + if ( !isset( $suggestions[$pageId] ) || + $suggest['score'] > $suggestions[$pageId]['score'] + ) { + $suggestions[$pageId] = $suggest; + } + } + } + } + + // simply sort by existing scores + usort( $suggestions, function ( $a, $b ) { + return $b['score'] - $a['score']; + } ); + + if ( $limit > 0 ) { + $suggestions = array_slice( $suggestions, 0, $limit ); + } + + // suggest currently returns page ids, we need to resolve those now + $pageIds = array(); + foreach ( $suggestions as $suggestion ) { + $pageIds[] = $suggestion['text']; + } + + // doesn't guarantee to maintain order + $unsortedTitles = Title::newFromIDs( $pageIds ); + $byId = array(); + foreach ( $unsortedTitles as $title ) { + $byId[$title->getArticleID()] = $title; + } + + $retval = array(); + foreach ( $suggestions as $suggestion ) { + $pageId = $suggestion['text']; + if ( isset( $byId[$pageId] ) ) { + $retval[] = array( + 'title' => (string)$byId[$pageId], + 'score' => $suggestion['score'], + ); + } + } + + return $retval; + } + + /** * Builds a match query against $field for $title. $title is munged to make title matching better more * intuitive for users. * @param string $field field containing the title @@ -1199,6 +1327,7 @@ 'path' => $search->getPath(), 'params' => $search->getOptions(), 'query' => $query->toArray(), + 'options' => $queryOptions, ) ); } diff --git a/maintenance/runSearch.php b/maintenance/runSearch.php index ccf8069..4e5c357 100644 --- a/maintenance/runSearch.php +++ b/maintenance/runSearch.php @@ -5,6 +5,7 @@ use CirrusSearch; use CirrusSearch\Searcher; use Status; +use CirrusSearch\Search\ResultSet; /** * Run search queries provided on stdin @@ -38,7 +39,7 @@ parent::__construct(); $this->addDescription( "Run one or more searches against the cluster. " . "search queries are read from stdin." ); - $this->addOption( 'type', 'What type of search to run, prefix or full_text. ' . + $this->addOption( 'type', 'What type of search to run, prefix, suggest or full_text. ' . 'defaults to full_text.', false, true ); $this->addOption( 'options', 'A JSON object mapping from global variable to ' . 'its test value' ); @@ -94,9 +95,14 @@ $data = array( 'query' => $query ); $status = $this->searchFor( $query ); if ( $status->isOK() ) { - $data['rows'] = $status->getValue()->numRows(); + $value = $status->getValue(); + if ( $value instanceof ResultSet ) { + $data['rows'] = $value->numRows(); + } elseif ( is_array ($value ) ) { + $data['rows'] = count( $value ); + } } else { - $data['error'] = $resultSet->getMessage()->text(); + $data['error'] = $status->getMessage()->text(); } return json_encode( $data ); } @@ -124,6 +130,15 @@ $searcher = new Searcher( 0, 10 ); return $searcher->prefixSearch( $query ); + case 'suggest': + $searcher = new Searcher( 0, 10 ); + $result = $searcher->suggest( $query ); + if ( $result instanceof Status ) { + return $result; + } else { + return Status::newGood( $result ); + } + default: $this->error( "\nERROR: Unknown search type $searchType\n" ); exit( 1 ); diff --git a/maintenance/updateSuggesterIndex.php b/maintenance/updateSuggesterIndex.php index 838f0be..79225b2 100644 --- a/maintenance/updateSuggesterIndex.php +++ b/maintenance/updateSuggesterIndex.php @@ -153,6 +153,7 @@ "Message: $message\n" . "Trace:\n" . $trace, 1 ); } + $this->getIndex()->refresh(); } private function deleteOldIndex() { @@ -397,5 +398,5 @@ } } -$maintClass = "CirrusSearch\Maintenance\UpdateSuggesterIndex"; +$maintClass = 'CirrusSearch\Maintenance\UpdateSuggesterIndex'; require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/tests/browser/features/step_definitions/search_steps.rb b/tests/browser/features/step_definitions/search_steps.rb index 484e605..08feb47 100644 --- a/tests/browser/features/step_definitions/search_steps.rb +++ b/tests/browser/features/step_definitions/search_steps.rb @@ -56,6 +56,36 @@ Then(/^the api should offer to search for pages containing (.*)$/) do |term| @api_result[0].should == term end +When(/^I ask suggestion API for (.*)$/) do |search| + begin + @api_result = suggestions_for_api(search) + rescue MediawikiApi::ApiError => e + @api_error = e + end +end +When(/^I ask suggestion API at most (\d+) items? for (.*)$/) do |limit, search| + begin + @api_result = suggestions_for_api(search, limit) + rescue MediawikiApi::ApiError => e + @api_error = e + end +end +Then(/^the API should produce list containing (.*)/) do |term| + found = false + @api_result["suggest"].each do |el| + found = true if el["title"] == term + end + found.should == true +end +Then(/^the API should produce list starting with (.*)/) do |term| + @api_result["suggest"][0]["title"].should == term +end +Then(/^the API should produce list of length (\d+)/) do |length| + @api_result["suggest"].length.should == length.to_i +end +Then(/^the API should produce empty list/) do + @api_result["suggest"].should == [] +end When(/^I get api near matches for (.*)$/) do |search| begin @api_result = search_for( @@ -467,6 +497,12 @@ thaw: 1 ) end +When(/^I reindex suggestions$/) do + api.action( + :'cirrus-suggest-index', + token_type: false + ) +end def within(seconds) end_time = Time.new + Integer(seconds) diff --git a/tests/browser/features/suggest_api.feature b/tests/browser/features/suggest_api.feature new file mode 100644 index 0000000..c4b203f --- /dev/null +++ b/tests/browser/features/suggest_api.feature @@ -0,0 +1,34 @@ +# +# This file is subject to the license terms in the COPYING file found in the +# CirrusSearch top-level directory and at +# https://git.wikimedia.org/blob/mediawiki%2Fextensions%2FCirrusSearch/HEAD/COPYING. No part of +# CirrusSearch, including this file, may be copied, modified, propagated, or +# distributed except according to the terms contained in the COPYING file. +# +# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the +# CirrusSearch top-level directory and at +# https://git.wikimedia.org/blob/mediawiki%2Fextensions%2FCirrusSearch/HEAD/CREDITS +# +@api @suggest +Feature: Suggestion API test + + Scenario: Search suggestions + When I ask suggestion API for main + Then the API should produce list containing Main Page + + Scenario: Created pages suggestions + When I ask suggestion API for x-m + Then the API should produce list containing X-Men + + Scenario: Nothing to suggest + When I ask suggestion API for jabberwocky + Then the API should produce empty list + + Scenario: Ordering + When I ask suggestion API for x-m + Then the API should produce list starting with X-Men + + Scenario: Ordering & limit + When I ask suggestion API at most 1 item for x-m + Then the API should produce list starting with X-Men + And the API should produce list of length 1 \ No newline at end of file diff --git a/tests/browser/features/support/cirrus_search_api_helper.rb b/tests/browser/features/support/cirrus_search_api_helper.rb index 630988a..4fa9a80 100644 --- a/tests/browser/features/support/cirrus_search_api_helper.rb +++ b/tests/browser/features/support/cirrus_search_api_helper.rb @@ -56,6 +56,16 @@ ) end + # Get suggestions for a particular string using the new suggestions api + def suggestions_for_api(search, limit = nil) + req = {} + req["limit"] = limit if limit + api.action(:'cirrus-suggest', req.merge( + text: search, + token_type: false + )) + end + def sha1_for_image(title, current_api = nil) current_api ||= api existing = current_api.prop( diff --git a/tests/browser/features/support/hooks.rb b/tests/browser/features/support/hooks.rb index 90317a3..beed156 100644 --- a/tests/browser/features/support/hooks.rb +++ b/tests/browser/features/support/hooks.rb @@ -616,6 +616,19 @@ end end +suggest = false +Before("@suggest") do + unless suggest + steps %( + Given a page named X-Men exists with contents The X-Men are a fictional team of superheroes + And a page named Xavier, Charles exists with contents Professor Charles Francis Xavier (also known as Professor X) is the founder of [[X-Men]] + And a page named X-Force exists with contents X-Force is a fictional team of of [[X-Men]] + And I reindex suggestions + ) + suggest = true + end +end + # Prevents api tests from generating fail screenshots. Must come after all the above hooks # because some of them use the browser to set the preconditions necessary for api tests. Before("@api") do diff --git a/tests/jenkins/Jenkins.php b/tests/jenkins/Jenkins.php index 43b7486..1bc555c 100644 --- a/tests/jenkins/Jenkins.php +++ b/tests/jenkins/Jenkins.php @@ -77,6 +77,7 @@ // Test only API action to expose freezing/thawing writes to the elasticsearch cluster $wgAPIModules['cirrus-freeze-writes'] = 'CirrusSearch\Api\FreezeWritesToCluster'; +$wgAPIModules['cirrus-suggest-index'] = 'CirrusSearch\Api\SuggestIndex'; // Bring the ElasticWrite backoff down to between 2^-1 and 2^3 seconds during browser tests $wgCirrusSearchWriteBackoffExponent = -1; -- To view, visit https://gerrit.wikimedia.org/r/230927 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I9c36b9c02a23c30038b1f0d8e8b8a9e310829e7e Gerrit-PatchSet: 30 Gerrit-Project: mediawiki/extensions/CirrusSearch Gerrit-Branch: master Gerrit-Owner: Smalyshev <[email protected]> Gerrit-Reviewer: Chad <[email protected]> Gerrit-Reviewer: Cindy-the-browser-test-bot <[email protected]> Gerrit-Reviewer: DCausse <[email protected]> Gerrit-Reviewer: EBernhardson <[email protected]> Gerrit-Reviewer: Manybubbles <[email protected]> Gerrit-Reviewer: MaxSem <[email protected]> Gerrit-Reviewer: Smalyshev <[email protected]> Gerrit-Reviewer: Tjones <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
