/**
   * A recursive method for generating <code>NamedLists</code> from this field suitable for
   * including in a pivot facet response to the original distributed request.
   */
  public List<NamedList<Object>> convertToListOfNamedLists() {

    List<NamedList<Object>> convertedPivotList = null;

    if (valueCollection.size() > 0) {
      convertedPivotList = new LinkedList<>();
      for (PivotFacetValue pivot : valueCollection)
        convertedPivotList.add(pivot.convertToNamedList());
    }

    return convertedPivotList;
  }
  /**
   * A recursive method to construct a new <code>PivotFacetField</code> object from the contents of
   * the {@link NamedList}s provided by the specified shard, relative to a parent value (if this is
   * not the top field in the pivot hierarchy)
   *
   * <p>The associated child {@link PivotFacetValue}s will be recursively built as well.
   *
   * @see PivotFacetValue#createFromNamedList
   * @param shardNumber the id of the shard that provided this data
   * @param rb The response builder of the current request
   * @param owner the parent value in the current pivot (may be null)
   * @param pivotValues the data from the specified shard for this pivot field, may be null or empty
   * @return the new PivotFacetField, null if pivotValues is null or empty.
   */
  public static PivotFacetField createFromListOfNamedLists(
      int shardNumber,
      ResponseBuilder rb,
      PivotFacetValue owner,
      List<NamedList<Object>> pivotValues) {

    if (null == pivotValues || pivotValues.size() <= 0) return null;

    NamedList<Object> firstValue = pivotValues.get(0);
    PivotFacetField createdPivotFacetField =
        new PivotFacetField(rb, owner, PivotFacetHelper.getField(firstValue));

    int lowestCount = Integer.MAX_VALUE;

    for (NamedList<Object> pivotValue : pivotValues) {

      lowestCount = Math.min(lowestCount, PivotFacetHelper.getCount(pivotValue));

      PivotFacetValue newValue =
          PivotFacetValue.createFromNamedList(shardNumber, rb, createdPivotFacetField, pivotValue);
      createdPivotFacetField.valueCollection.add(newValue);
    }

    createdPivotFacetField.shardLowestCount.put(shardNumber, lowestCount);
    createdPivotFacetField.numberOfValuesContributedByShard.put(shardNumber, pivotValues.size());

    return createdPivotFacetField;
  }
  /**
   * Checks the {@link #lowestCountContributedbyShard} for each shard, combined with the counts we
   * already know, to see if this value is a viable candidate -- <b>Does not make sense when using
   * {@link FacetParams#FACET_SORT_INDEX}</b>
   *
   * @see #processDefiniteCandidateElement
   */
  private void processPossibleCandidateElement(
      PivotFacet pf, PivotFacetValue value, final int refinementThreshold) {

    assert FacetParams.FACET_SORT_COUNT.equals(facetFieldSort)
        : "Method only makes sense when sorting by count";

    int maxPossibleCountAfterRefinement = value.getCount();

    for (int shard = pf.knownShards.nextSetBit(0);
        0 <= shard;
        shard = pf.knownShards.nextSetBit(shard + 1)) {
      if (!value.shardHasContributed(shard)) {
        maxPossibleCountAfterRefinement += lowestCountContributedbyShard(shard);
      }
    }

    if (refinementThreshold <= maxPossibleCountAfterRefinement) {
      processDefiniteCandidateElement(pf, value);
    }
  }
  private void contributeValueFromShard(
      int shardNumber, ResponseBuilder rb, NamedList<Object> shardValue) {

    incrementShardValueCount(shardNumber);

    Comparable value = PivotFacetHelper.getValue(shardValue);
    int count = PivotFacetHelper.getCount(shardValue);

    // We're changing values so we most mark the collection as dirty
    valueCollection.markDirty();

    if ((!shardLowestCount.containsKey(shardNumber)) || shardLowestCount.get(shardNumber) > count) {
      shardLowestCount.put(shardNumber, count);
    }

    PivotFacetValue facetValue = valueCollection.get(value);
    if (null == facetValue) {
      // never seen before, we need to create it from scratch
      facetValue = PivotFacetValue.createFromNamedList(shardNumber, rb, this, shardValue);
      this.valueCollection.add(facetValue);
    } else {
      facetValue.mergeContributionFromShard(shardNumber, rb, shardValue);
    }
  }
  /**
   * Adds refinement requests for the value for each shard that has not already contributed a count
   * for this value.
   */
  private void processDefiniteCandidateElement(PivotFacet pf, PivotFacetValue value) {

    for (int shard = pf.knownShards.nextSetBit(0);
        0 <= shard;
        shard = pf.knownShards.nextSetBit(shard + 1)) {
      if (!value.shardHasContributed(shard)) {
        if ( // if we're doing index order, we need to refine anything
        // (mincount may have excluded from a shard)
        FacetParams.FACET_SORT_INDEX.equals(facetFieldSort)
            // if we are doing count order, we need to refine if the limit was hit
            // (if not, the shard doesn't have the value or it would have returned already)
            || numberOfValuesContributedByShardWasLimitedByFacetFieldLimit(shard)) {

          pf.addRefinement(shard, value);
        }
      }
    }
  }
  private void refineNextLevelOfFacets(PivotFacet pf) {

    List<PivotFacetValue> explicitValsToRefine = valueCollection.getNextLevelValuesToRefine();

    for (PivotFacetValue value : explicitValsToRefine) {
      if (null != value.getChildPivot()) {
        value.getChildPivot().queuePivotRefinementRequests(pf);
      }
    }

    PivotFacetValue missing = this.valueCollection.getMissingValue();
    if (null != missing && null != missing.getChildPivot()) {
      missing.getChildPivot().queuePivotRefinementRequests(pf);
    }
  }
 /**
  * A recursive method that walks up the tree of pivot fields/values to build a list of String
  * representations of the values that lead down to this PivotFacetField.
  *
  * @return A mutable List of the pivot values leading down to this pivot field, will never be null
  *     but may contain nulls and may be empty if this is a top level pivot field
  * @see PivotFacetValue#getValuePath
  */
 public List<String> getValuePath() {
   if (null != parentValue) {
     return parentValue.getValuePath();
   }
   return new ArrayList<String>(3);
 }
Beispiel #8
0
  /**
   * A recursive method to construct a new <code>PivotFacetValue</code> object from the contents of
   * the {@link NamedList} provided by the specified shard, relative to the specified field.
   *
   * <p>If the <code>NamedList</code> contains data for a child {@link PivotFacetField} that will be
   * recursively built as well.
   *
   * @see PivotFacetField#createFromListOfNamedLists
   * @param shardNumber the id of the shard that provided this data
   * @param rb The response builder of the current request
   * @param parentField the parent field in the current pivot associated with this value
   * @param pivotData the data from the specified shard for this pivot value
   */
  @SuppressWarnings("unchecked")
  public static PivotFacetValue createFromNamedList(
      int shardNumber,
      ResponseBuilder rb,
      PivotFacetField parentField,
      NamedList<Object> pivotData) {

    Comparable pivotVal = null;
    int pivotCount = 0;
    List<NamedList<Object>> childPivotData = null;
    NamedList<NamedList<NamedList<?>>> statsValues = null;
    NamedList<Number> queryCounts = null;
    SimpleOrderedMap<SimpleOrderedMap<Object>> ranges = null;

    for (int i = 0; i < pivotData.size(); i++) {
      String key = pivotData.getName(i);
      Object value = pivotData.getVal(i);
      PivotListEntry entry = PivotListEntry.get(key);

      switch (entry) {
        case VALUE:
          pivotVal = (Comparable) value;
          break;
        case FIELD:
          assert parentField.field.equals(value)
              : "Parent Field mismatch: " + parentField.field + "!=" + value;
          break;
        case COUNT:
          pivotCount = (Integer) value;
          break;
        case PIVOT:
          childPivotData = (List<NamedList<Object>>) value;
          break;
        case STATS:
          statsValues = (NamedList<NamedList<NamedList<?>>>) value;
          break;
        case QUERIES:
          queryCounts = (NamedList<Number>) value;
          break;
        case RANGES:
          ranges = (SimpleOrderedMap<SimpleOrderedMap<Object>>) value;
          break;
        default:
          throw new RuntimeException("PivotListEntry contains unaccounted for item: " + entry);
      }
    }

    PivotFacetValue newPivotFacet = new PivotFacetValue(parentField, pivotVal);
    newPivotFacet.count = pivotCount;
    newPivotFacet.sourceShards.set(shardNumber);
    if (statsValues != null) {
      newPivotFacet.statsValues = PivotFacetHelper.mergeStats(null, statsValues, rb._statsInfo);
    }
    if (queryCounts != null) {
      newPivotFacet.queryCounts = PivotFacetHelper.mergeQueryCounts(null, queryCounts);
    }
    if (ranges != null) {
      newPivotFacet.rangeCounts = new LinkedHashMap<>();
      RangeFacetRequest.DistribRangeFacet.mergeFacetRangesFromShardResponse(
          newPivotFacet.rangeCounts, ranges);
    }

    newPivotFacet.childPivot =
        PivotFacetField.createFromListOfNamedLists(shardNumber, rb, newPivotFacet, childPivotData);

    return newPivotFacet;
  }