Example #1
0
 /**
  * Get a random quip
  *
  * @return ResultSet
  */
 public function getRandom()
 {
     $fs = new FunctionScore();
     $fs->setRandomScore();
     $query = new Query($fs);
     $query->setFrom(0)->setSize(1)->setFields($this->defaultFields());
     return $this->doSearch($query);
 }
Example #2
0
 /**
  * @group functional
  * @expectedException \Elastica\Exception\InvalidException
  */
 public function testArrayConfigSearch()
 {
     $client = $this->_getClient();
     $search = new Search($client);
     $index = $client->getIndex('zero');
     $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
     $docs = array();
     for ($i = 0; $i < 11; ++$i) {
         $docs[] = new Document($i, array('id' => 1, 'email' => '*****@*****.**', 'username' => 'test'));
     }
     $type = $index->getType('zeroType');
     $type->addDocuments($docs);
     $index->refresh();
     $search->addIndex($index)->addType($type);
     //Backward compatibility, integer => limit
     // default limit results  (default limit is 10)
     $resultSet = $search->search('test');
     $this->assertEquals(10, $resultSet->count());
     // limit = 1
     $resultSet = $search->search('test', 1);
     $this->assertEquals(1, $resultSet->count());
     //Array with limit
     $resultSet = $search->search('test', array('limit' => 2));
     $this->assertEquals(2, $resultSet->count());
     //Array with size
     $resultSet = $search->search('test', array('size' => 2));
     $this->assertEquals(2, $resultSet->count());
     //Array with from
     $resultSet = $search->search('test', array('from' => 10));
     $this->assertEquals(10, $resultSet->current()->getId());
     //Array with routing
     $resultSet = $search->search('test', array('routing' => 'r1,r2'));
     $this->assertEquals(10, $resultSet->count());
     //Array with limit and routing
     $resultSet = $search->search('test', array('limit' => 5, 'routing' => 'r1,r2'));
     $this->assertEquals(5, $resultSet->count());
     //Search types
     $resultSet = $search->search('test', array('limit' => 5, 'search_type' => 'count'));
     $this->assertTrue($resultSet->count() === 0 && $resultSet->getTotalHits() === 11);
     //Timeout - this one is a bit more tricky to test
     $mockResponse = new \Elastica\Response(json_encode(array('timed_out' => true)));
     $client = $this->getMockBuilder('Elastica\\Client')->disableOriginalConstructor()->getMock();
     $client->method('request')->will($this->returnValue($mockResponse));
     $search = new Search($client);
     $script = new Script('Thread.sleep(100); return _score;');
     $query = new FunctionScore();
     $query->addScriptScoreFunction($script);
     $resultSet = $search->search($query, array('timeout' => 50));
     $this->assertTrue($resultSet->hasTimedOut());
     // Throws InvalidException
     $resultSet = $search->search('test', array('invalid_option' => 'invalid_option_value'));
 }
 /**
  * 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 functional
  */
 public function testFieldValueFactor()
 {
     $this->_checkVersion('1.6');
     $expected = array('function_score' => array('functions' => array(array('field_value_factor' => array('field' => 'popularity', 'factor' => 1.2, 'modifier' => 'sqrt', 'missing' => 0.1)))));
     $query = new FunctionScore();
     $query->addFieldValueFactorFunction('popularity', 1.2, FunctionScore::FIELD_VALUE_FACTOR_MODIFIER_SQRT, 0.1);
     $this->assertEquals($expected, $query->toArray());
     $response = $this->_getIndexForTest()->search($query);
     $results = $response->getResults();
     $this->assertCount(2, $results);
     $this->assertEquals(2, $results[0]->getId());
 }
 /**
  * @group functional
  */
 public function testSetMinScore()
 {
     $expected = array('function_score' => array('min_score' => 0.8, 'functions' => array(array('gauss' => array('price' => array('origin' => 0, 'scale' => 10))))));
     $query = new FunctionScore();
     $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', 0, 10);
     $returnedValue = $query->setMinScore(0.8);
     $this->assertEquals($expected, $query->toArray());
     $this->assertInstanceOf('Elastica\\Query\\FunctionScore', $returnedValue);
     $response = $this->_getIndexForTest()->search($query);
     $results = $response->getResults();
     $this->assertCount(1, $results);
     $this->assertEquals(1, $results[0]->getId());
 }
 public function testScriptScore()
 {
     $scriptString = "_score * doc['price'].value";
     $script = new Script($scriptString);
     $query = new FunctionScore();
     $query->addScriptScoreFunction($script);
     $expected = array('function_score' => array('functions' => array(array('script_score' => array('script' => $scriptString)))));
     $this->assertEquals($expected, $query->toArray());
     $response = $this->type->search($query);
     $results = $response->getResults();
     // the document the highest price should be scored highest
     $result0 = $results[0]->getData();
     $this->assertEquals("Miller's Field", $result0['name']);
 }
 public function append(FunctionScore $functionScore)
 {
     $functionScore->addScriptScoreFunction(new \Elastica\Script($this->script, null, 'expression'), null, $this->weight);
 }