private NamedList getTermCounts()

in solr/core/src/java/org/apache/solr/request/SimpleFacets.java [437:674]


  private NamedList<Integer> getTermCounts(String field, Integer mincount, ParsedParams parsed)
      throws IOException {
    final SolrParams params = parsed.params;
    final DocSet docs = parsed.docs;
    final int threads = parsed.threads;
    int offset = params.getFieldInt(field, FacetParams.FACET_OFFSET, 0);
    int limit = params.getFieldInt(field, FacetParams.FACET_LIMIT, 100);
    boolean missing = params.getFieldBool(field, FacetParams.FACET_MISSING, false);

    // when limit=0 and missing=false then return empty list
    if (limit == 0 && !missing) return new NamedList<>();

    if (mincount == null) {
      Boolean zeros = params.getFieldBool(field, FacetParams.FACET_ZEROS);
      // mincount = (zeros!=null && zeros) ? 0 : 1;
      mincount = (zeros != null && !zeros) ? 1 : 0;
      // current default is to include zeros.
    }

    // default to sorting if there is a limit.
    String sort =
        params.getFieldParam(
            field,
            FacetParams.FACET_SORT,
            limit > 0 ? FacetParams.FACET_SORT_COUNT : FacetParams.FACET_SORT_INDEX);
    String prefix = params.getFieldParam(field, FacetParams.FACET_PREFIX);

    final Predicate<BytesRef> termFilter = newBytesRefFilter(field, params);

    boolean exists = params.getFieldBool(field, FacetParams.FACET_EXISTS, false);

    NamedList<Integer> counts;
    SchemaField sf = searcher.getSchema().getField(field);
    if (sf.getType().isPointField() && !sf.hasDocValues()) {
      throw new SolrException(
          SolrException.ErrorCode.BAD_REQUEST, "Can't facet on a PointField without docValues");
    }
    FieldType ft = sf.getType();

    // determine what type of faceting method to use
    final String methodStr = params.getFieldParam(field, FacetParams.FACET_METHOD);
    final FacetMethod requestedMethod;
    if (FacetParams.FACET_METHOD_enum.equals(methodStr)) {
      requestedMethod = FacetMethod.ENUM;
    } else if (FacetParams.FACET_METHOD_fcs.equals(methodStr)) {
      requestedMethod = FacetMethod.FCS;
    } else if (FacetParams.FACET_METHOD_fc.equals(methodStr)) {
      requestedMethod = FacetMethod.FC;
    } else if (FacetParams.FACET_METHOD_uif.equals(methodStr)) {
      requestedMethod = FacetMethod.UIF;
    } else {
      requestedMethod = null;
    }

    final boolean multiToken = sf.multiValued() || ft.multiValuedFieldCache();

    FacetMethod appliedFacetMethod =
        selectFacetMethod(field, sf, requestedMethod, mincount, exists);

    RTimer timer = null;
    if (fdebug != null) {
      fdebug.putInfoItem(
          "requestedMethod", requestedMethod == null ? "not specified" : requestedMethod.name());
      fdebug.putInfoItem("appliedMethod", appliedFacetMethod.name());
      fdebug.putInfoItem("inputDocSetSize", docs.size());
      fdebug.putInfoItem("field", field);
      timer = new RTimer();
    }

    if (params.getFieldBool(field, GroupParams.GROUP_FACET, false)) {
      counts =
          getGroupedCounts(
              searcher,
              docs,
              field,
              multiToken,
              offset,
              limit,
              mincount,
              missing,
              sort,
              prefix,
              termFilter);
    } else {
      assert appliedFacetMethod != null;
      switch (appliedFacetMethod) {
        case ENUM:
          assert TrieField.getMainValuePrefix(ft) == null;
          counts =
              getFacetTermEnumCounts(
                  searcher,
                  docs,
                  field,
                  offset,
                  limit,
                  mincount,
                  missing,
                  sort,
                  prefix,
                  termFilter,
                  exists);
          break;
        case FCS:
          assert ft.isPointField() || !multiToken;
          if (ft.isPointField() || (ft.getNumberType() != null && !sf.multiValued())) {
            if (prefix != null) {
              throw new SolrException(
                  ErrorCode.BAD_REQUEST,
                  FacetParams.FACET_PREFIX + " is not supported on numeric types");
            }
            if (termFilter != null) {
              throw new SolrException(
                  ErrorCode.BAD_REQUEST,
                  "BytesRef term filters ("
                      + FacetParams.FACET_MATCHES
                      + ", "
                      + FacetParams.FACET_CONTAINS
                      + ", "
                      + FacetParams.FACET_EXCLUDETERMS
                      + ") are not supported on numeric types");
            }
            if (ft.isPointField()
                && mincount <= 0) { // default is mincount=0.  See SOLR-10033 & SOLR-11174.
              String warningMessage =
                  "Raising facet.mincount from "
                      + mincount
                      + " to 1, because field "
                      + field
                      + " is Points-based.";
              log.warn(warningMessage);
              @SuppressWarnings({"unchecked"})
              List<String> warnings = (List<String>) rb.rsp.getResponseHeader().get("warnings");
              if (null == warnings) {
                warnings = new ArrayList<>();
                rb.rsp.getResponseHeader().add("warnings", warnings);
              }
              warnings.add(warningMessage);

              mincount = 1;
            }
            counts =
                NumericFacets.getCounts(
                    searcher, docs, field, offset, limit, mincount, missing, sort);
          } else {
            PerSegmentSingleValuedFaceting ps =
                new PerSegmentSingleValuedFaceting(
                    searcher,
                    docs,
                    field,
                    offset,
                    limit,
                    mincount,
                    missing,
                    sort,
                    prefix,
                    termFilter);
            Executor executor = threads == 0 ? directExecutor : facetExecutor;
            ps.setNumThreads(threads);
            counts = ps.getFacetCounts(executor);
          }
          break;
        case UIF:
          // Emulate the JSON Faceting structure so we can use the same parsing classes
          Map<String, Object> jsonFacet = CollectionUtil.newHashMap(13);
          jsonFacet.put("type", "terms");
          jsonFacet.put("field", field);
          jsonFacet.put("offset", offset);
          jsonFacet.put("limit", limit);
          jsonFacet.put("mincount", mincount);
          jsonFacet.put("missing", missing);
          jsonFacet.put("prefix", prefix);
          jsonFacet.put("numBuckets", params.getFieldBool(field, "numBuckets", false));
          jsonFacet.put("allBuckets", params.getFieldBool(field, "allBuckets", false));
          jsonFacet.put("method", "uif");
          jsonFacet.put("cacheDf", 0);
          jsonFacet.put("perSeg", false);

          final String sortVal;
          switch (sort) {
            case FacetParams.FACET_SORT_COUNT_LEGACY:
              sortVal = FacetParams.FACET_SORT_COUNT;
              break;
            case FacetParams.FACET_SORT_INDEX_LEGACY:
              sortVal = FacetParams.FACET_SORT_INDEX;
              break;
            default:
              sortVal = sort;
          }
          jsonFacet.put(SORT, sortVal);

          // TODO do we handle debug?  Should probably already be handled by the legacy code

          Object resObj = FacetRequest.parseOneFacetReq(req, jsonFacet).process(req, docs);
          // Go through the response to build the expected output for SimpleFacets
          counts = new NamedList<>();
          if (resObj != null) {
            @SuppressWarnings({"unchecked"})
            NamedList<Object> res = (NamedList<Object>) resObj;

            @SuppressWarnings({"unchecked"})
            List<NamedList<Object>> buckets = (List<NamedList<Object>>) res.get("buckets");
            for (NamedList<Object> b : buckets) {
              counts.add(b.get("val").toString(), ((Number) b.get("count")).intValue());
            }
            if (missing) {
              @SuppressWarnings({"unchecked"})
              NamedList<Object> missingCounts = (NamedList<Object>) res.get("missing");
              counts.add(null, ((Number) missingCounts.get("count")).intValue());
            }
          }
          break;
        case FC:
          counts =
              DocValuesFacets.getCounts(
                  searcher,
                  docs,
                  field,
                  offset,
                  limit,
                  mincount,
                  missing,
                  sort,
                  prefix,
                  termFilter,
                  fdebug);
          break;
        default:
          throw new AssertionError();
      }
    }

    if (fdebug != null) {
      long timeElapsed = (long) timer.getTime();
      fdebug.setElapse(timeElapsed);
    }

    return counts;
  }