diff --git a/.travis.yml b/.travis.yml index 56fc02d771..892163e2bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,10 @@ language: php php: - - 5.3 - 5.4 - 5.5 - 5.6 -matrix: - allow_failures: - - php: 5.6 - env: matrix: - ES_COMPOSER_NODEV=no diff --git a/ansible/es-playbook.yml b/ansible/es-playbook.yml index 9761c41478..c7b06ef491 100644 --- a/ansible/es-playbook.yml +++ b/ansible/es-playbook.yml @@ -4,11 +4,11 @@ hosts: localhost connection: local vars: - - ES_VER: "1.3.4" - - ES_SHORT_VER: "1.3" - - ES_MAPPER_ATTACHMENTS_VER: "2.3.2" - - ES_TRANSPORT_THRIFT_VER: "2.3.0" - - ES_GEOCLUSTER_FACET_VER: "0.0.11" + - ES_VER: "1.4.2" + - ES_SHORT_VER: "1.4" + - ES_MAPPER_ATTACHMENTS_VER: "2.4.1" + - ES_TRANSPORT_THRIFT_VER: "2.4.1" + - ES_GEOCLUSTER_FACET_VER: "0.0.12" - ES_PROJECT_ROOT: "{{ lookup('env', 'ES_PROJECT_ROOT') }}" - ES_COMPOSER_NODEV: "{{ lookup('env', 'ES_COMPOSER_NODEV') }}" roles: diff --git a/changes.txt b/changes.txt index 9a08491099..839d86f5f4 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,9 @@ CHANGES +2015-01-19 +- Update to elasticsearch 1.4.2 +- Remove support for PHP 5.3 + 2015-01-14 - added @return annotation to top_hits aggregation DSL method @@ -31,6 +35,8 @@ CHANGES 2014-11-16 - Added Elastica\QueryBuilder #724 +- Update to elasticsearch 1.4.0 +- Disable official support for PHP 5.3 2014-11-13 - fixed reserved words in queries which composed of upper case letters (Util::replaceBooleanWords) #722 diff --git a/composer.json b/composer.json index dc77339721..443edeee0f 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "psr/log": "~1.0" }, "require-dev": { - "psr/log": "~1.0", "munkie/elasticsearch-thrift-php": "1.4.*", "phpunit/phpunit": "4.1.*", "satooshi/php-coveralls": "dev-master" diff --git a/lib/Elastica/Document.php b/lib/Elastica/Document.php index b0d47269b8..1dfa714a8d 100644 --- a/lib/Elastica/Document.php +++ b/lib/Elastica/Document.php @@ -176,7 +176,7 @@ public function addFile($key, $filepath, $mimeType = '') $value = base64_encode(file_get_contents($filepath)); if (!empty($mimeType)) { - $value = array('_content_type' => $mimeType, '_name' => $filepath, 'content' => $value); + $value = array('_content_type' => $mimeType, '_name' => $filepath, '_content' => $value); } $this->set($key, $value); diff --git a/lib/Elastica/Index/Settings.php b/lib/Elastica/Index/Settings.php index 3438bc4d7e..24aa513d6b 100644 --- a/lib/Elastica/Index/Settings.php +++ b/lib/Elastica/Index/Settings.php @@ -2,6 +2,8 @@ namespace Elastica\Index; +use Elastica\Exception\NotFoundException; +use Elastica\Exception\ResponseException; use Elastica\Index as BaseIndex; use Elastica\Request; @@ -68,31 +70,34 @@ public function get($setting = '') $requestData = $this->request()->getData(); $data = reset($requestData); + if (empty($data['settings']) || empty($data['settings']['index'])) { + // should not append, the request should throw a ResponseException + throw new NotFoundException('Index ' . $this->getIndex()->getName() . ' not found'); + } $settings = $data['settings']['index']; - if (!empty($setting)) { - if (isset($settings[$setting])) { - return $settings[$setting]; - } else { - if (strpos($setting, '.') !== false) { - // translate old dot-notation settings to nested arrays - $keys = explode('.', $setting); - foreach ($keys as $key) { - if (isset($settings[$key])) { - $settings = $settings[$key]; - } else { - return; - } - } + if (!$setting) { + // return all array + return $settings; + } - return $settings; + if (isset($settings[$setting])) { + return $settings[$setting]; + } else { + if (strpos($setting, '.') !== false) { + // translate old dot-notation settings to nested arrays + $keys = explode('.', $setting); + foreach ($keys as $key) { + if (isset($settings[$key])) { + $settings = $settings[$key]; + } else { + return null; + } } - - return; + return $settings; } + return null; } - - return $settings; } /** @@ -118,7 +123,18 @@ public function setNumberOfReplicas($replicas) */ public function setReadOnly($readOnly = true) { - return $this->set(array('blocks.read_only' => $readOnly)); + return $this->set(array('blocks.write' => $readOnly)); + } + + /** + * getReadOnly + * + * @access public + * @return bool + */ + public function getReadOnly() + { + return $this->get('blocks.write') === 'true'; // ES returns a string for this setting } /** @@ -156,7 +172,7 @@ public function setBlocksWrite($state = true) { $state = $state ? 1 : 0; - return $this->set(array('blocks.write' => (int) $state)); + return $this->set(array('blocks.write' => $state)); } /** @@ -164,7 +180,18 @@ public function setBlocksWrite($state = true) */ public function getBlocksMetadata() { - return (bool) $this->get('blocks.metadata'); + // TODO will have to be replace by block.metadata.write once https://github.com/elasticsearch/elasticsearch/pull/9203 has been fixed + // the try/catch will have to be remove too + try { + return (bool) $this->get('blocks.metadata'); + } catch (ResponseException $e) { + if (strpos($e->getMessage(), 'ClusterBlockException') !== false) { + // hacky way to test if the metadata is blocked since bug 9203 is not fixed + return true; + } else { + throw $e; + } + } } /** @@ -173,9 +200,10 @@ public function getBlocksMetadata() */ public function setBlocksMetadata($state = true) { + // TODO will have to be replace by block.metadata.write once https://github.com/elasticsearch/elasticsearch/pull/9203 has been fixed $state = $state ? 1 : 0; - return $this->set(array('blocks.metadata' => (int) $state)); + return $this->set(array('blocks.metadata' => $state)); } /** @@ -314,7 +342,9 @@ public function request(array $data = array(), $method = Request::GET) { $path = '_settings'; - $data = array('index' => $data); + if (!empty($data)) { + $data = array('index' => $data); + } return $this->getIndex()->request($path, $method, $data); } diff --git a/lib/Elastica/Index/Status.php b/lib/Elastica/Index/Status.php index b5e7e03400..4c0450e499 100644 --- a/lib/Elastica/Index/Status.php +++ b/lib/Elastica/Index/Status.php @@ -88,7 +88,11 @@ public function getAliases() { $responseData = $this->getIndex()->request('_aliases', \Elastica\Request::GET)->getData(); - return array_keys($responseData[$this->getIndex()->getName()]['aliases']); + $data = $responseData[$this->getIndex()->getName()]; + if (!empty($data['aliases'])) { + return array_keys($data['aliases']); + } + return []; } /** diff --git a/lib/Elastica/Query/FunctionScore.php b/lib/Elastica/Query/FunctionScore.php index 643f7f560a..a2a7809ce6 100644 --- a/lib/Elastica/Query/FunctionScore.php +++ b/lib/Elastica/Query/FunctionScore.php @@ -56,9 +56,10 @@ public function setFilter(AbstractFilter $filter) * @param string $functionType valid values are DECAY_* constants and script_score * @param array|float $functionParams the body of the function. See documentation for proper syntax. * @param AbstractFilter $filter optional filter to apply to the function + * @param float $weight function weight * @return \Elastica\Query\FunctionScore */ - public function addFunction($functionType, $functionParams, AbstractFilter $filter = null) + public function addFunction($functionType, $functionParams, AbstractFilter $filter = null, $weight = null) { $function = array( $functionType => $functionParams, @@ -66,8 +67,11 @@ public function addFunction($functionType, $functionParams, AbstractFilter $filt if (!is_null($filter)) { $function['filter'] = $filter->toArray(); } - $this->_functions[] = $function; + if ($weight !== null) { + $function['weight'] = $weight; + } + $this->_functions[] = $function; return $this; } @@ -75,11 +79,12 @@ public function addFunction($functionType, $functionParams, AbstractFilter $filt * Add a script_score function to the query * @param Script $script a Script object * @param AbstractFilter $filter an optional filter to apply to the function + * @param float $weight the weight of the function * @return \Elastica\Query\FunctionScore */ - public function addScriptScoreFunction(Script $script, AbstractFilter $filter = null) + public function addScriptScoreFunction(Script $script, AbstractFilter $filter = null, $weight = null) { - return $this->addFunction('script_score', $script->toArray(), $filter); + return $this->addFunction('script_score', $script->toArray(), $filter, $weight); } /** @@ -91,12 +96,20 @@ public function addScriptScoreFunction(Script $script, AbstractFilter $filter = * @param string $offset If defined, this function will only be computed for documents with a distance from the origin greater than this value * @param float $decay optionally defines how documents are scored at the distance given by the $scale parameter * @param float $scaleWeight optional factor by which to multiply the score at the value provided by the $scale parameter + * @param float $weight optional factor by which to multiply the score at the value provided by the $scale parameter * @param AbstractFilter $filter a filter associated with this function * @return \Elastica\Query\FunctionScore */ - public function addDecayFunction($function, $field, $origin, $scale, $offset = null, $decay = null, $scaleWeight = null, - AbstractFilter $filter = null) - { + public function addDecayFunction( + $function, + $field, + $origin, + $scale, + $offset = null, + $decay = null, + $weight = null, + AbstractFilter $filter = null + ) { $functionParams = array( $field => array( 'origin' => $origin, @@ -109,32 +122,44 @@ public function addDecayFunction($function, $field, $origin, $scale, $offset = n if (!is_null($decay)) { $functionParams[$field]['decay'] = (float) $decay; } - if (!is_null($scaleWeight)) { - $functionParams[$field]['scale_weight'] = (float) $scaleWeight; - } - return $this->addFunction($function, $functionParams, $filter); + return $this->addFunction($function, $functionParams, $filter, $weight); } /** * Add a boost_factor function to the query + * * @param float $boostFactor the boost factor value * @param AbstractFilter $filter a filter associated with this function + * + * @return void + * @deprecated */ public function addBoostFactorFunction($boostFactor, AbstractFilter $filter = null) { - $this->addFunction('boost_factor', $boostFactor, $filter); + $this->addWeightFunction($boostFactor, $filter); + } + + /** + * @param float $weight the weight of the function + * @param AbstractFilter $filter a filter associated with this function + * + * @return void + */ + public function addWeightFunction($weight, AbstractFilter $filter = null) + { + $this->addFunction('weight', $weight, $filter); } /** * Add a random_score function to the query * @param number $seed the seed value * @param AbstractFilter $filter a filter associated with this function - * @param float $boost an optional boost value associated with this function + * @param float $weight an optional boost value associated with this function */ - public function addRandomScoreFunction($seed, AbstractFilter $filter = null, $boost = null) + public function addRandomScoreFunction($seed, AbstractFilter $filter = null, $weight = null) { - $this->addFunction('random_score', array('seed' => $seed), $filter, $boost); + $this->addFunction('random_score', array('seed' => $seed), $filter, $weight); } /** diff --git a/lib/Elastica/Status.php b/lib/Elastica/Status.php index 3ff3ae4afc..cce94fea10 100644 --- a/lib/Elastica/Status.php +++ b/lib/Elastica/Status.php @@ -80,12 +80,7 @@ public function getIndexStatuses() */ public function getIndexNames() { - $names = array(); - foreach ($this->_data['indices'] as $name => $data) { - $names[] = $name; - } - - return $names; + return array_keys($this->_data['indices']); } /** diff --git a/test/benchmark/BulkMemoryUsageTest.php b/test/benchmark/BulkMemoryUsageTest.php index 23e6521f3e..4494ec3511 100644 --- a/test/benchmark/BulkMemoryUsageTest.php +++ b/test/benchmark/BulkMemoryUsageTest.php @@ -41,6 +41,6 @@ public function testServersArray() $endMemory = memory_get_usage(); - $this->assertLessThan(1.2, $endMemory/$startMemory); + $this->assertLessThan(1.3, $endMemory/$startMemory); } } diff --git a/test/lib/Elastica/Test/Base.php b/test/lib/Elastica/Test/Base.php index 55cd88739d..c6c995ec02 100644 --- a/test/lib/Elastica/Test/Base.php +++ b/test/lib/Elastica/Test/Base.php @@ -3,6 +3,7 @@ namespace Elastica\Test; use Elastica\Client; +use Elastica\Index; class Base extends \PHPUnit_Framework_TestCase { @@ -28,4 +29,17 @@ protected function _createIndex($name = 'test', $delete = true, $shards = 1) return $index; } + + protected function _waitForAllocation(Index $index) + { + do { + $settings = $index->getStatus()->get(); + $allocated = true; + foreach ($settings['shards'] as $shard) { + if ($shard[0]['routing']['state'] != 'STARTED') { + $allocated = false; + } + } + } while (!$allocated); + } } diff --git a/test/lib/Elastica/Test/Facet/GeoClusterTest.php b/test/lib/Elastica/Test/Facet/GeoClusterTest.php index d06b58f9c7..a82379f1b5 100644 --- a/test/lib/Elastica/Test/Facet/GeoClusterTest.php +++ b/test/lib/Elastica/Test/Facet/GeoClusterTest.php @@ -39,6 +39,7 @@ public function testQuery() { $query = new \Elastica\Query(); $query->setFacets(array($facet)); + $response = $type->search($query); $facets = $response->getFacets(); @@ -46,4 +47,4 @@ public function testQuery() { $index->delete(); } -} \ No newline at end of file +} diff --git a/test/lib/Elastica/Test/Index/SettingsTest.php b/test/lib/Elastica/Test/Index/SettingsTest.php index c55668ea77..eb710a10d2 100644 --- a/test/lib/Elastica/Test/Index/SettingsTest.php +++ b/test/lib/Elastica/Test/Index/SettingsTest.php @@ -10,7 +10,7 @@ class SettingsTest extends BaseTest { - + public function testGet() { $indexName = 'elasticatest'; @@ -197,12 +197,11 @@ public function testSetReadOnly() $type = $index->getType('test'); $type->addDocument($doc1); - $this->assertEquals('false', $index->getSettings()->get('blocks.read_only')); //ES returns a string for this setting + $this->assertFalse($index->getSettings()->getReadOnly()); // Try to add doc to read only index $index->getSettings()->setReadOnly(true); - - $this->assertEquals('true', $index->getSettings()->get('blocks.read_only')); + $this->assertTrue($index->getSettings()->getReadOnly()); try { $type->addDocument($doc2); @@ -210,7 +209,7 @@ public function testSetReadOnly() } catch (ResponseException $e) { $message = $e->getMessage(); $this->assertContains('ClusterBlockException', $message); - $this->assertContains('index read-only', $message); + $this->assertContains('index write', $message); } // Remove read only, add document @@ -287,16 +286,24 @@ public function testGetSetBlocksMetadata() $index->delete(); } - protected function _waitForAllocation(Index $index) + /** + * testNotFoundIndex + * + * @access public + * @return void + */ + public function testNotFoundIndex() { - do { - $settings = $index->getStatus()->get(); - $allocated = true; - foreach ($settings['shards'] as $shard) { - if ($shard[0]['routing']['state'] != 'STARTED') { - $allocated = false; - } - } - } while (!$allocated); + $client = $this->_getClient(); + $index = $client->getIndex('not_found_index'); + //wait for the shards to be allocated + + try { + $settings = $index->getSettings()->get(); + $this->fail('Should throw exception because of index not found'); + } catch (ResponseException $e) { + $message = $e->getMessage(); + $this->assertContains('IndexMissingException', $message); + } } } diff --git a/test/lib/Elastica/Test/IndexTest.php b/test/lib/Elastica/Test/IndexTest.php index 30264e70c6..8601ecb97f 100644 --- a/test/lib/Elastica/Test/IndexTest.php +++ b/test/lib/Elastica/Test/IndexTest.php @@ -356,8 +356,10 @@ public function testAddAliasTwoIndices() $index2 = $client->getIndex($indexName2); $index1->create(array(), true); + $this->_waitForAllocation($index1); $index1->addAlias($aliasName); $index2->create(array(), true); + $this->_waitForAllocation($index2); $index1->refresh(); $index2->refresh(); @@ -560,18 +562,21 @@ public function testCreateArray() //Testing recreate (backward compatibility) $index = $client->getIndex($indexName); $index->create(array(), true); + $this->_waitForAllocation($index); $status = new Status($client); $this->assertTrue($status->indexExists($indexName)); //Testing create index with array options $opts = array('recreate' => true, 'routing' => 'r1,r2'); $index->create(array(), $opts); + $this->_waitForAllocation($index); $status = new Status($client); $this->assertTrue($status->indexExists($indexName)); //Testing invalid options $opts = array('recreate' => true, 'routing' => 'r1,r2', 'testing_invalid_option' => true); $index->create(array(), $opts); + $this->_waitForAllocation($index); $status = new Status($client); $this->assertTrue($status->indexExists($indexName)); } diff --git a/test/lib/Elastica/Test/PercolatorTest.php b/test/lib/Elastica/Test/PercolatorTest.php index f4cfae0c06..40dca2ad03 100644 --- a/test/lib/Elastica/Test/PercolatorTest.php +++ b/test/lib/Elastica/Test/PercolatorTest.php @@ -9,6 +9,7 @@ use Elastica\Query\Term; use Elastica\Query; use Elastica\Test\Base as BaseTest; +use Elastica\Type; class PercolatorTest extends BaseTest { @@ -17,6 +18,7 @@ public function testConstruct() $percolatorName = 'percotest'; $index = $this->_createIndex($percolatorName); + $percolator = new Percolator($index); $query = new Term(array('field1' => 'value1')); @@ -40,6 +42,7 @@ public function testConstruct() public function testMatchDoc() { $index = $this->_createIndex(); + $percolator = new Percolator($index); $percolatorName = 'percotest'; @@ -221,4 +224,21 @@ public function testPercolateExistingDocWithIdThatShouldBeUrlEncoded() $this->assertCount(1, $matches); $index->delete(); } + + /** + * {@inheritdoc} + */ + protected function _createIndex($name = 'test', $delete = true, $shards = 1) + { + $index = parent::_createIndex($name, $delete, $shards); + $type = new Type($index, 'test'); + $mapping = [ + 'name' => ['type' => 'string'], + 'field1' => ['type' => 'string'], + ]; + + $type->setMapping($mapping); + + return $index; + } } diff --git a/test/lib/Elastica/Test/Query/FunctionScoreTest.php b/test/lib/Elastica/Test/Query/FunctionScoreTest.php index 47d9dd2ce8..7063e152ef 100644 --- a/test/lib/Elastica/Test/Query/FunctionScoreTest.php +++ b/test/lib/Elastica/Test/Query/FunctionScoreTest.php @@ -94,6 +94,52 @@ public function testToArray() $this->assertEquals($expected, $query->toArray()); } + public function testDecayWeight() + { + $priceOrigin = 0; + $locationScale = '2mi'; + $priceScale = 9.25; + $query = new FunctionScore(); + $childQuery = new \Elastica\Query\MatchAll(); + $query->setQuery($childQuery); + $query->addDecayFunction( + FunctionScore::DECAY_GAUSS, + 'location', + $this->locationOrigin, + $locationScale, + null, + null, + .5 + ); + $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', $priceOrigin, $priceScale, null, null, 2); + $expected = array( + 'function_score' => array( + 'query' => $childQuery->toArray(), + 'functions' => array( + array( + 'gauss' => array( + 'location' => array( + 'origin' => $this->locationOrigin, + 'scale' => $locationScale + ) + ), + 'weight' => .5, + ), + array( + 'gauss' => array( + 'price' => array( + 'origin' => $priceOrigin, + 'scale' => $priceScale + ) + ), + 'weight' => 2, + ) + ) + ) + ); + $this->assertEquals($expected, $query->toArray()); + } + public function testGauss() { $query = new FunctionScore(); @@ -107,7 +153,7 @@ public function testGauss() $this->assertEquals("Mr. Frostie's", $result0['name']); } - public function testBoostFactor() + public function testWeight() { $filter = new Term(array('price' => 4.5)); $query = new FunctionScore(); @@ -116,7 +162,7 @@ public function testBoostFactor() 'function_score' => array( 'functions' => array( array( - 'boost_factor' => 5.0, + 'weight' => 5.0, 'filter' => array( 'term' => array( 'price' => 4.5 @@ -165,11 +211,37 @@ public function testRandomScore() $results = $response->getResults(); // the document with the random score should have a score > 1, means it is the first result - $result0 = $results[1]->getData(); - + $result0 = $results[0]->getData(); + $this->assertEquals("Miller's Field", $result0['name']); } + public function testRandomScoreWeight() + { + $filter = new Term(array('price' => 4.5)); + $query = new FunctionScore(); + $query->addRandomScoreFunction(2, $filter, 2); + $expected = array( + 'function_score' => array( + 'functions' => array( + array( + 'random_score' => array( + 'seed' => 2 + ), + 'filter' => array( + 'term' => array( + 'price' => 4.5 + ) + ), + 'weight' => 2, + ) + ) + ) + ); + + $this->assertEquals($expected, $query->toArray()); + } + public function testRandomScoreWithoutSeed() { $query = new FunctionScore(); diff --git a/test/lib/Elastica/Test/ScriptFieldsTest.php b/test/lib/Elastica/Test/ScriptFieldsTest.php index a3dd0d516e..718fa0c8fe 100644 --- a/test/lib/Elastica/Test/ScriptFieldsTest.php +++ b/test/lib/Elastica/Test/ScriptFieldsTest.php @@ -17,9 +17,10 @@ public function setUp() $this->index = $this->_createIndex(); } - public function tearDown() + protected function tearDown() { $this->index->delete(); + parent::tearDown(); } public function testNewScriptFields() diff --git a/test/lib/Elastica/Test/SearchTest.php b/test/lib/Elastica/Test/SearchTest.php index fc4d1695df..026a98d5a5 100644 --- a/test/lib/Elastica/Test/SearchTest.php +++ b/test/lib/Elastica/Test/SearchTest.php @@ -358,6 +358,13 @@ public function testArrayConfigSearch() $this->assertTrue(($resultSet->count() === 0) && $resultSet->getTotalHits() === 11); //Timeout - this one is a bit more tricky to test + $mockResponse = new \Elastica\Response(json_encode(['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); @@ -471,24 +478,24 @@ public function testEmptySearch() $source = $resultSet->current()->getSource(); $this->assertEquals('bunny', $source['username']); } - + public function testCount() { $index = $this->_createIndex('eeee'); $search = new Search($index->getClient()); $type = $index->getType('test'); - + $doc = new Document(1, array('id' => 1, 'username' => 'ruflin')); - + $type->addDocument($doc); $index->refresh(); - + $search->addIndex($index); $search->addType($type); - + $result1 = $search->count(new \Elastica\Query\MatchAll()); $this->assertEquals(1, $result1); - - + + $result2 = $search->count(new \Elastica\Query\MatchAll(), true); $this->assertInstanceOf('\Elastica\ResultSet', $result2); $this->assertEquals(1, $result2->getTotalHits()); diff --git a/test/lib/Elastica/Test/TypeTest.php b/test/lib/Elastica/Test/TypeTest.php index 89aeeb147d..4c91b25a29 100644 --- a/test/lib/Elastica/Test/TypeTest.php +++ b/test/lib/Elastica/Test/TypeTest.php @@ -674,6 +674,7 @@ public function testUpdateDocumentWithFieldsSource() public function testUpdateDocumentWithoutId() { $index = $this->_createIndex(); + $this->_waitForAllocation($index); $type = $index->getType('elastica_type'); $document = new Document(); @@ -781,6 +782,7 @@ public function testAddDocumentAutoGeneratedId() public function testAddDocumentWithoutSerializer() { $index = $this->_createIndex(); + $this->_waitForAllocation($index); $type = new Type($index, 'user');