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

org.apache.lens.cube.parse.CandidateTablePruneCause 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.parse;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;

import static org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode.*;

import static com.google.common.collect.Lists.newArrayList;

import java.util.*;

import org.apache.lens.cube.metadata.TimeRange;
import org.apache.lens.server.api.error.LensException;


import org.codehaus.jackson.annotate.JsonWriteNullProperties;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Contains the cause why a candidate table is not picked for answering the query
 */
// no args constructor Needed for jackson. SUSPEND CHECKSTYLE CHECK HideUtilityClassConstructorCheck
@JsonWriteNullProperties(false)
@Data
@NoArgsConstructor
public class CandidateTablePruneCause {

  public enum CandidateTablePruneCode {
    // other fact set element is removed
    ELEMENT_IN_SET_PRUNED("Other candidate from measure covering set is pruned"),
    // least weight not satisfied
    MORE_WEIGHT("Picked table had more weight than minimum."),
    // partial data is enabled, another fact has more data.
    LESS_DATA("Picked table has less data than the maximum"),
    // cube table has more partitions
    MORE_PARTITIONS("Picked table has more partitions than minimum"),
    // storage is not supported by execution engine/driver
    UNSUPPORTED_STORAGE("Unsupported Storage"),
    // invalid cube table
    INVALID("Invalid cube table provided in query"),
    SEGMENTATION_PRUNED_WITH_ERROR ("%s") {
      @Override
      Object[] getFormatPlaceholders(Set causes) {
        return new Object[]{
          causes.stream().map(cause->cause.innerException).map(LensException::getMessage).collect(joining(",")),
        };
      }
    },

    // expression is not evaluable in the candidate
    COLUMN_NOT_FOUND("%s are not %s") {
      Object[] getFormatPlaceholders(Set causes) {
        if (causes.size() == 1) {
          return new String[]{
            "Columns " + causes.iterator().next().getMissingColumns(),
            "present in any table",
          };
        } else {
          return new String[]{
            "Column Sets: " + causes.stream().map(CandidateTablePruneCause::getMissingColumns).collect(toSet()),
            "queriable together",
          };
        }
      }
    },
    // candidate table tries to get denormalized field from dimension and the
    // referred dimension is invalid.
    INVALID_DENORM_TABLE("Referred dimension is invalid in one of the candidate tables"),

    // Moved from Stoarge causes .
    //The storage is removed as its not set in property "lens.cube.query.valid.fact..storagetables"
    INVALID_STORAGE("Invalid Storage"),
    // storage table does not exist. Commented as its not being used anywhere in master.
    // STOARGE_TABLE_DOES_NOT_EXIST("Storage table does not exist"),
    // storage has no update periods queried. Commented as its not being used anywhere in master.
    // MISSING_UPDATE_PERIODS("Storage has no update periods"),

    // storage table has no partitions queried
    NO_PARTITIONS("Storage table has no partitions"),
    // partition column does not exist
    PART_COL_DOES_NOT_EXIST("Partition column does not exist"),
    // Range is not supported by this storage table
    TIME_RANGE_NOT_ANSWERABLE("Range not answerable"),
    STORAGE_NOT_AVAILABLE_IN_RANGE("No storages available for all of these time ranges: %s") {
      @Override
      Object[] getFormatPlaceholders(Set causes) {
        return new Object[]{
          causes.stream().map(CandidateTablePruneCause::getInvalidRanges).flatMap(Collection::stream)
            .collect(toSet()).toString(),
        };
      }
    },

    EXPRESSION_NOT_EVALUABLE("%s expressions not evaluable") {
      Object[] getFormatPlaceholders(Set causes) {
        return new String[]{
          causes.stream().map(CandidateTablePruneCause::getMissingExpressions).flatMap(Collection::stream)
            .collect(toSet()).toString(),
        };
      }
    },
    // column not valid in cube table. Commented the below line as it's not being used in master.
    //COLUMN_NOT_VALID("Column not valid in cube table"),
    // column not found in cube table
    DENORM_COLUMN_NOT_FOUND("%s are not %s") {
      Object[] getFormatPlaceholders(Set causes) {
        if (causes.size() == 1) {
          return new String[]{
            "Columns " + causes.iterator().next().getMissingColumns(),
            "present in any table",
          };
        } else {
          return new String[]{
            "Column Sets: " + causes.stream().map(CandidateTablePruneCause::getMissingColumns).collect(toSet()),
            "queriable together",
          };
        }
      }
    },
    // missing storage tables for cube table
    MISSING_STORAGES("Missing storage tables for the cube table"),
    // no candidate storges for cube table, storage cause will have why each
    // storage is not a candidate
    NO_CANDIDATE_STORAGES("No candidate storages for any table"),
    // time dimension not supported. Either directly or indirectly.
    TIMEDIM_NOT_SUPPORTED("Queried data not available for time dimensions: %s") {
      @Override
      Object[] getFormatPlaceholders(Set causes) {
        return new Object[]{
          causes.stream().map(CandidateTablePruneCause::getUnsupportedTimeDims).flatMap(Collection::stream)
            .collect(toSet()).toString(),
        };
      }
    },
    NO_FACT_UPDATE_PERIODS_FOR_GIVEN_RANGE("No fact update periods for given range"),

    // no candidate update periods, update period cause will have why each
    // update period is not a candidate
    NO_CANDIDATE_UPDATE_PERIODS("Storage update periods are not valid for given time range"),

    NO_COLUMN_PART_OF_A_JOIN_PATH("No column part of a join path. Join columns: [%s]") {
      Object[] getFormatPlaceholders(Set causes) {
        return new String[]{
          causes.stream().map(CandidateTablePruneCause::getJoinColumns).flatMap(Collection::stream)
            .collect(toSet()).toString(),
        };
      }
    },
    // cube table is an aggregated fact and queried column is not under default
    // aggregate
    MISSING_DEFAULT_AGGREGATE("Columns: [%s] are missing default aggregate") {
      Object[] getFormatPlaceholders(Set causes) {
        return new String[]{
          causes.stream().map(CandidateTablePruneCause::getColumnsMissingDefaultAggregate).flatMap(Collection::stream)
            .collect(toSet()).toString(),
        };
      }
    },
    SEGMENTATION_PRUNED("%s") {
      @Override
      Object[] getFormatPlaceholders(Set causes) {
        Map briefCause = Maps.newHashMap();
        for (CandidateTablePruneCause cause : causes) {
          briefCause.putAll(cause.getInnerCauses());
        }
        if (briefCause.size() == 1) {
          return new Object[]{briefCause.values().iterator().next(), };
        }
        return new Object[]{
          "segmentation pruned: "
            + briefCause.entrySet().stream().map(entry->entry.getKey()+": "+entry.getValue()).collect(joining(";")),
        };
      }
    },
    // missing partitions for cube table
    MISSING_PARTITIONS("Missing partitions for the cube table: %s") {
      Object[] getFormatPlaceholders(Set causes) {
        return new String[]{
          causes.stream().map(CandidateTablePruneCause::getMissingPartitions).collect(toSet()).toString(),
        };
      }
    },
    // incomplete data in the fact
    INCOMPLETE_PARTITION("Data for the requested metrics is only partially complete. Partially complete metrics are:"
            + " %s. Please try again later or rerun after removing incomplete metrics") {
      Object[] getFormatPlaceholders(Set causes) {
        return new String[]{
          causes.stream().map(CandidateTablePruneCause::getIncompletePartitions).collect(toSet()).toString(),
        };
      }
    };

    String errorFormat;

    CandidateTablePruneCode(String format) {
      this.errorFormat = format;
    }

    Object[] getFormatPlaceholders(Set causes) {
      return null;
    }

    String getBriefError(Set causes) {
      try {
        return String.format(errorFormat, getFormatPlaceholders(causes));
      } catch (NullPointerException e) {
        return name();
      }
    }
  }

  public enum SkipUpdatePeriodCode {
    // invalid update period
    INVALID,
    //this update period is greater than the Query max interval as provided by user with lens.cube.query.max.interval
    UPDATE_PERIOD_BIGGER_THAN_MAX,
    TIME_RANGE_NOT_ANSWERABLE_BY_UPDATE_PERIOD
  }

  // Used for Test cases only.
  // storage to skip storage cause for  dim table
  private Map dimStoragePruningCauses;

  // cause for cube table
  private CandidateTablePruneCode cause;
  // populated only incase of missing partitions cause
  private Set missingPartitions;
  // populated only incase of incomplete partitions cause
  private Map> incompletePartitions;
  // populated only incase of missing update periods cause
  private List missingUpdatePeriods;
  // populated in case of missing columns
  private Set missingColumns;
  // populated in case of expressions not evaluable
  private List missingExpressions;
  // populated in case of no column part of a join path
  private Collection joinColumns;
  // the columns that are missing default aggregate. only set in case of MISSING_DEFAULT_AGGREGATE
  private List columnsMissingDefaultAggregate;
  // if a time dim is not supported by the fact. Would be set if and only if
  // the fact is not partitioned by part col of the time dim and time dim is not a dim attribute
  private Set unsupportedTimeDims;
  private MaxCoveringFactResolver.TimeCovered maxTimeCovered;
  // time covered
  // ranges in which fact is invalid
  private List invalidRanges;

  private List nonExistantPartCols;

  private Map updatePeriodRejectionCause;

  private Map innerCauses;
  private LensException innerException;

  public CandidateTablePruneCause(CandidateTablePruneCode cause) {
    this.cause = cause;
  }

  // Different static constructors for different causes.
  static CandidateTablePruneCause storageNotAvailableInRange(List ranges) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(STORAGE_NOT_AVAILABLE_IN_RANGE);
    cause.invalidRanges = ranges;
    return cause;
  }
  static CandidateTablePruneCause timeDimNotSupported(Set unsupportedTimeDims) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(TIMEDIM_NOT_SUPPORTED);
    cause.unsupportedTimeDims = unsupportedTimeDims;
    return cause;
  }

  static CandidateTablePruneCause columnNotFound(Collection missingColumns) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(COLUMN_NOT_FOUND);
    cause.setMissingColumns(Sets.newHashSet(missingColumns));
    return cause;
  }
  static CandidateTablePruneCause denormColumnNotFound(Collection missingColumns) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(DENORM_COLUMN_NOT_FOUND);
    cause.setMissingColumns(Sets.newHashSet(missingColumns));
    return cause;
  }

  static CandidateTablePruneCause columnNotFound(String... columns) {
    return columnNotFound(newArrayList(columns));
  }

  static CandidateTablePruneCause expressionNotEvaluable(String... exprs) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(EXPRESSION_NOT_EVALUABLE);
    cause.setMissingExpressions(newArrayList(exprs));
    return cause;
  }

  static CandidateTablePruneCause missingPartitions(Set nonExistingParts) {
    CandidateTablePruneCause cause =
      new CandidateTablePruneCause(MISSING_PARTITIONS);
    cause.setMissingPartitions(nonExistingParts);
    return cause;
  }

  static CandidateTablePruneCause incompletePartitions(Map> incompleteParts) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(INCOMPLETE_PARTITION);
    //incompleteParts may be null when partial data is allowed.
    cause.setIncompletePartitions(incompleteParts);
    return cause;
  }

  public static CandidateTablePruneCause lessData(MaxCoveringFactResolver.TimeCovered timeCovered) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(LESS_DATA);
    cause.setMaxTimeCovered(timeCovered);
    return cause;
  }

  public static CandidateTablePruneCause noColumnPartOfAJoinPath(final Collection colSet) {
    CandidateTablePruneCause cause =
      new CandidateTablePruneCause(NO_COLUMN_PART_OF_A_JOIN_PATH);
    cause.setJoinColumns(colSet);
    return cause;
  }

  static CandidateTablePruneCause missingDefaultAggregate(String... names) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(MISSING_DEFAULT_AGGREGATE);
    cause.setColumnsMissingDefaultAggregate(newArrayList(names));
    return cause;
  }

  /**
   * This factroy menthod can be used when a Dim Table is pruned because all its Storages are pruned.
   * @param dimStoragePruningCauses
   * @return
   */
  static CandidateTablePruneCause noCandidateStoragesForDimtable(
    Map dimStoragePruningCauses) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(NO_CANDIDATE_STORAGES);
    cause.setDimStoragePruningCauses(new HashMap());
    for (Map.Entry entry : dimStoragePruningCauses.entrySet()) {
      String key = entry.getKey();
      key = key.substring(0, (key.indexOf("_") + key.length() + 1) % (key.length() + 1)); // extract the storage part
      cause.getDimStoragePruningCauses().put(key.toLowerCase(), entry.getValue());
    }
    return cause;
  }

  /**
   * Queried partition columns are not present in this Storage Candidate
   * @param missingPartitionColumns
   * @return
   */
  public static CandidateTablePruneCause partitionColumnsMissing(final String... missingPartitionColumns) {
    return partitionColumnsMissing(Lists.newArrayList(missingPartitionColumns));
  }
  public static CandidateTablePruneCause partitionColumnsMissing(final List missingPartitionColumns) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(PART_COL_DOES_NOT_EXIST);
    cause.nonExistantPartCols = missingPartitionColumns;
    return cause;
  }

  /**
   * All update periods of this Stoarge Candidate are rejected.
   * @param updatePeriodRejectionCause
   * @return
   */
  static CandidateTablePruneCause updatePeriodsRejected(
    final Map updatePeriodRejectionCause) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(NO_CANDIDATE_UPDATE_PERIODS);
    cause.updatePeriodRejectionCause = updatePeriodRejectionCause;
    return cause;
  }
  public static CandidateTablePruneCause segmentationPruned(Map inner) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(SEGMENTATION_PRUNED);
    cause.innerCauses = inner;
    return cause;
  }
  public static CandidateTablePruneCause segmentationPruned(LensException e) {
    CandidateTablePruneCause cause = new CandidateTablePruneCause(SEGMENTATION_PRUNED_WITH_ERROR);
    cause.innerException = e;
    return cause;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy