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

org.apache.solr.analytics.util.RangeEndpointCalculator 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.request.RangeFacetRequest;
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.SchemaField;
import org.apache.solr.schema.TrieDateField;
import org.apache.solr.schema.TrieField;
import org.apache.solr.util.DateMathParser;


public abstract class RangeEndpointCalculator> {
  protected final SchemaField field;
  protected final RangeFacetRequest request;
  
  public RangeEndpointCalculator(final RangeFacetRequest request) {
    this.field = request.getField();
    this.request = request;
  }

  /**
   * 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;
    
    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;
    }
  }
  
  public List getRanges(){

    final T start = getValue(request.getStart());
    T end = getValue(request.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 String[] gaps = request.getGaps();
    String gap = gaps[0];
    
    final EnumSet include = request.getInclude();
        
    T low = start;
    
    List ranges = new ArrayList<>();
    
    int gapCounter = 0;
    
    while (low.compareTo(end) < 0) {
      if (gapCounter> create(RangeFacetRequest request){
    final SchemaField sf = request.getField();
    final FieldType ft = sf.getType();
    final RangeEndpointCalculator calc;
    if (ft instanceof TrieField) {
      switch (ft.getNumberType()) {
        case FLOAT:
          calc = new FloatRangeEndpointCalculator(request);
          break;
        case DOUBLE:
          calc = new DoubleRangeEndpointCalculator(request);
          break;
        case INTEGER:
          calc = new IntegerRangeEndpointCalculator(request);
          break;
        case LONG:
          calc = new LongRangeEndpointCalculator(request);
          break;
        case DATE:
          calc = new DateRangeEndpointCalculator(request, null);
          break;
        default:
          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on tried field of unexpected type:" + sf.getName());
      }
    } else {
      throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on field:" + sf);
    } 
    return calc;
  }
  
  public static class FloatRangeEndpointCalculator extends RangeEndpointCalculator {
  
    public FloatRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
    
    @Override
    protected Float parseVal(String rawval) {
      return Float.valueOf(rawval);
    }
    
    @Override
    public Float parseAndAddGap(Float value, String gap) {
      return new Float(value.floatValue() + Float.parseFloat(gap));
    }
    
  }
  
  public static class DoubleRangeEndpointCalculator extends RangeEndpointCalculator {
  
    public DoubleRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
    
    @Override
    protected Double parseVal(String rawval) {
      return Double.valueOf(rawval);
    }
    
    @Override
    public Double parseAndAddGap(Double value, String gap) {
      return new Double(value.doubleValue() + Double.parseDouble(gap));
    }
    
  }
  
  public static class IntegerRangeEndpointCalculator extends RangeEndpointCalculator {
  
    public IntegerRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
    
    @Override
    protected Integer parseVal(String rawval) {
      return Integer.valueOf(rawval);
    }
    
    @Override
    public Integer parseAndAddGap(Integer value, String gap) {
      return new Integer(value.intValue() + Integer.parseInt(gap));
    }
    
  }
  
  public static class LongRangeEndpointCalculator extends RangeEndpointCalculator {
  
    public LongRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
    
    @Override
    protected Long parseVal(String rawval) {
      return Long.valueOf(rawval);
    }
    
    @Override
    public Long parseAndAddGap(Long value, String gap) {
      return new Long(value.longValue() + Long.parseLong(gap));
    }
    
  }
  
  public static class DateRangeEndpointCalculator extends RangeEndpointCalculator {
    private final Date now;
    public DateRangeEndpointCalculator(final RangeFacetRequest request, final Date now) { 
      super(request); 
      this.now = now;
      if (! (field.getType() instanceof TrieDateField) ) {
        throw new IllegalArgumentException("SchemaField must use field type extending TrieDateField");
      }
    }
    
    @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