/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * Licensed 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 com.linkedin.pinot.common.data; import com.google.common.base.Preconditions; import com.linkedin.pinot.common.data.FieldSpec.DataType; import com.linkedin.pinot.common.data.TimeGranularitySpec.TimeFormat; import com.linkedin.pinot.common.utils.EqualityUtils; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.joda.time.DateTime; /** * The <code>TimeGranularitySpec</code> class contains all specs related to time field. * <p>- <code>DataType</code>: data type of the time column (e.g. INT, LONG). * <p>- <code>TimeType</code>: time unit of the time column (e.g. MINUTES, HOURS). * <p>- <code>TimeUnitSize</code>: size of the time buckets (e.g. 10 MINUTES, 2 HOURS). By default this is set to 1. * <p>- <code>TimeFormat</code>: Can be either EPOCH (default) or SIMPLE_DATE_FORMAT:pattern e.g SIMPLE_DATE_FORMAT:yyyyMMdd * <p>- <code>Name</code>: name of the time column. * <p>E.g. * <p>If the time column is in millisecondsSinceEpoch, constructor can be invoked as: * <p><code>TimeGranularitySpec(LONG, MILLISECONDS, timeColumnName)</code> * <p>If the time column is in tenMinutesSinceEpoch, constructor can be invoked as: * <p><code>TimeGranularitySpec(LONG, 10, MINUTES, timeColumnName)</code> * <p>If the time column is in Simple Date Format: * <p><code>new TimeGranularitySpec(DataType.STRING, 1, TimeUnit.HOURS, TimeFormat.SIMPLE_DATE_FORMAT.toString() +":yyyyMMdd", "hour");</code> */ @JsonIgnoreProperties(ignoreUnknown = true) public class TimeGranularitySpec { private static final int DEFAULT_TIME_UNIT_SIZE = 1; private DataType _dataType; private TimeUnit _timeType; private int _timeUnitSize = DEFAULT_TIME_UNIT_SIZE; private String _timeFormat = TimeFormat.EPOCH.toString(); private String _name; /* * Can be either EPOCH (default) or SIMPLE_DATE_FORMAT:pattern e.g SIMPLE_DATE_FORMAT:yyyyMMdd */ public enum TimeFormat { EPOCH, //default SIMPLE_DATE_FORMAT } // Default constructor required by JSON de-serializer. DO NOT REMOVE. public TimeGranularitySpec() { } /** * * @param dataType * @param timeType * @param name */ public TimeGranularitySpec(@Nonnull DataType dataType, @Nonnull TimeUnit timeType, @Nonnull String name) { Preconditions.checkNotNull(timeType); Preconditions.checkNotNull(name); _dataType = dataType.getStoredType(); _timeType = timeType; _name = name; } /** * * @param dataType * @param timeType * @param timeFormat Can be either EPOCH (default) or SIMPLE_DATE_FORMAT:pattern e.g SIMPLE_DATE_FORMAT:yyyyMMdd * @param name */ public TimeGranularitySpec(@Nonnull DataType dataType, @Nonnull TimeUnit timeType, @Nonnull String timeFormat, @Nonnull String name) { Preconditions.checkNotNull(timeType); Preconditions.checkNotNull(name); Preconditions.checkNotNull(timeFormat); Preconditions.checkArgument(timeFormat.equals(TimeFormat.EPOCH.toString()) || (timeFormat.startsWith(TimeFormat.SIMPLE_DATE_FORMAT.toString()))); _dataType = dataType.getStoredType(); _timeType = timeType; _name = name; _timeFormat = timeFormat; } /** * * @param dataType * @param timeUnitSize * @param timeType * @param name */ public TimeGranularitySpec(@Nonnull DataType dataType, int timeUnitSize, @Nonnull TimeUnit timeType, @Nonnull String name) { Preconditions.checkNotNull(timeType); Preconditions.checkNotNull(name); _dataType = dataType.getStoredType(); _timeType = timeType; _timeUnitSize = timeUnitSize; _name = name; } /** * * @param dataType * @param timeUnitSize * @param timeType * @param timeFormat Can be either EPOCH (default) or SIMPLE_DATE_FORMAT:pattern e.g SIMPLE_DATE_FORMAT:yyyyMMdd * @param name */ public TimeGranularitySpec(@Nonnull DataType dataType, int timeUnitSize, @Nonnull TimeUnit timeType, @Nonnull String timeFormat, @Nonnull String name) { Preconditions.checkNotNull(timeType); Preconditions.checkNotNull(name); Preconditions.checkNotNull(timeFormat); Preconditions.checkArgument(timeFormat.equals(TimeFormat.EPOCH.toString()) || (timeFormat.startsWith(TimeFormat.SIMPLE_DATE_FORMAT.toString()))); _dataType = dataType.getStoredType(); _timeType = timeType; _timeUnitSize = timeUnitSize; _name = name; _timeFormat = timeFormat; } public DataType getDataType() { return _dataType; } public void setDataType(@Nonnull DataType dataType) { _dataType = dataType.getStoredType(); } public TimeUnit getTimeType() { return _timeType; } public void setTimeType(@Nonnull TimeUnit timeType) { Preconditions.checkNotNull(timeType); _timeType = timeType; } public int getTimeUnitSize() { return _timeUnitSize; } // Required by JSON de-serializer. DO NOT REMOVE. public void setTimeUnitSize(int timeUnitSize) { Preconditions.checkArgument(timeUnitSize > 0); _timeUnitSize = timeUnitSize; } // Required by JSON de-serializer (for backward compatible). DO NOT REMOVE. public void setTimeunitSize(int timeUnitSize) { Preconditions.checkArgument(timeUnitSize > 0); _timeUnitSize = timeUnitSize; } public String getName() { return _name; } public void setName(@Nonnull String name) { Preconditions.checkNotNull(name); _name = name; } public void setTimeFormat(String timeFormat) { this._timeFormat = timeFormat; } public String getTimeFormat() { return _timeFormat; } /** * Convert the units of time since epoch to {@link DateTime} format using current <code>TimeGranularitySpec</code>. */ public DateTime toDateTime(long timeSinceEpoch) { return new DateTime(_timeType.toMillis(timeSinceEpoch * _timeUnitSize)); } @Override public String toString() { return "< data type: " + _dataType + ", time type: " + _timeType + ", time unit size: " + _timeUnitSize + ", name: " + _name + ", timeFormat: " + _timeFormat + " >"; } @Override public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof TimeGranularitySpec) { TimeGranularitySpec anotherTimeGranularitySpec = (TimeGranularitySpec) anObject; return _dataType.equals(anotherTimeGranularitySpec._dataType) && _timeType.equals(anotherTimeGranularitySpec._timeType) && _timeUnitSize == anotherTimeGranularitySpec._timeUnitSize && _name.equals(anotherTimeGranularitySpec._name) && _timeFormat.equals(anotherTimeGranularitySpec._timeFormat); } return false; } @Override public int hashCode() { int result = _dataType.hashCode(); result = EqualityUtils.hashCodeOf(result, _timeType); result = EqualityUtils.hashCodeOf(result, _timeUnitSize); result = EqualityUtils.hashCodeOf(result, _name); result = EqualityUtils.hashCodeOf(result, _timeFormat); return result; } }