Custom query with search_api_facets hides other facet items when addCondition is added

Created on 22 April 2022, over 2 years ago

Problem/Motivation

Hi there. I have the following query to bring nodes and a facet called "Type":

    $query = $this->index->query();

    $query->setOption('search_api_facets', [
      'type' => [
        'field' => 'field_type',
        'limit' => 0,
        'operator' => 'OR',
        'min_count' => 1,
        'missing' => FALSE,
      ],
    ]);

    $results = $query->execute();
    $facets = $results->getExtraData('search_api_facets', []);

It shows the facet options:
[ ] New
[ ] Preowned
[ ] Loaner

However, if I add a query condition like below, it shows only the "New" facet option:
$query->addCondition('field_type', 'New');

The facets show only:
[x] New

When I capture the Solr logs, it shows this in the params fq=ss_field_type:"New", whereas I think it should show this instead fq={!tag=facet:field_type}ss_field_type:"New" based on this Solr doc https://solr.apache.org/guide/6_6/faceting.html

I wonder if there's another way to use Facets with filters programmatically, keeping the other facet options when one is selected? E.g.:

[x] New
[ ] Preowned
[ ] Loaner

Thank you!

Drupal core 9.3.3
Search API 8.x-1.23
Search API Solr 4.2.0
Facets 2.0.2

💬 Support request
Status

Active

Version

2.0

Component

Code

Created by

🇧🇷Brazil rcsilvadev São Paulo, Brazil

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇧🇾Belarus andreylugovtsov

    Were you able to find a solution?
    Facing the same problem

  • 🇧🇾Belarus andreylugovtsov
    
    In case someone else facet the problem.
    Solution is to register an event subscriber and modify Solr query according to documentation.
    
    /**
     * Add tags to fq fields and facet.field fields to exclude each facet's
     * filtering constraints 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 https://solr.apache.org/guide/7_6/faceting.html#tagging-and-excluding-filters
     */
    class ProcessFacetFilterQuery implements EventSubscriberInterface {
    
      /**
       * {@inheritdoc}
       */
      public static function getSubscribedEvents(): array {
        return [
          Events::POST_CREATE_REQUEST => 'processFacets',
        ];
      }
    
      /**
       * Process facets fields.
       *
       * @param \Solarium\Core\Event\PostCreateRequest $event
       *   The event.
       */
      public function processFacets(PostCreateRequest $event): void {
        $request = $event->getRequest();
        $params = $request->getParams();
    
        foreach ($params['facet.field'] ?? [] as $facetField) {
          /*
           * Spotting an "ex=facet:" tag inside facet field value means
           * that facet is configured in OR mode. That works right.
           * Problem occurs, when that facet is also used in a query condition.
           * That makes it lose its values.
           * A modification to fq param should be applied in that case.
           */
          $fieldName = preg_match('/ex=facet:(.*)}/', $facetField, $matches) ? $matches[1] : NULL;
          if ($fieldName) {
            $this->modifyFilterQueryParam($params, $fieldName);
          }
        }
    
        $request->setParams($params);
      }
    
      /**
       * Modify fq filter param.
       *
       * @param array $params
       *   Request params.
       * @param string $facetField
       *   Facet field name.
       *
       *   If facet filter is being applied as a query condition,
       *   fq param should be modified to exclude facet filter
       *   from losing its values.
       *
       * @see https://solr.apache.org/guide/7_6/faceting.html#changing-the-output-key
       * @see \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::setFacets()
       */
      private function modifyFilterQueryParam(array &$params, string $facetField): void {
        foreach ($params['fq'] as $key => $field) {
          if (str_contains($field, $facetField)) {
            $params['fq'][$key] = "{!tag=facet:{$facetField}}" . $field;
          }
        }
      }
    
    }
    
Production build 0.71.5 2024