diff --git a/docs/queries/select-query/building-a-select-query/components/distributed-search-component.md b/docs/queries/select-query/building-a-select-query/components/distributed-search-component.md index 510f7551c..951e3aa87 100644 --- a/docs/queries/select-query/building-a-select-query/components/distributed-search-component.md +++ b/docs/queries/select-query/building-a-select-query/components/distributed-search-component.md @@ -8,6 +8,7 @@ Options | shards | string | null | Shards to use for request | | shardhandler | string | null | Request handler to use | | collections | string | null | A list of collections, for use with SolrCloud (available in Solarium 3.1+) | +| replicas | string | null | A list of replicas, for use with SolrCloud (available in Solarium 3.1+) | || Example diff --git a/library/Solarium/QueryType/Select/Query/Component/DistributedSearch.php b/library/Solarium/QueryType/Select/Query/Component/DistributedSearch.php index 5e6c9f05a..b4341d102 100644 --- a/library/Solarium/QueryType/Select/Query/Component/DistributedSearch.php +++ b/library/Solarium/QueryType/Select/Query/Component/DistributedSearch.php @@ -65,6 +65,13 @@ class DistributedSearch extends AbstractComponent */ protected $collections = array(); + /** + * Requests will be load balanced across replicas in this list. + * + * @var array + */ + protected $replicas = array(); + /** * Get component type. * @@ -318,6 +325,94 @@ public function getCollections() return $this->collections; } + /** + * Add a replica. + * + * @param string $key unique string + * @param string $replica The syntax is host:port/base_url + * + * @return self Provides fluent interface + * + * @link https://cwiki.apache.org/confluence/display/solr/Distributed+Requests + */ + public function addReplica($key, $replica) + { + $this->replicas[$key] = $replica; + + return $this; + } + + /** + * Add multiple replicas. + * + * @param array $replicas + * + * @return self Provides fluent interface + */ + public function addReplicas(array $replicas) + { + foreach ($replicas as $key => $replica) { + $this->addReplica($key, $replica); + } + + return $this; + } + + /** + * Remove a replica. + * + * @param string $key + * + * @return self Provides fluent interface + */ + public function removeReplica($key) + { + if (isset($this->replicas[$key])) { + unset($this->replicas[$key]); + } + + return $this; + } + + /** + * Remove all replicas. + * + * @return self Provides fluent interface + */ + public function clearReplicas() + { + $this->replicas = array(); + + return $this; + } + + /** + * Set multiple replicas. + * + * This overwrites any existing replicas + * + * @param array $replicas Associative array of collections + * + * @return self Provides fluent interface + */ + public function setReplicas(array $replicas) + { + $this->clearReplicas(); + $this->addReplicas($replicas); + + return $this; + } + + /** + * Get a list of the replicas. + * + * @return array + */ + public function getReplicas() + { + return $this->replicas; + } + /** * Initialize options. * @@ -334,6 +429,9 @@ protected function init() case 'collections': $this->setCollections($value); break; + case 'replicas': + $this->setReplicas($value); + break; } } } diff --git a/library/Solarium/QueryType/Select/RequestBuilder/Component/DistributedSearch.php b/library/Solarium/QueryType/Select/RequestBuilder/Component/DistributedSearch.php index aa5071ca8..80b9ee8f9 100644 --- a/library/Solarium/QueryType/Select/RequestBuilder/Component/DistributedSearch.php +++ b/library/Solarium/QueryType/Select/RequestBuilder/Component/DistributedSearch.php @@ -64,6 +64,14 @@ public function buildComponent($component, $request) $request->addParam('shards', implode(',', $shards)); } + $replicas = array_values($component->getReplicas()); + + if (count($replicas)) { + $value = ($request->getParam('shards')) ? $request->getParam('shards').','.implode('|', $replicas) : implode('|', $replicas); + + $request->addParam('shards', $value, true); + } + $request->addParam('shards.qt', $component->getShardRequestHandler()); // add collections to request diff --git a/tests/Solarium/Tests/QueryType/Select/Query/Component/DistributedSearchTest.php b/tests/Solarium/Tests/QueryType/Select/Query/Component/DistributedSearchTest.php index 78a8a1ea4..bc450264a 100644 --- a/tests/Solarium/Tests/QueryType/Select/Query/Component/DistributedSearchTest.php +++ b/tests/Solarium/Tests/QueryType/Select/Query/Component/DistributedSearchTest.php @@ -75,6 +75,19 @@ public function testConfigModeForCollections() $this->assertEquals($options['collections'], $this->distributedSearch->getCollections()); } + public function testConfigModeForReplicas() + { + $options = array( + 'replicas' => array( + 'replica1' => 'localhost:8983/solr/collection1', + 'replica2' => 'localhost:8983/solr/collection2', + ), + ); + + $this->distributedSearch->setOptions($options); + $this->assertEquals($options['replicas'], $this->distributedSearch->getReplicas()); + } + public function testGetType() { $this->assertEquals( @@ -242,4 +255,73 @@ public function testSetCollections() $collections ); } + + public function testAddReplica() + { + $this->distributedSearch->addReplica('replica1', 'localhost:8983/solr/replica1'); + $replicas = $this->distributedSearch->getReplicas(); + $this->assertEquals( + 'localhost:8983/solr/replica1', + $replicas['replica1'] + ); + } + + public function testRemoveReplica() + { + $this->distributedSearch->addReplica('replica1', 'localhost:8983/solr/replica1'); + $this->distributedSearch->removeReplica('replica1'); + $replicas = $this->distributedSearch->getReplicas(); + $this->assertFalse(isset($replicas['replica1'])); + } + + public function testClearReplicas() + { + $this->distributedSearch->addReplicas( + array( + 'replica1' => 'localhost:8983/solr/replica1', + 'replica2' => 'localhost:8983/solr/replica2', + ) + ); + $this->distributedSearch->clearReplicas(); + $replicas = $this->distributedSearch->getReplicas(); + $this->assertTrue(is_array($replicas)); + $this->assertEquals(0, count($replicas)); + } + + public function testAddReplicas() + { + $replicas = array( + 'replica1' => 'localhost:8983/solr/replica1', + 'replica2' => 'localhost:8983/solr/replica2', + ); + $this->distributedSearch->addReplicas($replicas); + $this->assertEquals($replicas, $this->distributedSearch->getReplicas()); + } + + public function testSetReplicas() + { + $this->distributedSearch->addReplicas( + array( + 'replica1' => 'localhost:8983/solr/replica1', + 'replica2' => 'localhost:8983/solr/replica2', + ) + ); + $this->distributedSearch->setReplicas( + array( + 'replica3' => 'localhost:8983/solr/replica3', + 'replica4' => 'localhost:8983/solr/replica4', + 'replica5' => 'localhost:8983/solr/replica5', + ) + ); + $replicas = $this->distributedSearch->getReplicas(); + $this->assertEquals(3, count($replicas)); + $this->assertEquals( + array( + 'replica3' => 'localhost:8983/solr/replica3', + 'replica4' => 'localhost:8983/solr/replica4', + 'replica5' => 'localhost:8983/solr/replica5', + ), + $replicas + ); + } } diff --git a/tests/Solarium/Tests/QueryType/Select/Query/Component/Facet/IntervalTest.php b/tests/Solarium/Tests/QueryType/Select/Query/Component/Facet/IntervalTest.php new file mode 100644 index 000000000..369711dc5 --- /dev/null +++ b/tests/Solarium/Tests/QueryType/Select/Query/Component/Facet/IntervalTest.php @@ -0,0 +1,88 @@ +facet = new Interval(); + } + + public function testConfigMode() + { + $options = array( + 'key' => 'myKey', + 'exclude' => array('e1', 'e2'), + 'set' => array('i1', 'i2'), + ); + + $this->facet->setOptions($options); + + $this->assertEquals($options['key'], $this->facet->getKey()); + $this->assertEquals($options['exclude'], $this->facet->getExcludes()); + $this->assertEquals($options['set'], $this->facet->getSet()); + } + + public function testGetType() + { + $this->assertEquals( + FacetSet::FACET_INTERVAL, + $this->facet->getType() + ); + } + + public function testSetAndGetSet() + { + $this->facet->setSet('interval1,interval2'); + $this->assertEquals(array('interval1', 'interval2'), $this->facet->getSet()); + } + + public function testEmptySet() + { + $this->assertEquals(array(), $this->facet->getSet()); + } + + public function testSetAndGetField() + { + $this->facet->setField('field1'); + $this->assertEquals('field1', $this->facet->getField()); + } +} diff --git a/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/DistributedSearchTest.php b/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/DistributedSearchTest.php index 7d8894e79..226ed9ded 100644 --- a/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/DistributedSearchTest.php +++ b/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/DistributedSearchTest.php @@ -82,4 +82,47 @@ public function testBuildComponentWithCollections() $this->assertEquals(array('collection' => $url.'1,'.$url.'2,'.$url.'3'), $request->getParams()); } + + public function testBuildComponentWithReplicas() + { + $builder = new RequestBuilder(); + $request = new Request(); + + $url = 'localhost:8983/solr/replica'; + $component = new Component(); + $component->addReplica('replica1', $url.'1'); + $component->addReplicas( + array( + 'replica2' => $url.'2', + 'replica3' => $url.'3', + ) + ); + + $request = $builder->buildComponent($component, $request); + + $this->assertEquals(array('shards' => $url.'1|'.$url.'2|'.$url.'3'), $request->getParams()); + } + + + + public function testBuildComponentWithReplicasAndShard() + { + $builder = new RequestBuilder(); + $request = new Request(); + + $url = 'localhost:8983/solr/replica'; + $component = new Component(); + $component->addShard('shard1', 'localhost:8983/solr/shard1'); + + $component->addReplicas( + array( + 'replica2' => $url.'2', + 'replica3' => $url.'3', + ) + ); + + $request = $builder->buildComponent($component, $request); + + $this->assertEquals(array('shards' => 'localhost:8983/solr/shard1,'.$url.'2|'.$url.'3'), $request->getParams()); + } } diff --git a/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/FacetSetTest.php b/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/FacetSetTest.php index 2fd2c33e7..f1b99117b 100644 --- a/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/FacetSetTest.php +++ b/tests/Solarium/Tests/QueryType/Select/RequestBuilder/Component/FacetSetTest.php @@ -39,6 +39,7 @@ use Solarium\QueryType\Select\Query\Component\Facet\MultiQuery as FacetMultiQuery; use Solarium\QueryType\Select\Query\Component\Facet\Range as FacetRange; use Solarium\QueryType\Select\Query\Component\Facet\Pivot as FacetPivot; +use Solarium\QueryType\Select\Query\Component\Facet\Interval as FacetInterval; class FacetSetTest extends \PHPUnit_Framework_TestCase { @@ -259,6 +260,31 @@ public function testBuildWithContainsSettings() urldecode($request->getUri()) ); } + + public function testBuildeWithIntervalFacet() + { + $facet = new FacetInterval( + array( + 'key' => 'f1', + 'fields' => 'cat,inStock', + 'set' => array(0 => 'int1', 'one' => 'int2'), + ) + ); + + $this->component->addFacet($facet); + + $request = $this->builder->buildComponent($this->component, $this->request); + + $this->assertEquals( + null, + $request->getRawData() + ); + + $this->assertEquals( + '?facet=true&f..facet.interval.set=int1&f..facet.interval.set={!key="one"}int2', + urldecode($request->getUri()) + ); + } } class UnknownFacet extends FacetField