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

org.apache.solr.analytics.util.FacetRangeGenerator 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.analytics.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import org.apache.solr.analytics.facet.RangeFacet;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
import org.apache.solr.common.params.FacetParams.FacetRangeOther;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.NumericFieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.util.DateMathParser;


/**
 * Calculates a set of {@link FacetRange}s for a given {@link RangeFacet}.
 */
public abstract class FacetRangeGenerator> {
  protected final SchemaField field;
  protected final RangeFacet rangeFacet;
  
  public FacetRangeGenerator(final RangeFacet rangeFacet) {
    this.field = rangeFacet.getField();
    this.rangeFacet = rangeFacet;
  }

  /**
   * Formats a Range endpoint for use as a range label name in the response.
   * Default Impl just uses toString()
   */
  public String formatValue(final T val) {
    return val.toString();
  }
  
  /**
   * Parses a String param into an Range endpoint value throwing 
   * a useful exception if not possible
   */
  public final T getValue(final String rawval) {
    try {
      return parseVal(rawval);
    } catch (Exception e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse value "+rawval+" for field: " + field.getName(), e);
    }
  }
  
  /**
   * Parses a String param into an Range endpoint. 
   * Can throw a low level format exception as needed.
   */
  protected abstract T parseVal(final String rawval) throws java.text.ParseException;

  /** 
   * Parses a String param into a value that represents the gap and 
   * can be included in the response, throwing 
   * a useful exception if not possible.
   *
   * Note: uses Object as the return type instead of T for things like 
   * Date where gap is just a DateMathParser string 
   */
  public final Object getGap(final String gap) {
    try {
      return parseGap(gap);
    } catch (Exception e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse gap "+gap+" for field: " + field.getName(), e);
    }
  }

  /**
   * Parses a String param into a value that represents the gap and 
   * can be included in the response. 
   * Can throw a low level format exception as needed.
   *
   * Default Impl calls parseVal
   */
  protected Object parseGap(final String rawval) throws java.text.ParseException {
    return parseVal(rawval);
  }

  /**
   * Adds the String gap param to a low Range endpoint value to determine 
   * the corrisponding high Range endpoint value, throwing 
   * a useful exception if not possible.
   */
  public final T addGap(T value, String gap) {
    try {
      return parseAndAddGap(value, gap);
    } catch (Exception e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't add gap "+gap+" to value " + value + " for field: " + field.getName(), e);
    }
  }
  
  /**
   * Adds the String gap param to a low Range endpoint value to determine 
   * the corrisponding high Range endpoint value.
   * Can throw a low level format exception as needed.
   */
  protected abstract T parseAndAddGap(T value, String gap) throws java.text.ParseException;

  public static class FacetRange {
    public final String name;
    public final String lower;
    public final String upper;
    public final boolean includeLower;
    public final boolean includeUpper;
    private final String facetValue;
    
    public FacetRange(String name, String lower, String upper, boolean includeLower, boolean includeUpper) {
      this.name = name;
      this.lower = lower;
      this.upper = upper;
      this.includeLower = includeLower;
      this.includeUpper = includeUpper;
      
      String value = "(*";
      if (lower != null) {
        value = (includeLower ? "[" : "(") + lower;
      }
      value += " TO ";
      if (upper == null) {
        value += "*)";
      } else {
        value += upper + (includeUpper? "]" : ")");
      }
      facetValue = value;
    }
    
    @Override
    public String toString() {
        return facetValue;
    }
  }
  
  public List getRanges(){

    final T start = getValue(rangeFacet.getStart());
    T end = getValue(rangeFacet.getEnd()); // not final, hardend may change this
    
    if( end.compareTo(start) < 0 ){
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "range facet 'end' comes before 'start': "+end+" < "+start);
    }
    
    // explicitly return the gap.  compute this early so we are more 
    // likely to catch parse errors before attempting math
    final List gaps = rangeFacet.getGaps();
    String gap = gaps.get(0);
    
    final EnumSet include = rangeFacet.getInclude();
        
    T low = start;
    
    List ranges = new ArrayList<>();
    
    int gapCounter = 0;
    
    while (low.compareTo(end) < 0) {
      if (gapCounter> create(RangeFacet rangeFacet){
    final SchemaField sf = rangeFacet.getField();
    final FieldType ft = sf.getType();
    final FacetRangeGenerator calc;
    if (ft instanceof NumericFieldType) {
      switch (ft.getNumberType()) {
        case FLOAT:
          calc = new FloatFacetRangeGenerator(rangeFacet);
          break;
        case DOUBLE:
          calc = new DoubleFacetRangeGenerator(rangeFacet);
          break;
        case INTEGER:
          calc = new IntegerFacetRangeGenerator(rangeFacet);
          break;
        case LONG:
          calc = new LongFacetRangeGenerator(rangeFacet);
          break;
        case DATE:
          calc = new DateFacetRangeGenerator(rangeFacet, null);
          break;
        default:
          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on numeric field of unexpected type: " + sf.getName());
      }
    } else {
      throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on non-numeric field: " + sf);
    } 
    return calc;
  }
}
class IntegerFacetRangeGenerator extends FacetRangeGenerator {
  public IntegerFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }

  @Override
  protected Integer parseVal(String rawval) {
    return Integer.valueOf(rawval);
  }
  @Override
  public Integer parseAndAddGap(Integer value, String gap) {
    return new Integer(value.intValue() + Integer.valueOf(gap).intValue());
  }
}
class LongFacetRangeGenerator extends FacetRangeGenerator {
  public LongFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }

  @Override
  protected Long parseVal(String rawval) {
    return Long.valueOf(rawval);
  }
  @Override
  public Long parseAndAddGap(Long value, String gap) {
    return new Long(value.longValue() + Long.valueOf(gap).longValue());
  }
}

class FloatFacetRangeGenerator extends FacetRangeGenerator {
  public FloatFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }

  @Override
  protected Float parseVal(String rawval) {
    return Float.valueOf(rawval);
  }
  @Override
  public Float parseAndAddGap(Float value, String gap) {
    return new Float(value.floatValue() + Float.valueOf(gap).floatValue());
  }
}

class DoubleFacetRangeGenerator extends FacetRangeGenerator {
  public DoubleFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }

  @Override
  protected Double parseVal(String rawval) {
    return Double.valueOf(rawval);
  }
  @Override
  public Double parseAndAddGap(Double value, String gap) {
    return new Double(value.doubleValue() + Double.valueOf(gap).doubleValue());
  }
}
class DateFacetRangeGenerator extends FacetRangeGenerator {
  private final Date now;
  public DateFacetRangeGenerator(final RangeFacet rangeFacet, final Date now) { 
    super(rangeFacet); 
    this.now = now;
  }
  
  @Override
  public String formatValue(Date val) {
    return val.toInstant().toString();
  }
  @Override
  protected Date parseVal(String rawval) {
    return DateMathParser.parseMath(now, rawval);
  }
  @Override
  protected Object parseGap(final String rawval) {
    return rawval;
  }
  @Override
  public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException {
    final DateMathParser dmp = new DateMathParser();
    dmp.setNow(value);
    return dmp.parseMath(gap);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy