There's active development in FacetAPI for supporting multi-select facets with item counts independent of own facet, see #1446824.
For this to work, the backend providers have to add support for this, too - and we at search_api(_solr) should do this, too.
The folks from good 'ole Apache Solr module are moving in this direction, too, see #1448394: Support the multi-select facet feature where the associated counts are maintained as if no contraints have been applied, so we shouldn't fall behind.

The use cases are ubiquitous and manifold. Basically this is needed for good usability on Facets with only one items being allowed to be active at a time, where a user expects to see result counts on items uninfluenced by their own facet status, as a click on another item of that facet would just switch from one item to the other, and not widen or narrow the existing item filtering on that facet.

The short version of this feature request is that it would allow for Solr to provide the "summary output" functionality of Views contextual filters. Since Solr is specifically designed to calculating aggregate results like this, it would be a more efficient option. It would also allow for Solr to used for more navigational purposes.

The respective mechanism in Solr have already been identified. For hints and an example see comment below, and further details and discussion as well as a provisional proof of concept based on solr query rewriting at #1446824: Support the multi-select facet feature of Solr where the associated counts are maintained as if no contraints have been applied.

Comments

danielnolde’s picture

Issue summary: View changes

cosmetics

danielnolde’s picture

(From cpliakas)

Pulling directly from the Solr documentation for reference...

Tagging and excluding Filters

One can tag specific filters and exclude those filters when faceting. This is generally needed when doing multi-select faceting.

Consider the following example query with faceting:

q=mainquery&fq=status:public&fq=doctype:pdf&facet=on&facet.field=doctype

Because everything is already constrained by the filter doctype:pdf, the facet.field=doctype facet command is currently redundant and will return 0 counts for everything except doctype:pdf.

To implement a multi-select facet for doctype, a GUI may want to still display the other doctype values and their associated counts, as if the doctype:pdf constraint had not yet been applied. Example:

=== Document Type ===
  [ ] Word (42)
  [x] PDF  (96)
  [ ] Excel(11)
  [ ] HTML (63)

To return counts for doctype values that are currently not selected, tag filters that directly constrain doctype, and exclude those filters when faceting on doctype.

q=mainquery&fq=status:public&fq={!tag=dt}doctype:pdf&facet=on&facet.field={!ex=dt}doctype
danielnolde’s picture

This taggin concept is basically working as suggested:

Well, not as a general Search API / Facet API implementation a.t.m., but the following code simulates the suggested tagging and tagged-excluding on solr queries made by search_api with search_api_solr, on all involved facets for a certain search_api index. See it as a proof of (the tagging) concept, and/or change it (module name, limiting index name etc.) and use it to solve your (anyone) problem:



/*
 * Implementes _search_api_solr_query_alter().
 *
 * Add tags to fq fields and facet.field fields to exclude each facet's
 * filtering contraints from influencing its own facet item's result counts,
 * to always keep the result counts of each facet item independent of that
 * facet's filtering.
 *
 * See http://drupal.org/node/1446824# for background information.
 */
function ri_portfolio_search_api_solr_query_alter(array &$call_args, SearchApiQueryInterface $query) {
  // Only alter queries on the portfolio index.
  if ($query->getIndex()->machine_name != 'portfolio') return;

  // Go through all facet.field(s).
  foreach($call_args['params']['facet.field'] as $key => $facetfield) {
    // Come up with tag name for the facet.field.
    $tag = 'dtex'.$key;
    // Mark the tag form "exclude from counting" for this facet.
    $call_args['params']['facet.field'][$key] = "{!ex=$tag}" . $facetfield;
    // Tag the respective query field with the tag.
    _ri_portfolio_alter_solr_add_field_tag($call_args, $facetfield, $tag);
    
    // What the heck is done here? See example and explanation at:
    // Example from http://drupal.org/node/1446824#comment-5632892
    // q=mainquery&fq=status:public&fq=doctype:pdf&facet=on&facet.field=doctype
    // q=mainquery&fq=status:public&fq=         doctype:pdf&facet=on&facet.field=        doctype
    // q=mainquery&fq=status:public&fq={!tag=dt}doctype:pdf&facet=on&facet.field={!ex=dt}doctype
  }  
}


/**
 * Helper function to add a tag to a solr query field for search_api_solr query.
 */
function _ri_portfolio_alter_solr_add_field_tag(array &$call_args, $change_fieldname, $tag) {
  foreach($call_args['params']['fq'] as $key => $field) {
    $fieldname_end_pos = strpos($field, ':');
    $fieldname = substr($field, 0, $fieldname_end_pos);
    if ($fieldname == $change_fieldname) {
      $call_args['params']['fq'][$key] = "{!tag=$tag}" . $field;
    }
  }
}



danielnolde’s picture

So, how can we proceed to support this behaviour seemlessly from search_api_solr+search_api to facet_api ?
Chris from Facet API suggested to implement the solr-tagging in the backend (i.e. search_api + search_api_solr), and to offer and propagate a corresponding option for Facet API facets in the bridging code between the two modules.

Thomas (drunken monkey), do you agree?
Where do we attack within search_api(_solr) ?
How do we split work?
Let's discuss the search_api specifics here and coordinate the effort with Facet API over at #1446824: Support the multi-select facet feature of Solr where the associated counts are maintained as if no contraints have been applied, agreed?

andypost’s picture

Hey, is there any progress here? This feature is very needed mostly for navigation purposes and also could be used to produce some visual statistics about data

Anonymous’s picture

Thank you danielnolde, your code saved me a lot of time! It's working great, now I just need to rewrite the Facet API links so that filters are mutually exclusive.

Thanks again!

drunken monkey’s picture

Hasn't this already been solved for almost a year now? Or what's the difference to OR facets?

Anonymous’s picture

The "OR" facets is close to the senario I am trying to implement. The difference is that with the OR facets the previously selected facet is still active when selecting a new one.

The scenario I am trying to achieve is to keep the facet options always visible (and the OR facet does this) but the options should be mutually exclusive.

If I search "Space" In Movies and I get the following Genre terms:

Sci-fi (8)
Action (7)

I should be able to click on Action and from there I should have the option to switch to Sci-Fi (and Action will not be active anymore)

I hope this makes sense. Thanks!

Anonymous’s picture

Nevermind. You are 100% right, the OR behavior is the same. The problem is trying to deactivate one selection when picking another one.

drunken monkey’s picture

Category: feature » support
Status: Active » Fixed

As a last ressort, you could probably just re-write the facet links to only include the new filter for the field.
Anyways, good luck then!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

issue number activation