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

org.apache.lens.cube.metadata.Cube Maven / Gradle / Ivy

The 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.lens.cube.metadata;

import java.lang.reflect.Constructor;
import java.util.*;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.metadata.Table;

import com.google.common.collect.Sets;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Cube extends AbstractBaseTable implements CubeInterface {
  private final Set measures;
  private final Set dimensions;
  private final Map measureMap;
  private final Map dimMap;


  public Cube(String name, Set measures, Set dimensions) {
    this(name, measures, dimensions, new HashMap());
  }

  public Cube(String name, Set measures, Set dimensions,
    Map properties) {
    this(name, measures, dimensions, properties, 0L);
  }

  public Cube(String name, Set measures, Set dimensions, Map properties,
    double weight) {
    this(name, measures, dimensions, null, null, properties, weight);
  }

  public Cube(String name, Set measures, Set dimensions, Set expressions,
    Set joinChains, Map properties, double weight) {
    super(name, expressions, joinChains, properties, weight);
    this.measures = measures;
    this.dimensions = dimensions;

    measureMap = new HashMap<>();
    for (CubeMeasure m : measures) {
      measureMap.put(m.getName().toLowerCase(), m);
    }

    dimMap = new HashMap<>();
    for (CubeDimAttribute dim : dimensions) {
      dimMap.put(dim.getName().toLowerCase(), dim);
    }

    addProperties();
  }

  public Cube(Table tbl) {
    super(tbl);
    this.measures = getMeasures(getName(), getProperties());
    this.dimensions = getDimensions(getName(), getProperties());

    measureMap = new HashMap<>();
    for (CubeMeasure m : measures) {
      measureMap.put(m.getName().toLowerCase(), m);
    }

    dimMap = new HashMap<>();
    for (CubeDimAttribute dim : dimensions) {
      addAllDimsToMap(dim);
    }
  }

  private void addAllDimsToMap(CubeDimAttribute dim) {
    dimMap.put(dim.getName().toLowerCase(), dim);
    if (dim instanceof HierarchicalDimAttribute) {
      for (CubeDimAttribute d : ((HierarchicalDimAttribute) dim).getHierarchy()) {
        addAllDimsToMap(d);
      }
    }
  }

  public Set getMeasures() {
    return measures;
  }
  public Optional getColumnStartTime(String column) {
    return Optional.ofNullable(getColumnByName(column)).map(CubeColumn::getStartTime);
  }
  public Optional getColumnEndTime(String column) {
    return Optional.ofNullable(getColumnByName(column)).map(CubeColumn::getEndTime);
  }

  public Set getDimAttributes() {
    return dimensions;
  }

  public Set getTimedDimensions() {
    String str = getProperties().get(MetastoreUtil.getCubeTimedDimensionListKey(getName()));
    Set timedDimensions = new HashSet<>();
    if (str != null) {
      timedDimensions.addAll(Arrays.asList(StringUtils.split(str, ',')));
    }
    return timedDimensions;
  }

  @Override
  public CubeTableType getTableType() {
    return CubeTableType.CUBE;
  }

  @Override
  public void addProperties() {
    super.addProperties();
    MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeMeasureListKey(getName()), measures);
    setMeasureProperties(getProperties(), measures);
    MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeDimensionListKey(getName()), dimensions);
    setDimensionProperties(getProperties(), dimensions);
  }

  private static void setMeasureProperties(Map props, Set measures) {
    for (CubeMeasure measure : measures) {
      measure.addProperties(props);
    }
  }

  private static void setDimensionProperties(Map props, Set dimensions) {
    for (CubeDimAttribute dimension : dimensions) {
      dimension.addProperties(props);
    }
  }

  public static Set getMeasures(String name, Map props) {
    Set measures = new HashSet<>();
    String measureStr = MetastoreUtil.getNamedStringValue(props, MetastoreUtil.getCubeMeasureListKey(name));
    String[] names = measureStr.split(",");
    for (String measureName : names) {
      String className = props.get(MetastoreUtil.getMeasureClassPropertyKey(measureName));
      CubeMeasure measure;
      try {
        Class clazz = Class.forName(className);
        Constructor constructor;
        constructor = clazz.getConstructor(String.class, Map.class);
        measure = (CubeMeasure) constructor.newInstance(new Object[]{measureName, props});
      } catch (Exception e) {
        throw new IllegalArgumentException("Invalid measure", e);
      }
      measures.add(measure);
    }
    return measures;
  }

  public static Set getDimensions(String name, Map props) {
    Set dimensions = new HashSet<>();
    String dimStr = MetastoreUtil.getNamedStringValue(props, MetastoreUtil.getCubeDimensionListKey(name));
    if (StringUtils.isNotBlank(dimStr)) {
      String[] names = dimStr.split(",");
      for (String dimName : names) {
        String className = props.get(MetastoreUtil.getDimensionClassPropertyKey(dimName));
        CubeDimAttribute dim;
        try {
          Class clazz = Class.forName(className);
          Constructor constructor;
          constructor = clazz.getConstructor(String.class, Map.class);
          dim = (CubeDimAttribute) constructor.newInstance(new Object[]{dimName, props});
        } catch (Exception e) {
          throw new IllegalArgumentException("Invalid dimension", e);
        }
        dimensions.add(dim);
      }
    }
    return dimensions;
  }

  @Override
  public int hashCode() {
    return super.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (!super.equals(obj)) {
      return false;
    }
    Cube other = (Cube) obj;
    if (this.getMeasures() == null) {
      if (other.getMeasures() != null) {
        return false;
      }
    } else if (!this.getMeasures().equals(other.getMeasures())) {
      return false;
    }
    if (this.getDimAttributes() == null) {
      if (other.getDimAttributes() != null) {
        return false;
      }
    } else if (!this.getDimAttributes().equals(other.getDimAttributes())) {
      return false;
    }
    return true;
  }

  public CubeDimAttribute getDimAttributeByName(String dimension) {
    return dimMap.get(dimension == null ? null : dimension.toLowerCase());
  }

  public CubeMeasure getMeasureByName(String measure) {
    return measureMap.get(measure == null ? null : measure.toLowerCase());
  }

  public CubeColumn getColumnByName(String column) {
    CubeColumn cubeCol = super.getExpressionByName(column);
    if (cubeCol == null) {
      cubeCol = getMeasureByName(column);
      if (cubeCol == null) {
        cubeCol = getDimAttributeByName(column);
      }
    }
    return cubeCol;
  }

  /**
   * Alters the measure if already existing or just adds if it is new measure.
   *
   * @param measure new measure definition
   */
  public void alterMeasure(@NonNull CubeMeasure measure) {
    // Replace measure if already existing
    if (measureMap.containsKey(measure.getName().toLowerCase())) {
      measures.remove(getMeasureByName(measure.getName()));
      log.info("Replacing measure {} with {}", getMeasureByName(measure.getName()), measure);
    }

    measures.add(measure);
    measureMap.put(measure.getName().toLowerCase(), measure);
    MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeMeasureListKey(getName()), measures);
    measure.addProperties(getProperties());
  }

  /**
   * Remove the joinchain with name specified
   *
   * @param chainName chain name
   */
  public boolean removeJoinChain(@NonNull String chainName) {
    if (super.removeJoinChain(chainName)) {
      log.info("Removing dimension {}", getDimAttributeByName(chainName));
      return true;
    }
    return false;
  }

  /**
   * Alters the dimension if already existing or just adds if it is new dimension
   *
   * @param dimension the dim attribute
   */
  public void alterDimension(@NonNull CubeDimAttribute dimension) {
    // Replace dimension if already existing
    if (dimMap.containsKey(dimension.getName().toLowerCase())) {
      dimensions.remove(getDimAttributeByName(dimension.getName()));
      log.info("Replacing dimension {} with {}", getDimAttributeByName(dimension.getName()), dimension);
    }

    dimensions.add(dimension);
    dimMap.put(dimension.getName().toLowerCase(), dimension);
    MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeDimensionListKey(getName()), dimensions);
    dimension.addProperties(getProperties());
  }


  /**
   * Remove the attribute with name specified
   *
   * @param dimName attribute name
   */
  public void removeDimension(@NonNull String dimName) {
    if (dimMap.containsKey(dimName.toLowerCase())) {
      log.info("Removing dimension {}", getDimAttributeByName(dimName));
      dimensions.remove(getDimAttributeByName(dimName));
      dimMap.remove(dimName.toLowerCase());
      MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeDimensionListKey(getName()), dimensions);
    }
  }

  /**
   * Remove the measure with name specified
   *
   * @param msrName measure name
   */
  public void removeMeasure(@NonNull String msrName) {
    if (measureMap.containsKey(msrName.toLowerCase())) {
      log.info("Removing measure {}", getMeasureByName(msrName));
      measures.remove(getMeasureByName(msrName));
      measureMap.remove(msrName.toLowerCase());
      MetastoreUtil.addNameStrings(getProperties(), MetastoreUtil.getCubeMeasureListKey(getName()), measures);
    }
  }

  /**
   * Adds the timed dimension
   *
   * @param timedDimension time dimension
   */
  public void addTimedDimension(@NonNull String timedDimension) {
    timedDimension = timedDimension.toLowerCase();
    Set timeDims = getTimedDimensions();
    if (timeDims == null) {
      timeDims = new LinkedHashSet<>();
    }
    if (timeDims.contains(timedDimension)) {
      log.info("Timed dimension {} is already present in cube {}", timedDimension, getName());
      return;
    }

    timeDims.add(timedDimension);
    getProperties().put(MetastoreUtil.getCubeTimedDimensionListKey(getName()), StringUtils.join(timeDims, ","));
  }

  /**
   * Removes the timed dimension
   *
   * @param timedDimension time dimension
   */
  public void removeTimedDimension(@NonNull String timedDimension) {
    timedDimension = timedDimension.toLowerCase();
    Set timeDims = getTimedDimensions();
    if (timeDims != null && timeDims.contains(timedDimension)) {
      timeDims.remove(timedDimension);
      getProperties().put(MetastoreUtil.getCubeTimedDimensionListKey(getName()), StringUtils.join(timeDims, ","));
    }
  }

  @Override
  public boolean isDerivedCube() {
    return false;
  }

  @Override
  public Set getMeasureNames() {
    Set measureNames = new HashSet<>();
    for (CubeMeasure f : getMeasures()) {
      measureNames.add(f.getName().toLowerCase());
    }
    return measureNames;
  }

  @Override
  public Set getDimAttributeNames() {
    Set dimNames = new HashSet<>();
    for (CubeDimAttribute f : getDimAttributes()) {
      MetastoreUtil.addColumnNames(f, dimNames);
    }
    return dimNames;
  }

  @Override
  public boolean allFieldsQueriable() {
    String canBeQueried = getProperties().get(MetastoreConstants.CUBE_ALL_FIELDS_QUERIABLE);
    return canBeQueried == null || Boolean.parseBoolean(canBeQueried.toLowerCase());
  }

  @Override
  public Set getAllFieldNames() {
    Set fieldNames = super.getAllFieldNames();
    fieldNames.addAll(getMeasureNames());
    fieldNames.addAll(getDimAttributeNames());
    fieldNames.addAll(getTimedDimensions());
    return fieldNames;
  }

  public Set getAllFields() {
    Set columns = Sets.newHashSet();
    columns.addAll(getMeasures());
    columns.addAll(getDimAttributes());
    columns.addAll(getExpressions());
    return columns;
  }

  /**
   * @see org.apache.lens.cube.metadata.AbstractBaseTable
   */
  @Override
  protected String getJoinChainListPropKey(@NonNull String tblname) {
    return MetastoreUtil.getCubeJoinChainListKey(getName());
  }

  public String getPartitionColumnOfTimeDim(@NonNull String timeDimName) {
    String partCol = getProperties().get(MetastoreConstants.TIMEDIM_TO_PART_MAPPING_PFX + timeDimName);
    return StringUtils.isNotBlank(partCol) ? partCol : timeDimName;
  }

  public String getTimeDimOfPartitionColumn(@NonNull String partCol) {
    Map properties = getProperties();
    for (Map.Entry entry : properties.entrySet()) {
      if (entry.getKey().startsWith(MetastoreConstants.TIMEDIM_TO_PART_MAPPING_PFX)
        && entry.getValue().equalsIgnoreCase(partCol)) {
        return entry.getKey().replace(MetastoreConstants.TIMEDIM_TO_PART_MAPPING_PFX, "");
      }
    }
    return partCol;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy