Commit 73ebbf44 authored by Bas de Nooijer's avatar Bas de Nooijer

- added range facet

- added unittests for range facet
parent 80ac9643
...@@ -130,6 +130,9 @@ class Solarium_Client_Request_Select extends Solarium_Client_Request ...@@ -130,6 +130,9 @@ class Solarium_Client_Request_Select extends Solarium_Client_Request
case Solarium_Query_Select_Component_Facet::MULTIQUERY: case Solarium_Query_Select_Component_Facet::MULTIQUERY:
$this->addFacetMultiQuery($facet); $this->addFacetMultiQuery($facet);
break; break;
case Solarium_Query_Select_Component_Facet::RANGE:
$this->addFacetRange($facet);
break;
default: default:
throw new Solarium_Exception('Unknown facet type'); throw new Solarium_Exception('Unknown facet type');
} }
...@@ -193,6 +196,40 @@ class Solarium_Client_Request_Select extends Solarium_Client_Request ...@@ -193,6 +196,40 @@ class Solarium_Client_Request_Select extends Solarium_Client_Request
$this->addFacetQuery($facetQuery); $this->addFacetQuery($facetQuery);
} }
} }
/**
* Add params for a range facet to request
*
* @param Solarium_Query_Select_Component_Facet_Range $facet
* @return void
*/
public function addFacetRange($facet)
{
$field = $facet->getField();
$this->addParam(
'facet.range',
$this->renderLocalParams(
$field,
array('key' => $facet->getKey(), 'ex' => $facet->getExcludes())
)
);
$this->addParam("f.$field.facet.range.start", $facet->getStart());
$this->addParam("f.$field.facet.range.end", $facet->getEnd());
$this->addParam("f.$field.facet.range.gap", $facet->getGap());
$this->addParam("f.$field.facet.range.hardend", $facet->getHardend());
$other = explode(',', $facet->getOther());
foreach ($other AS $otherValue) {
$this->addParam("f.$field.facet.range.other", trim($otherValue));
}
$include = explode(',', $facet->getInclude());
foreach ($include AS $includeValue) {
$this->addParam("f.$field.facet.range.include", trim($includeValue));
}
}
/** /**
* Add params for morelikethis * Add params for morelikethis
......
...@@ -123,6 +123,9 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response ...@@ -123,6 +123,9 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response
case Solarium_Query_Select_Component_Facet::MULTIQUERY: case Solarium_Query_Select_Component_Facet::MULTIQUERY:
$this->_addFacetMultiQuery($facet); $this->_addFacetMultiQuery($facet);
break; break;
case Solarium_Query_Select_Component_Facet::RANGE:
$this->_addFacetRange($facet);
break;
default: default:
throw new Solarium_Exception('Unknown facet type'); throw new Solarium_Exception('Unknown facet type');
} }
...@@ -151,7 +154,7 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response ...@@ -151,7 +154,7 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response
} }
$this->_facets[$key] = $this->_facets[$key] =
new Solarium_Result_Select_Component_Facet_Field($facetValues); new Solarium_Result_Select_Facet_Field($facetValues);
} }
} }
...@@ -168,7 +171,7 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response ...@@ -168,7 +171,7 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response
$value = $this->_data['facet_counts']['facet_queries'][$key]; $value = $this->_data['facet_counts']['facet_queries'][$key];
$this->_facets[$key] = $this->_facets[$key] =
new Solarium_Result_Select_Component_Facet_Query($value); new Solarium_Result_Select_Facet_Query($value);
} }
} }
...@@ -190,7 +193,30 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response ...@@ -190,7 +193,30 @@ class Solarium_Client_Response_Select extends Solarium_Client_Response
} }
$this->_facets[$facet->getKey()] = $this->_facets[$facet->getKey()] =
new Solarium_Result_Select_Component_Facet_MultiQuery($values); new Solarium_Result_Select_Facet_MultiQuery($values);
}
/**
* Add a facet result for a range facet
*
* @param Solarium_Query_Select_Component_Facet_Range $facet
* @return void
*/
protected function _addFacetRange($facet)
{
$key = $facet->getKey();
if (isset($this->_data['facet_counts']['facet_ranges'][$key])) {
$data = $this->_data['facet_counts']['facet_ranges'][$key];
$before = (isset($data['before'])) ? $data['before'] : null;
$after = (isset($data['after'])) ? $data['after'] : null;
$between = (isset($data['after'])) ? $data['after'] : null;
$this->_facets[$key] =
new Solarium_Result_Select_Facet_Range($data['counts'], $before, $after, $between);
}
} }
/** /**
......
...@@ -52,6 +52,7 @@ abstract class Solarium_Query_Select_Component_Facet extends Solarium_Configurab ...@@ -52,6 +52,7 @@ abstract class Solarium_Query_Select_Component_Facet extends Solarium_Configurab
const QUERY = 'query'; const QUERY = 'query';
const FIELD = 'field'; const FIELD = 'field';
const MULTIQUERY = 'multiquery'; const MULTIQUERY = 'multiquery';
const RANGE = 'range';
/** /**
* Exclude tags for this facet * Exclude tags for this facet
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
*
* @package Solarium
* @subpackage Query
*/
/**
* Facet range
*
* @link http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range
*
* @package Solarium
* @subpackage Query
*/
class Solarium_Query_Select_Component_Facet_Range extends Solarium_Query_Select_Component_Facet
{
/**
* Values for the 'other' option
*/
const OTHER_BEFORE = 'before';
const OTHER_AFTER = 'after';
const OTHER_BETWEEN = 'between';
const OTHER_ALL = 'all';
const OTHER_NONE = 'none';
/**
* Values for the 'include' option
*/
const INCLUDE_LOWER = 'lower';
const INCLUDE_UPPER = 'upper';
const INCLUDE_EDGE = 'edge';
const INCLUDE_OUTER = 'outer';
const INCLUDE_ALL = 'all';
/**
* Initialize options
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
*
* @return void
*/
protected function _init()
{
foreach ($this->_options AS $name => $value) {
switch ($name) {
case 'include':
$this->setInclude($value);
break;
case 'other':
$this->setOther($value);
break;
}
}
}
/**
* Get the facet type
*
* @return string
*/
public function getType()
{
return self::RANGE;
}
/**
* Set the field name
*
* @param string $query
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setField($field)
{
return $this->_setOption('field', $field);
}
/**
* Get the field name
*
* @return string
*/
public function getField()
{
return $this->getOption('field');
}
/**
* Set the lower bound of the range
*
* @param string $start
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setStart($start)
{
return $this->_setOption('start', $start);
}
/**
* Get the lower bound of the range
*
* @return string
*/
public function getStart()
{
return $this->getOption('start');
}
/**
* Set the upper bound of the range
*
* @param string $end
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setEnd($end)
{
return $this->_setOption('end', $end);
}
/**
* Get the upper bound of the range
*
* @return string
*/
public function getEnd()
{
return $this->getOption('end');
}
/**
* Set range gap
*
* The size of each range expressed as a value to be added to the lower bound
*
* @param string $gap
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setGap($gap)
{
return $this->_setOption('gap', $gap);
}
/**
* Get range gap
*
* The size of each range expressed as a value to be added to the lower bound
*
* @return string
*/
public function getGap()
{
return $this->getOption('gap');
}
/**
* Set hardend option
*
* A Boolean parameter instructing Solr what to do in the event that facet.range.gap
* does not divide evenly between facet.range.start and facet.range.end
*
* @param boolean $hardend
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setHardend($hardend)
{
return $this->_setOption('hardend', $hardend);
}
/**
* Get hardend option
*
* @return boolean
*/
public function getHardend()
{
return $this->getOption('hardend');
}
/**
* Set other counts
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $other
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setOther($other)
{
if (is_array($other)) {
$other = implode(',',$other);
}
return $this->_setOption('other', $other);
}
/**
* Get other counts
*
* In case of multiple values a comma separated string will be returned
*
* @return string
*/
public function getOther()
{
return $this->getOption('other');
}
/**
* Set include option
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $include
* @return Solarium_Query_Select_Component_Facet_Range Provides fluent interface
*/
public function setInclude($include)
{
if (is_array($include)) {
$include = implode(',',$include);
}
return $this->_setOption('include', $include);
}
/**
* Get include option
*
* In case of multiple values a comma separated string will be returned
*
* @return string
*/
public function getInclude()
{
return $this->getOption('include');
}
}
\ No newline at end of file
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
*
* @package Solarium
* @subpackage Result
*/
/**
* Select range facet result
*
* A multiquery facet will usually return a dataset of multiple count, in each
* row a range as key and it's count. You can access the values as an array using
* {@link getValues()} or iterate this object.
*
* The extra counts 'before', 'between' and 'after' are only available if the
* right settings for the option 'other' were used in the query.
*
* @package Solarium
* @subpackage Result
*/
class Solarium_Result_Select_Facet_Range extends Solarium_Result_Select_Facet_Field
{
/**
* Count of all records with field values lower then lower bound of the first range
*
* @var int
*/
protected $_before;
/**
* Count of all records with field values greater then the upper bound of the last range
*
* @var int
*/
protected $_after;
/**
* Count all records with field values between the start and end bounds of all ranges
*
* @var int
*/
protected $_between;
/**
* Constructor
*
* @param array $values
* @return void
*/
public function __construct($values, $before, $after, $between)
{
$this->_values = $values;
$this->_before = $before;
$this->_after = $after;
$this->_between = $between;
}
/**
* Get 'before' count
*
* Count of all records with field values lower then lower bound of the first range
* Only available if the 'other' setting was used in the query facet.
*
* @return int
*/
public function getBefore()
{
return $this->_before;
}
/**
* Get 'after' count
*
* Count of all records with field values greater then the upper bound of the last range
* Only available if the 'other' setting was used in the query facet.
*
* @return int
*/
public function getAfter()
{
return $this->_after;
}
/**
* Get 'between' count
*
* Count all records with field values between the start and end bounds of all ranges
* Only available if the 'other' setting was used in the query facet.
*
* @return int
*/
public function getBetween()
{
return $this->_between;
}
}
\ No newline at end of file
...@@ -127,6 +127,33 @@ class Solarium_Client_Request_SelectTest extends PHPUnit_Framework_TestCase ...@@ -127,6 +127,33 @@ class Solarium_Client_Request_SelectTest extends PHPUnit_Framework_TestCase
); );
} }
public function testSelectUrlWithRangeFacet()
{
$this->_query->getFacetSet()->addFacet(new Solarium_Query_Select_Component_Facet_Range(
array(
'key' => 'f1',
'field' => 'price',
'start' => '1',
'end' => 100,
'gap' => 10,
'other' => 'all',
'include' => 'outer'
)
));
$request = new Solarium_Client_Request_Select($this->_options, $this->_query);
$this->assertEquals(
null,
$request->getRawData()
);
$this->assertEquals(
'http://127.0.0.1:80/solr/select?q=*:*&start=0&rows=10&fl=*,score&wt=json&facet=true&facet.range={!key=f1}price&f.price.facet.range.start=1&f.price.facet.range.end=100&f.price.facet.range.gap=10&f.price.facet.range.other=all&f.price.facet.range.include=outer',
urldecode($request->getUri())
);
}
public function testSelectUrlWithFacetsAndGlobalFacetSettings() public function testSelectUrlWithFacetsAndGlobalFacetSettings()
{ {
$this->_query->getFacetSet()->setMissing(true); $this->_query->getFacetSet()->setMissing(true);
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
class Solarium_Query_Select_Component_Facet_RangeTest extends PHPUnit_Framework_TestCase
{
protected $_facet;
public function setUp()
{
$this->_facet = new Solarium_Query_Select_Component_Facet_Range;
}
public function testGetType()
{
$this->assertEquals(
Solarium_Query_Select_Component_Facet::RANGE,
$this->_facet->getType()
);
}
public function testSetAndGetField()
{
$this->_facet->setField('price');
$this->assertEquals('price', $this->_facet->getField());
}
public function testSetAndGetStart()
{
$this->_facet->setStart(1);
$this->assertEquals(1, $this->_facet->getStart());
}
public function testSetAndGetEnd()
{
$this->_facet->setEnd(100);
$this->assertEquals(100, $this->_facet->getEnd());
}
public function testSetAndGetGap()
{
$this->_facet->setGap(10);
$this->assertEquals(10, $this->_facet->getGap());
}
public function testSetAndGetHardend()
{
$this->_facet->setHardend(true);
$this->assertEquals(true, $this->_facet->getHardend());
}
public function testSetAndGetOther()
{
$this->_facet->setOther('all');
$this->assertEquals('all', $this->_facet->getOther());
}
public function testSetAndGetOtherArray()
{
$this->_facet->setOther(array('before','after'));
$this->assertEquals('before,after', $this->_facet->getOther());
}
public function testSetAndGetInclude()
{
$this->_facet->setInclude('all');
$this->assertEquals('all', $this->_facet->getInclude());
}
public function testSetAndGetIncludeArray()
{
$this->_facet->setInclude(array('lower','upper'));
$this->assertEquals('lower,upper', $this->_facet->getInclude());
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
class Solarium_Result_Select_Facet_RangeTest extends PHPUnit_Framework_TestCase
{
/**
* @var Solarium_Result_Select_Facet_Range
*/
protected $_facet;
protected $_values, $_before, $_after, $_between;
public function setUp()
{
$this->_values = array(
'10.0' => 12,
'20.0' => 5,
'30.0' => 3,
);
$this->_before = 2;
$this->_after = 4;
$this->_between = 3;
$this->_facet = new Solarium_Result_Select_Facet_Range($this->_values, $this->_before, $this->_after, $this->_between);
}
public function testGetValues()
{
$this->assertEquals($this->_values, $this->_facet->getValues());
}
public function testCount()
{
$this->assertEquals(count($this->_values), count($this->_facet));
}
public function testIterator()
{
$values = array();
foreach($this->_facet AS $key => $value)
{
$values[$key] = $value;
}
$this->assertEquals($this->_values, $values);
}
public function testGetBefore()
{
$this->assertEquals($this->_before, $this->_facet->getBefore());
}
public function testGetAfter()
{
$this->assertEquals($this->_after, $this->_facet->getAfter());
}
public function testGetBetween()
{
$this->assertEquals($this->_between, $this->_facet->getBetween());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment