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

org.apache.solr.analytics.expression.ExpressionFactory 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.expression;

import java.util.ArrayList;
import java.util.List;

import org.apache.solr.analytics.statistics.StatsCollector;
import org.apache.solr.analytics.util.AnalyticsParams;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.util.DateMathParser;

public class ExpressionFactory {

  /**
   * Creates a single expression that contains delegate expressions and/or 
   * a StatsCollector.
   * StatsCollectors are given as input and not created within the method so that
   * expressions can share the same StatsCollectors, minimizing computation.
   * 
   * @param expression String representation of the desired expression
   * @param statsCollectors List of StatsCollectors to build the expression with. 
   * @return the expression
   */
  @SuppressWarnings("deprecation")
  public static Expression create(String expression, StatsCollector[] statsCollectors) {
    int paren = expression.indexOf('(');
    if (paren<=0) {
      throw new SolrException(ErrorCode.BAD_REQUEST, "The expression ["+expression+"] has no arguments and is not supported.");
    }
    String topOperation = expression.substring(0,paren).trim();
    String operands;
    try {
      operands = expression.substring(paren+1, expression.lastIndexOf(')')).trim();
    } catch (Exception e) {
      throw new SolrException(ErrorCode.BAD_REQUEST,"Missing closing parenthesis in ["+expression+"]",e);
    }
    
    // Builds a statistic, constant or recursively builds an expression tree
    
    // Statistic 
    if (AnalyticsParams.ALL_STAT_SET.contains(topOperation)) {
      if (topOperation.equals(AnalyticsParams.STAT_PERCENTILE)) {
        operands = expression.substring(expression.indexOf(',')+1, expression.lastIndexOf(')')).trim();
        topOperation = topOperation+"_"+expression.substring(expression.indexOf('(')+1, expression.indexOf(',')).trim();
      }
      StatsCollector collector = null;
      // Finds the desired counter and builds an expression around it and the desired statistic.
      for (StatsCollector c : statsCollectors) {
        if (c.valueSourceString().equals(operands)) { 
          collector = c;
          break;
        }
      }
      if (collector == null) {
        throw new SolrException(ErrorCode.BAD_REQUEST, "ValueSource ["+operands+"] in Expression ["+expression+"] not found.");
      }
      return new BaseExpression(collector, topOperation);
    }
    // Constant
    if (topOperation.equals(AnalyticsParams.CONSTANT_NUMBER)) {
      try {
        return new ConstantNumberExpression(Double.parseDouble(operands));
      } catch (NumberFormatException e) {
        throw new SolrException(ErrorCode.BAD_REQUEST, "The constant "+operands+" cannot be converted into a number.",e);
      }
    } else if (topOperation.equals(AnalyticsParams.CONSTANT_DATE)) {
      return new ConstantDateExpression(DateMathParser.parseMath(null, operands));
    } else if (topOperation.equals(AnalyticsParams.CONSTANT_STRING)) {
      operands = expression.substring(paren+1, expression.lastIndexOf(')'));
      return new ConstantStringExpression(operands);
    }
    
    // Complex Delegating Expressions
    String[] arguments = getArguments(operands);
    Expression[] expArgs = new Expression[arguments.length];
    for (int count = 0; count < arguments.length; count++) {
      // Recursively builds delegate expressions
      expArgs[count] = create(arguments[count], statsCollectors);
    }
    
    // Single Delegate Expressions
    if (expArgs.length==1) {
      // Numeric Expression
      if (topOperation.equals(AnalyticsParams.NEGATE)) {
        return new NegateExpression(expArgs[0]);
      }
      if (topOperation.equals(AnalyticsParams.ABSOLUTE_VALUE)) {
        return new AbsoluteValueExpression(expArgs[0]);
      }
      // String Expression
      else if (topOperation.equals(AnalyticsParams.REVERSE)) {
        return new ReverseExpression(expArgs[0]);
      }
      throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments.");
    }  else {
      // Multi Delegate Expressions
      // Numeric Expression
      if (topOperation.equals(AnalyticsParams.ADD)) {
        return new AddExpression(expArgs);
      } else if (topOperation.equals(AnalyticsParams.MULTIPLY)) {
        return new MultiplyExpression(expArgs);
      }
      // Date Expression
      else if (topOperation.equals(AnalyticsParams.DATE_MATH)) {
        return new DateMathExpression(expArgs);
      } 
      // String Expression
      else if (topOperation.equals(AnalyticsParams.CONCATENATE)) {
        return new ConcatenateExpression(expArgs);
      } 
      // Dual Delegate Expressions
      else if (expArgs.length==2 && (topOperation.equals(AnalyticsParams.DIVIDE) || topOperation.equals(AnalyticsParams.POWER) 
          || topOperation.equals(AnalyticsParams.LOG))) {
        // Numeric Expression
        if (topOperation.equals(AnalyticsParams.DIVIDE)) {
          return new DivideExpression(expArgs[0], expArgs[1]);
        } else if (topOperation.equals(AnalyticsParams.POWER)) {
          return new PowerExpression(expArgs[0], expArgs[1]);
        } else if (topOperation.equals(AnalyticsParams.LOG)) {
          return new LogExpression(expArgs[0], expArgs[1]);
        }
        return null;
      }
      throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments or is unsupported.");
    }
    
  }
  
  /**
   * Splits up an Expression's arguments.
   * 
   * @param expression Current expression string
   * @return List The list of arguments
   */
  public static String[] getArguments(String expression) {
    String[] strings = new String[1];
    int stack = 0;
    int start = 0;
    List arguments = new ArrayList<>();
    char[] chars = expression.toCharArray();
    for (int count = 0; count < expression.length(); count++) {
      char c = chars[count];
      if (c==',' && stack == 0) {
        arguments.add(expression.substring(start, count).replace("\\(","(").replace("\\)",")").replace("\\,",",").trim());
        start = count+1;
      } else if (c == '(') {
        stack ++;
      } else if (c == ')') {
        stack --;
      } else if (c == '\\') {
        ; // Do nothing.
      }
    }
    if (stack==0) {
      arguments.add(expression.substring(start).trim());
    }
    return arguments.toArray(strings);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy