solariumphp / solarium

PHP Solr client library
Other
931 stars 301 forks source link

"Complex" range implementation #240

Closed trasher closed 1 year ago

trasher commented 10 years ago

Hello,

I'm trying to get a range facet on the the same date field with multiple parameters. On Solr side, I use something like: {!key=foo facet.date.start=1980-01-01T00:00:00.000Z facet.date.end=2000-01-01T00:00:00.000Z facet.date.gap=+1DAY}date_field

That way, I get a facet named "foo" with the specified parameters on my date_field field. I did not find the right way to do that with Solarium :/

I've tried to pass the full expression in the createFacetRange() function. Doing this, I get the correct query sent to Solr, but Solarium is "not able" to retrieve results, so getFacets() does not return those specific results.

As far as I understand what happens in the Solarium\QueryType\Select\ResponseParser\Component::parse() function, Solarium will try to load a facet named "foo facet.date.start[...]" while Solr returns a facet named "foo".

Is there something I've missed or misunderstand, or is this feature not (yet?) implemented into Solarium? Is there a way I can get my facet results back?

Than you

trasher commented 10 years ago

Assuming key names cannot contains spaces, I've found a solution that works for me, let me know if you think that is incorrect:

diff -up ./library/Solarium/QueryType/Select/ResponseParser/Component/FacetSet.php.patch ./library/Solarium/QueryType/Select/ResponseParser/Component/FacetSet.php
--- ./library/Solarium/QueryType/Select/ResponseParser/Component/FacetSet.php.patch 2014-01-27 09:32:11.400457599 +0100
+++ ./library/Solarium/QueryType/Select/ResponseParser/Component/FacetSet.php   2014-01-27 09:15:28.819825528 +0100
@@ -99,6 +99,7 @@ class FacetSet extends ResponseParserAbs

         $facets = array();
         foreach ($facetSet->getFacets() as $key => $facet) {
+            $key = current(explode(' ', $key));
             switch ($facet->getType()) {
                 case QueryFacetSet::FACET_FIELD:
                     $result = $this->facetField($query, $facet, $data);
@@ -210,7 +211,7 @@ class FacetSet extends ResponseParserAbs
      */
     protected function facetRange($query, $facet, $data)
     {
-        $key = $facet->getKey();
+        $key = current(explode(' ', $facet->getKey()));
         if (isset($data['facet_counts']['facet_ranges'][$key])) {

             $data = $data['facet_counts']['facet_ranges'][$key];
basdenooijer commented 10 years ago

Thanks for the proposed solution. I'd like to experiment with it a bit, could you also show me the code you use to create and execute the query? That way I could try to convert this scenario into a unittest.

trasher commented 10 years ago

Here is a snippet of code (it's an adaptation, my real code is quite complex and is splitted into various functions):

$client = new Solarium\Client($config);
$query = $client->createSelect();
$facetSet = $query->getFacetSet();
$first_range = $facetSet->createFacetRange('threeyears');
$first_range->setField('date_field');
$first_range->setStart('1500-12-31T00:00:00Z');
$first_range->setEnd('2010-12-31T23:59:59Z');
$first_range->setGap('+3YEARS');
$second_ranger = $facetSet->createFacetRange(
    'years f.date_field.facet.range.start=1500-12-31T00:00:00Z f.date_field.facet.range.end=2010-12-31T23:59:59Z f.date_field.facet.range.gap=+1YEARS'
);
$second_range->setField('date_field');
$resultset = $client->select($query);
$result_facets = $resultset->getFacetSet();

$first_range_facet = $facetSet->getFacet('threeyears');
$second_range_facet = $facetSet->getFacet('years');
[...]

Both ranges use the same field (date_field), but the first one will use a 3 years gap, when the second one will use 1 year gap. Start and end range values can of course differ too.

FYI, I've found the solr syntax on that Jira entry: https://issues.apache.org/jira/browse/SOLR-1351?focusedCommentId=13633018&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13633018

Hope that can help :)

thomascorthals commented 1 year ago

This trick no longer work since Solarium 6.2.3. If you create a facet with a string argument like this, it is escaped automatically and Solr will interpret it as the full facet key.

$second_range = $facetSet->createFacetRange(
    'years f.date_field.facet.range.start=1500-12-31T00:00:00Z f.date_field.facet.range.end=2010-12-31T23:59:59Z f.date_field.facet.range.gap=+1YEARS'
);
$second_range->setField('date_field');

Since Solarium 6.1.4, you can send a request with multiple range facets on the same field like this. Starting with Solarium 6.2.3, spaces in the key are also supported.

$first_range = $facetSet->createFacetRange('threeyears');
$first_range->setField('{!f.date_field.facet.range.start=1500-12-31T00:00:00Z f.date_field.facet.range.end=2010-12-31T23:59:59Z f.date_field.facet.range.gap=+3YEARS}date_field');

$second_range = $facetSet->createFacetRange('years');
$second_range->setField('{!f.date_field.facet.range.start=1500-12-31T00:00:00Z f.date_field.facet.range.end=2010-12-31T23:59:59Z f.date_field.facet.range.gap=+1YEARS}date_field');

Earlier versions render an invalid request string with this code.