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

org.apache.solr.search.facet.FacetBucket 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 java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.solr.common.util.SimpleOrderedMap;

public class FacetBucket {
  @SuppressWarnings("rawtypes")
  final FacetModule.FacetBucketMerger parent;
  @SuppressWarnings({"rawtypes"})
  final Comparable bucketValue;
  final int bucketNumber;  // this is just for internal correlation (the first bucket created is bucket 0, the next bucket 1, across all field buckets)

  long count;
  Map subs;

  public FacetBucket(@SuppressWarnings("rawtypes") FacetModule.FacetBucketMerger parent
      , @SuppressWarnings("rawtypes") Comparable bucketValue, FacetMerger.Context mcontext) {
    this.parent = parent;
    this.bucketValue = bucketValue;
    this.bucketNumber = mcontext.getNewBucketNumber(); // TODO: we don't need bucket numbers for all buckets...
  }

  public long getCount() {
    return count;
  }

  /** returns the existing merger for the given key, or null if none yet exists */
  FacetMerger getExistingMerger(String key) {
    if (subs == null) return null;
    return subs.get(key);
  }

  private FacetMerger getMerger(String key, Object prototype) {
    FacetMerger merger = null;
    if (subs != null) {
      merger = subs.get(key);
      if (merger != null) return merger;
    }

    merger = parent.createFacetMerger(key, prototype);

    if (merger != null) {
      if (subs == null) {
        subs = new HashMap<>();
      }
      subs.put(key, merger);
    }

    return merger;
  }

  public void mergeBucket(@SuppressWarnings("rawtypes") SimpleOrderedMap bucket, FacetMerger.Context mcontext) {
    // todo: for refinements, we want to recurse, but not re-do stats for intermediate buckets

    mcontext.setShardFlag(bucketNumber);

    // drive merging off the received bucket?
    for (int i=0; i mergerEntry : subs.entrySet()) {
        FacetMerger subMerger = mergerEntry.getValue();
        Object mergedResult = subMerger.getMergedResult();
        if (null != mergedResult) {
          out.add(mergerEntry.getKey(), mergedResult);
        }
      }
    }

    return out;
  }

  public Map getRefinement(FacetMerger.Context mcontext, Collection refineTags) {
    if (subs == null) {
      return null;
    }
    Map refinement = null;
    for (String tag : refineTags) {
      FacetMerger subMerger = subs.get(tag);
      if (subMerger != null) {
        Map subRef = subMerger.getRefinement(mcontext);
        if (subRef != null) {
          if (refinement == null) {
            refinement = new HashMap<>(refineTags.size());
          }
          refinement.put(tag, subRef);
        }
      }
    }
    return refinement;
  }

  public Map getRefinement2(FacetMerger.Context mcontext, Collection refineTags) {
    // TODO - partial results should turn off refining!!!

    boolean parentMissing = mcontext.bucketWasMissing();

    // TODO: this is a redundant check for many types of facets... only do on field faceting
    if (!parentMissing) {
      // if parent bucket wasn't missing, check if this bucket was.
      // this really only needs checking on certain buckets... (like terms facet)
      boolean sawThisBucket = mcontext.getShardFlag(bucketNumber);
      if (!sawThisBucket) {
        mcontext.setBucketWasMissing(true);
      }
    } else {
      // if parent bucket was missing, then we should be too
      assert !mcontext.getShardFlag(bucketNumber);
    }

    Map refinement = null;

    if (!mcontext.bucketWasMissing()) {
      // this is just a pass-through bucket... see if there is anything to do at all
      if (subs == null || refineTags.isEmpty()) {
        return null;
      }
    } else {
      // for missing bucket, go over all sub-facts
      refineTags = null;
      refinement = new HashMap<>(4);
      if (bucketValue != null) {
        refinement.put("_v", bucketValue);
      }
      refinement.put("_m",1);
    }

    // TODO: listing things like sub-facets that have no field facets are redundant
    // (we only need facet that have variable values)

    for (Map.Entry sub : subs.entrySet()) {
      if (refineTags != null && !refineTags.contains(sub.getKey())) {
        continue;
      }
      Map subRef = sub.getValue().getRefinement(mcontext);
      if (subRef != null) {
        if (refinement == null) {
          refinement = new HashMap<>(4);
        }
        refinement.put(sub.getKey(), subRef);
      }
    }


    // reset the "bucketMissing" flag on the way back out.
    mcontext.setBucketWasMissing(parentMissing);
    return refinement;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy