jenkins-bot has submitted this change and it was merged.

Change subject: Move query rewriting into search backend
......................................................................


Move query rewriting into search backend

Special:Search recently gained query rewriting behavior when the
original query returned no results.  We want to expose this query
rewriting behavior to both api and web requests.  Additionally we
want to be able to test different configurations of the query
suggestions.  This patch allows for both by moving the rewriting
from core into the search backend.

This defaults to enabled for Special:Search, and disabled for
ApiQuerySearch. Internal code that talks to the search backend
needs to specifically enable this feature.

Bug: T106888
Change-Id: I0a8f75759f9148f53358707369b8a7128215de86
---
M includes/api/ApiQuerySearch.php
M includes/api/i18n/en.json
M includes/api/i18n/qqq.json
M includes/search/SearchResultSet.php
M includes/specials/SpecialSearch.php
M tests/phpunit/includes/specials/SpecialSearchTest.php
6 files changed, 73 insertions(+), 37 deletions(-)

Approvals:
  Smalyshev: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php
index 65fd727..b866f43 100644
--- a/includes/api/ApiQuerySearch.php
+++ b/includes/api/ApiQuerySearch.php
@@ -82,6 +82,7 @@
                        SearchEngine::create( $params['backend'] ) : 
SearchEngine::create();
                $search->setLimitOffset( $limit + 1, $params['offset'] );
                $search->setNamespaces( $params['namespace'] );
+               $search->setFeatureData( 'rewrite', 
(bool)$params['enablerewrites'] );
 
                $query = $search->transformSearchTerm( $query );
                $query = $search->replacePrefixes( $query );
@@ -133,6 +134,12 @@
                                        'suggestion', 
$matches->getSuggestionQuery() );
                                $apiResult->addValue( array( 'query', 
'searchinfo' ),
                                        'suggestionsnippet', 
$matches->getSuggestionSnippet() );
+                       }
+                       if ( isset( $searchInfo['rewrittenquery'] ) && 
$matches->hasRewrittenQuery() ) {
+                               $apiResult->addValue( array( 'query', 
'searchinfo' ),
+                                       'rewrittenquery', 
$matches->getQueryAfterRewrite() );
+                               $apiResult->addValue( array( 'query', 
'searchinfo' ),
+                                       'rewrittenquerysnippet', 
$matches->getQueryAfterRewriteSnippet() );
                        }
                }
 
@@ -303,10 +310,11 @@
                                )
                        ),
                        'info' => array(
-                               ApiBase::PARAM_DFLT => 'totalhits|suggestion',
+                               ApiBase::PARAM_DFLT => 
'totalhits|suggestion|rewrittenquery',
                                ApiBase::PARAM_TYPE => array(
                                        'totalhits',
                                        'suggestion',
+                                       'rewrittenquery',
                                ),
                                ApiBase::PARAM_ISMULTI => true,
                        ),
@@ -342,6 +350,7 @@
                                ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2
                        ),
                        'interwiki' => false,
+                       'enablerewrites' => false,
                );
 
                $alternatives = SearchEngine::getSearchTypes();
diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json
index d3189c6..212dc51 100644
--- a/includes/api/i18n/en.json
+++ b/includes/api/i18n/en.json
@@ -1036,6 +1036,7 @@
        "apihelp-query+search-param-limit": "How many total pages to return.",
        "apihelp-query+search-param-interwiki": "Include interwiki results in 
the search, if available.",
        "apihelp-query+search-param-backend": "Which search backend to use, if 
not the default.",
+       "apihelp-query+search-param-enablerewrites": "Enable internal query 
rewriting. Some search backends can rewrite the query into one its thinks gives 
better results, such as correcting spelling errors.",
        "apihelp-query+search-example-simple": "Search for <kbd>meaning</kbd>.",
        "apihelp-query+search-example-text": "Search texts for 
<kbd>meaning</kbd>.",
        "apihelp-query+search-example-generator": "Get page info about the 
pages returned for a search for <kbd>meaning</kbd>.",
diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json
index 5ac1e0d..58872a0 100644
--- a/includes/api/i18n/qqq.json
+++ b/includes/api/i18n/qqq.json
@@ -965,6 +965,7 @@
        "apihelp-query+search-param-limit": 
"{{doc-apihelp-param|query+search|limit}}",
        "apihelp-query+search-param-interwiki": 
"{{doc-apihelp-param|query+search|interwiki}}",
        "apihelp-query+search-param-backend": 
"{{doc-apihelp-param|query+search|backend}}",
+       "apihelp-query+search-param-enablerewrites": 
"{{doc-apihelp-param|query+search|enablerewrites}}",
        "apihelp-query+search-example-simple": 
"{{doc-apihelp-example|query+search}}",
        "apihelp-query+search-example-text": 
"{{doc-apihelp-example|query+search}}",
        "apihelp-query+search-example-generator": 
"{{doc-apihelp-example|query+search}}",
diff --git a/includes/search/SearchResultSet.php 
b/includes/search/SearchResultSet.php
index 0a05eef..8d18b0e 100644
--- a/includes/search/SearchResultSet.php
+++ b/includes/search/SearchResultSet.php
@@ -61,6 +61,33 @@
        }
 
        /**
+        * Some search modes will run an alternative query that it thinks gives
+        * a better result than the provided search. Returns true if this has
+        * occured.
+        *
+        * @return bool
+        */
+       function hasRewrittenQuery() {
+               return false;
+       }
+
+       /**
+        * @return string|null The search the query was internally rewritten to,
+        *  or null when the result of the original query was returned.
+        */
+       function getQueryAfterRewrite() {
+               return null;
+       }
+
+       /**
+        * @return string|null Same as self::getQueryAfterRewrite(), but in HTML
+        *  and with changes highlighted. Null when the query was not rewritten.
+        */
+       function getQueryAfterRewriteSnippet() {
+               return null;
+       }
+
+       /**
         * Some search modes return a suggested alternate term if there are
         * no exact hits. Returns true if there is one on this set.
         *
diff --git a/includes/specials/SpecialSearch.php 
b/includes/specials/SpecialSearch.php
index af2dc94..6606c7f 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -216,6 +216,7 @@
                global $wgContLang;
 
                $search = $this->getSearchEngine();
+               $search->setFeatureData( 'rewrite', $this->runSuggestion );
                $search->setLimitOffset( $this->limit, $this->offset );
                $search->setNamespaces( $this->namespaces );
                $search->prefix = $this->mPrefix;
@@ -272,12 +273,8 @@
                // did you mean... suggestions
                $didYouMeanHtml = '';
                if ( $showSuggestion && $textMatches && !$textStatus ) {
-                       if ( $this->shouldRunSuggestedQuery( $textMatches ) ) {
-                               $newMatches = $search->searchText( 
$textMatches->getSuggestionQuery() );
-                               if ( $newMatches instanceof SearchResultSet && 
$newMatches->numRows() > 0 ) {
-                                       $didYouMeanHtml = 
$this->getDidYouMeanRewrittenHtml( $term, $textMatches );
-                                       $textMatches = $newMatches;
-                               }
+                       if ( $textMatches->hasRewrittenQuery() ) {
+                               $didYouMeanHtml = 
$this->getDidYouMeanRewrittenHtml( $term, $textMatches );
                        } elseif ( $textMatches->hasSuggestion() ) {
                                $didYouMeanHtml = $this->getDidYouMeanHtml( 
$textMatches );
                        }
@@ -463,7 +460,7 @@
                // Showing results for '$rewritten'
                // Search instead for '$orig'
 
-               $params = array( 'search' => $textMatches->getSuggestionQuery() 
);
+               $params = array( 'search' => 
$textMatches->getQueryAfterRewrite() );
                if ( $this->fulltext != null ) {
                        $params['fulltext'] = $this->fulltext;
                }
@@ -471,7 +468,7 @@
 
                $rewritten = Linker::linkKnown(
                        $this->getPageTitle(),
-                       $textMatches->getSuggestionSnippet() ?: null,
+                       $textMatches->getQueryAfterRewriteSnippet() ?: null,
                        array(),
                        $stParams
                );
diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php 
b/tests/phpunit/includes/specials/SpecialSearchTest.php
index 7e60fdd..13c2838 100644
--- a/tests/phpunit/includes/specials/SpecialSearchTest.php
+++ b/tests/phpunit/includes/specials/SpecialSearchTest.php
@@ -145,34 +145,25 @@
        public function provideRewriteQueryWithSuggestion() {
                return array(
                        array(
-                               'With results and a suggestion does not run 
suggested query',
+                               'With suggestion and no rewritten query shows 
did you mean',
                                '/Did you mean: <a[^>]+>first suggestion/',
-                               array(
-                                       new SpecialSearchTestMockResultSet( 
'first suggestion', array(
-                                               SearchResult::newFromTitle( 
Title::newMainPage() ),
-                                       ) ),
-                                       new SpecialSearchTestMockResultSet( 
'was never run', array() ),
-                               ),
+                               new SpecialSearchTestMockResultSet( 'first 
suggestion', null, array(
+                                       SearchResult::newFromTitle( 
Title::newMainPage() ),
+                               ) ),
                        ),
 
                        array(
-                               'With no results and a suggestion responds with 
suggested query results',
+                               'With rewritten query informs user of change',
                                '/Showing results for <a[^>]+>first 
suggestion/',
-                               array(
-                                       new SpecialSearchTestMockResultSet( 
'first suggestion', array() ),
-                                       new SpecialSearchTestMockResultSet( 
'second suggestion', array(
-                                               SearchResult::newFromTitle( 
Title::newMainPage() ),
-                                       ) ),
-                               ),
+                               new SpecialSearchTestMockResultSet( 'asdf', 
'first suggestion', array(
+                                       SearchResult::newFromTitle( 
Title::newMainPage() ),
+                               ) ),
                        ),
 
                        array(
                                'When both queries have no results user gets no 
results',
                                '/There were no results matching the query/',
-                               array(
-                                       new SpecialSearchTestMockResultSet( 
'first suggestion', array() ),
-                                       new SpecialSearchTestMockResultSet( 
'second suggestion', array() ),
-                               ),
+                               new SpecialSearchTestMockResultSet( 'first 
suggestion', 'first suggestion', array() ),
                        ),
                );
        }
@@ -180,8 +171,8 @@
        /**
         * @dataProvider provideRewriteQueryWithSuggestion
         */
-       public function testRewriteQueryWithSuggestion( $message, $expectRegex, 
$fromResults ) {
-               $mockSearchEngine = $this->mockSearchEngine( $fromResults );
+       public function testRewriteQueryWithSuggestion( $message, $expectRegex, 
$results ) {
+               $mockSearchEngine = $this->mockSearchEngine( $results );
                $search = $this->getMockBuilder( 'SpecialSearch' )
                        ->setMethods( array( 'getSearchEngine' ) )
                        ->getMock();
@@ -199,17 +190,14 @@
                }
        }
 
-       protected function mockSearchEngine( array $returnValues ) {
+       protected function mockSearchEngine( $results ) {
                $mock = $this->getMockBuilder( 'SearchEngine' )
-                       ->setMethods( array( 'searchText' ) )
+                       ->setMethods( array( 'searchText', 'searchTitle' ) )
                        ->getMock();
 
                $mock->expects( $this->any() )
                        ->method( 'searchText' )
-                       ->will( call_user_func_array(
-                               array( $this, 'onConsecutiveCalls' ),
-                               array_map( array( $this, 'returnValue' ), 
$returnValues )
-                       ) );
+                       ->will( $this->returnValue( $results ) );
 
                return $mock;
        }
@@ -219,9 +207,10 @@
        protected $results;
        protected $suggestion;
 
-       public function __construct( $suggestion = null, array $results = 
array(), $containedSyntax = false) {
-               $this->results = $results;
+       public function __construct( $suggestion = null, $rewrittenQuery = 
null, array $results = array(), $containedSyntax = false) {
                $this->suggestion = $suggestion;
+               $this->rewrittenQuery = $rewrittenQuery;
+               $this->results = $results;
                $this->containedSyntax = $containedSyntax;
        }
 
@@ -244,4 +233,16 @@
        public function getSuggestionSnippet() {
                return $this->suggestion;
        }
+
+       public function hasRewrittenQuery() {
+               return $this->rewrittenQuery !== null;
+       }
+
+       public function getQueryAfterRewrite() {
+               return $this->rewrittenQuery;
+       }
+
+       public function getQueryAfterRewriteSnippet() {
+               return htmlspecialchars( $this->rewrittenQuery );
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/227501
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I0a8f75759f9148f53358707369b8a7128215de86
Gerrit-PatchSet: 8
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: DCausse <[email protected]>
Gerrit-Reviewer: EBernhardson <[email protected]>
Gerrit-Reviewer: MaxSem <[email protected]>
Gerrit-Reviewer: Smalyshev <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to