/**
  * @group functional
  */
 public function testWeight()
 {
     $filter = new Term(array('price' => 4.5));
     $query = new FunctionScore();
     $query->addBoostFactorFunction(5.0, $filter);
     $expected = array('function_score' => array('functions' => array(array('weight' => 5.0, 'filter' => array('term' => array('price' => 4.5))))));
     $this->assertEquals($expected, $query->toArray());
     $response = $this->_getIndexForTest()->search($query);
     $results = $response->getResults();
     // the document with price = 4.5 should be scored highest
     $result0 = $results[0]->getData();
     $this->assertEquals("Mr. Frostie's", $result0['name']);
 }
 /**
  * @group unit
  */
 public function testAddBoostFactorFunction()
 {
     $filter = new Term(array('price' => 4.5));
     $query = new FunctionScore();
     $query->addWeightFunction(5.0, $filter);
     $sameFilter = new Term(array('price' => 4.5));
     $sameQuery = new FunctionScore();
     $err = array();
     set_error_handler(function () use(&$err) {
         $err[] = func_get_args();
     });
     $sameQuery->addBoostFactorFunction(5.0, $sameFilter);
     restore_error_handler();
     $this->assertCount(1, $err);
     $this->assertEquals(E_USER_DEPRECATED, $err[0][0]);
     $this->assertEquals($query->toArray(), $sameQuery->toArray());
 }
 /**
  * If there is any boosting to be done munge the the current query to get it right.
  */
 private function installBoosts()
 {
     // Quick note:  At the moment ".isEmpty()" is _much_ faster then ".empty".  Never
     // use ".empty".  See https://github.com/elasticsearch/elasticsearch/issues/5086
     if ($this->sort !== 'relevance') {
         // Boosts are irrelevant if you aren't sorting by, well, relevance
         return;
     }
     $functionScore = new \Elastica\Query\FunctionScore();
     $useFunctionScore = false;
     // Customize score by boosting based on incoming links count
     if ($this->boostLinks) {
         $useFunctionScore = true;
         if ($this->config->getElement('CirrusSearchWikimediaExtraPlugin', 'field_value_factor_with_default')) {
             $functionScore->addFunction('field_value_factor_with_default', array('field' => 'incoming_links', 'modifier' => 'log2p', 'missing' => 0));
         } else {
             $scoreBoostExpression = "log10(doc['incoming_links'].value + 2)";
             $functionScore->addScriptScoreFunction(new \Elastica\Script($scoreBoostExpression, null, 'expression'));
         }
     }
     // Customize score by decaying a portion by time since last update
     if ($this->preferRecentDecayPortion > 0 && $this->preferRecentHalfLife > 0) {
         // Convert half life for time in days to decay constant for time in milliseconds.
         $decayConstant = log(2) / $this->preferRecentHalfLife / 86400000;
         $parameters = array('decayConstant' => $decayConstant, 'decayPortion' => $this->preferRecentDecayPortion, 'nonDecayPortion' => 1 - $this->preferRecentDecayPortion, 'now' => time() * 1000);
         // e^ct where t is last modified time - now which is negative
         $exponentialDecayExpression = "exp(decayConstant * (doc['timestamp'].value - now))";
         if ($this->preferRecentDecayPortion !== 1.0) {
             $exponentialDecayExpression = "{$exponentialDecayExpression} * decayPortion + nonDecayPortion";
         }
         $functionScore->addScriptScoreFunction(new \Elastica\Script($exponentialDecayExpression, $parameters, 'expression'));
         $useFunctionScore = true;
     }
     // Add boosts for pages that contain certain templates
     if ($this->boostTemplates) {
         foreach ($this->boostTemplates as $name => $boost) {
             $match = new \Elastica\Query\Match();
             $match->setFieldQuery('template', $name);
             $filterQuery = new \Elastica\Filter\Query($match);
             $filterQuery->setCached(true);
             $functionScore->addBoostFactorFunction($boost, $filterQuery);
         }
         $useFunctionScore = true;
     }
     // Add boosts for namespaces
     $namespacesToBoost = $this->namespaces ?: MWNamespace::getValidNamespaces();
     if ($namespacesToBoost) {
         // Group common weights together and build a single filter per weight
         // to save on filters.
         $weightToNs = array();
         foreach ($namespacesToBoost as $ns) {
             $weight = $this->getBoostForNamespace($ns);
             $weightToNs[(string) $weight][] = $ns;
         }
         if (count($weightToNs) > 1) {
             unset($weightToNs['1']);
             // That'd be redundant.
             foreach ($weightToNs as $weight => $namespaces) {
                 $filter = new \Elastica\Filter\Terms('namespace', $namespaces);
                 $functionScore->addBoostFactorFunction($weight, $filter);
                 $useFunctionScore = true;
             }
         }
     }
     // Boost pages in a user's language
     $userLang = $this->config->getUserLanguage();
     $userWeight = $this->config->getElement('CirrusSearchLanguageWeight', 'user');
     if ($userWeight) {
         $functionScore->addBoostFactorFunction($userWeight, new \Elastica\Filter\Term(array('language' => $userLang)));
         $useFunctionScore = true;
     }
     // And a wiki's language, if it's different
     $wikiWeight = $this->config->getElement('CirrusSearchLanguageWeight', 'wiki');
     if ($userLang != $this->config->get('LanguageCode') && $wikiWeight) {
         $functionScore->addBoostFactorFunction($wikiWeight, new \Elastica\Filter\Term(array('language' => $this->config->get('LanguageCode'))));
         $useFunctionScore = true;
     }
     if (!$useFunctionScore) {
         // Nothing to do
         return;
     }
     // The function score is done as a rescore on top of everything else
     $this->rescore[] = array('window_size' => $this->config->get('CirrusSearchFunctionRescoreWindowSize'), 'query' => array('rescore_query' => $functionScore, 'query_weight' => 1.0, 'rescore_query_weight' => 1.0, 'score_mode' => 'multiply'));
 }
 /**
  * @group unit
  */
 public function testLegacyFilterAddBoostFactorFunction()
 {
     $query = new FunctionScore();
     $this->hideDeprecated();
     $filter = new Term(array('price' => 4.5));
     $query->addWeightFunction(5.0, $filter);
     $this->showDeprecated();
     $sameQuery = new FunctionScore();
     $this->hideDeprecated();
     $sameFilter = new Term(array('price' => 4.5));
     $sameQuery->addBoostFactorFunction(5.0, $sameFilter);
     $this->showDeprecated();
     $this->assertEquals($query->toArray(), $sameQuery->toArray());
 }