All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.search.facet.FacetFieldProcessorByArray Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.solr.search.facet;

import static org.apache.solr.search.facet.FacetContext.SKIP_FACET;

import java.io.IOException;
import java.util.Date;
import java.util.function.IntFunction;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.facet.SlotAcc.SlotContext;
import org.apache.solr.search.facet.SlotAcc.SweepingCountSlotAcc;

/**
 * Base class for DV/UIF accumulating counts into an array by ordinal. It's for {@link
 * org.apache.lucene.index.SortedDocValues} and {@link org.apache.lucene.index.SortedSetDocValues}
 * only. It can handle terms (strings), not numbers directly but those encoded as terms, and is
 * multi-valued capable. By default, this class assumes subclasses can support sweeping collection
 * unless subclasses initialize countAcc directly in their constructors.
 *
 * @see SweepingCountSlotAcc
 */
abstract class FacetFieldProcessorByArray extends FacetFieldProcessor {
  BytesRefBuilder prefixRef;
  int startTermIndex;
  int endTermIndex;
  int nTerms;
  int nDocs;
  int maxSlots;

  int allBucketsSlot = -1; // slot for the primary Accs (countAcc, collectAcc)

  FacetFieldProcessorByArray(FacetContext fcontext, FacetField freq, SchemaField sf) {
    super(fcontext, freq, sf);
  }

  protected abstract void findStartAndEndOrds() throws IOException;

  protected abstract void collectDocs() throws IOException;

  /** this BytesRef may be shared across calls and should be deep-cloned if necessary */
  protected abstract BytesRef lookupOrd(int ord) throws IOException;

  /**
   * {@inheritDoc}
   *
   * 

This impl first initializes countAcc as a {@link SweepingCountSlotAcc} if null. */ @Override protected void createAccs(long docCount, int slotCount) throws IOException { if (countAcc == null) { countAcc = new SweepingCountSlotAcc(slotCount, this); } super.createAccs(docCount, slotCount); } /** * {@inheritDoc} * *

This impl first initializes countAcc as a {@link SweepingCountSlotAcc} if null. */ @Override void createCollectAcc(int numDocs, int numSlots) throws IOException { if (countAcc == null) { countAcc = new SweepingCountSlotAcc(numSlots, this); } super.createCollectAcc(numDocs, numSlots); registerSweepingAccIfSupportedByCollectAcc(); } @Override public void process() throws IOException { super.process(); response = calcFacets(); } private SimpleOrderedMap calcFacets() throws IOException { SimpleOrderedMap refineResult = null; boolean skipThisFacet = (fcontext.flags & SKIP_FACET) != 0; if (fcontext.facetInfo != null) { refineResult = refineFacets(); // if we've seen this facet bucket, then refining can be done. If we haven't, we still // only need to continue if we need allBuckets or numBuckets info. if (skipThisFacet || !freq.allBuckets) return refineResult; } String prefix = freq.prefix; if (prefix == null || prefix.length() == 0) { prefixRef = null; } else { prefixRef = new BytesRefBuilder(); prefixRef.copyChars(prefix); } findStartAndEndOrds(); if (refineResult != null) { if (freq.allBuckets) { // count is irrelevant, but hardcoded in collect(...), so intercept/mask normal counts. // Set here to prevent createAccs(...) from creating a 1-slot countAcc that will fail with // AIOOBE // NOTE: because collectAcc will be null, it is fine/irrelevant to set a countAcc that // doesn't support sweeping countAcc = Constants.DEV_NULL_SLOT_ACC; createAccs(nDocs, 1); assert collectAcc == null; // accs is created above and set on allBucketsAcc; but during collection, setNextReader is // called on otherAccs. otherAccs = accs; allBucketsAcc = new SpecialSlotAcc(fcontext, null, -1, accs, 0); collectDocs(); SimpleOrderedMap allBuckets = new SimpleOrderedMap<>(); allBuckets.add("count", allBucketsAcc.getSpecialCount()); allBucketsAcc.setValues(allBuckets, -1); // -1 slotNum is unused for SpecialSlotAcc refineResult.add("allBuckets", allBuckets); return refineResult; } } maxSlots = nTerms; if (freq.allBuckets) { allBucketsSlot = maxSlots++; } createCollectAcc(nDocs, maxSlots); if (freq.allBuckets) { allBucketsAcc = new SpecialSlotAcc(fcontext, collectAcc, allBucketsSlot, otherAccs, 0); } collectDocs(); return super.findTopSlots( nTerms, nTerms, slotNum -> { // getBucketValFromSlotNum try { return (Comparable) sf.getType().toObject(sf, lookupOrd(slotNum + startTermIndex)); } catch (IOException e) { throw new RuntimeException(e); } }, obj -> valueObjToString(obj)); } private static String valueObjToString(Object obj) { return (obj instanceof Date) ? ((Date) obj).toInstant().toString() : obj.toString(); } /** * SlotContext to use during all {@link SlotAcc} collection. * * @see #lookupOrd */ public IntFunction slotContext = (slotNum) -> { try { Object value = sf.getType().toObject(sf, lookupOrd(slotNum + startTermIndex)); Query q = makeBucketQuery(valueObjToString(value)); assert null != q : "null query for: '" + value + "'"; return new SlotContext(q); } catch (IOException e) { throw new RuntimeException(e); } }; }