public ProcessedFilter getProcessedFilter()

in solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java [1212:1348]


  public ProcessedFilter getProcessedFilter(List<Query> queries) throws IOException {
    ProcessedFilter pf = new ProcessedFilter();
    if (queries == null || queries.size() == 0) {
      return pf;
    }

    // We combine all the filter queries that come from the filter cache into "answer".
    // This might become pf.answer but not if there are any non-cached filters
    DocSet answer = null;

    boolean[] neg = new boolean[queries.size()];
    DocSet[] sets = new DocSet[queries.size()];
    List<ExtendedQuery> notCached = null;
    List<PostFilter> postFilters = null;

    int end = 0; // size of "sets" and "neg"; parallel arrays

    for (Query q : queries) {
      if (q instanceof ExtendedQuery eq) {
        if (!eq.getCache()) {
          if (eq.getCost() >= 100 && eq instanceof PostFilter) {
            if (postFilters == null) postFilters = new ArrayList<>(sets.length - end);
            postFilters.add((PostFilter) q);
          } else {
            if (notCached == null) notCached = new ArrayList<>(sets.length - end);
            notCached.add((ExtendedQuery) q);
          }
          continue;
        }
      }

      if (filterCache == null) {
        // there is no cache: don't pull bitsets
        if (notCached == null) notCached = new ArrayList<>(sets.length - end);
        WrappedQuery uncached = new WrappedQuery(q);
        uncached.setCache(false);
        notCached.add(uncached);
        continue;
      }

      Query posQuery = QueryUtils.getAbs(q);
      DocSet docSet = getPositiveDocSet(posQuery);
      // Negative query if absolute value different from original
      if (Objects.equals(q, posQuery)) {
        // keep track of the smallest positive set; use "answer" for this.
        if (answer == null) {
          answer = docSet;
          continue;
        }
        // note: assume that size() is cached.  It generally comes from the cache, so should be.
        if (docSet.size() < answer.size()) {
          // swap answer & docSet so that answer is smallest
          DocSet tmp = answer;
          answer = docSet;
          docSet = tmp;
        }
        neg[end] = false;
      } else {
        neg[end] = true;
      }
      sets[end++] = docSet;
    } // end of queries

    if (end > 0) {
      // Are all of our normal cached filters negative?
      if (answer == null) {
        answer = getLiveDocSet();
      }

      // This optimizes for the case where we have more than 2 filters and instead
      // of copying the bitsets we make one mutable bitset. We should only do this
      // for BitDocSet since it clones the backing bitset for andNot and intersection.
      if (end > 1 && answer instanceof BitDocSet) {
        answer = MutableBitDocSet.fromBitDocSet((BitDocSet) answer);
      }

      // do negative queries first to shrink set size
      for (int i = 0; i < end; i++) {
        if (neg[i]) answer = answer.andNot(sets[i]);
      }

      for (int i = 0; i < end; i++) {
        if (!neg[i]) answer = answer.intersection(sets[i]);
      }

      // Make sure to keep answer as an immutable DocSet if we made it mutable
      answer = MutableBitDocSet.unwrapIfMutable(answer);
    }

    // ignore "answer" if it simply matches all docs
    if (answer != null && answer.size() == numDocs()) {
      answer = null;
    }

    // answer is done.

    // If no notCached nor postFilters, we can return now.
    if (notCached == null && postFilters == null) {
      // "answer" is the only part of the filter, so set it.
      if (answer != null) {
        pf.answer = answer;
        pf.filter = answer.makeQuery();
      }
      return pf;
    }
    // pf.answer will remain null ...  (our local "answer" var is not the complete answer)

    // Set pf.filter based on combining "answer" and "notCached"
    if (notCached == null) {
      if (answer != null) {
        pf.filter = answer.makeQuery();
      }
    } else {
      notCached.sort(sortByCost); // pointless?
      final BooleanQuery.Builder builder = new BooleanQuery.Builder();
      if (answer != null) {
        builder.add(answer.makeQuery(), Occur.FILTER);
      }
      for (ExtendedQuery eq : notCached) {
        Query q = eq.getCostAppliedQuery();
        builder.add(q, Occur.FILTER);
      }
      pf.filter = builder.build();
    }

    // Set pf.postFilter
    if (postFilters != null) {
      postFilters.sort(sortByCost);
      for (int i = postFilters.size() - 1; i >= 0; i--) {
        DelegatingCollector prev = pf.postFilter;
        pf.postFilter = postFilters.get(i).getFilterCollector(this);
        if (prev != null) pf.postFilter.setDelegate(prev);
      }
    }

    return pf;
  }