/**
* 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.utils.EqualityUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/**
* The <code>MetricFieldSpec</code> class contains all specs related to any metric field (column) in {@link Schema}.
* <p>Different with {@link DimensionFieldSpec}, inside <code>MetricFieldSpec</code> we allow user defined
* {@link DerivedMetricType} and <code>fieldSize</code>.
* <p>{@link DerivedMetricType} is used when the metric field is derived from some other fields (e.g. HLL).
* <p><code>fieldSize</code> is used to mark the size of the value when the size is not constant (e.g. STRING).
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MetricFieldSpec extends FieldSpec {
private static final int UNDEFINED_FIELD_SIZE = -1;
// These two fields are for derived metric fields.
private int _fieldSize = UNDEFINED_FIELD_SIZE;
private DerivedMetricType _derivedMetricType = null;
// Default constructor required by JSON de-serializer. DO NOT REMOVE.
public MetricFieldSpec() {
super();
}
public MetricFieldSpec(@Nonnull String name, @Nonnull DataType dataType) {
super(name, dataType, true);
}
public MetricFieldSpec(@Nonnull String name, @Nonnull DataType dataType, @Nonnull Object defaultNullValue) {
super(name, dataType, true, defaultNullValue);
}
// For derived metric fields.
public MetricFieldSpec(@Nonnull String name, @Nonnull DataType dataType, int fieldSize,
@Nonnull DerivedMetricType derivedMetricType) {
super(name, dataType, true);
Preconditions.checkArgument(fieldSize > 0, "Field size must be a positive number.");
_fieldSize = fieldSize;
_derivedMetricType = derivedMetricType;
}
// For derived metric fields.
public MetricFieldSpec(@Nonnull String name, @Nonnull DataType dataType, int fieldSize,
@Nonnull DerivedMetricType derivedMetricType, @Nonnull Object defaultNullValue) {
super(name, dataType, true, defaultNullValue);
Preconditions.checkArgument(fieldSize > 0, "Field size must be a positive number.");
_fieldSize = fieldSize;
_derivedMetricType = derivedMetricType;
}
public int getFieldSize() {
if (_fieldSize == UNDEFINED_FIELD_SIZE) {
return getDataType().size();
} else {
return _fieldSize;
}
}
// Required by JSON de-serializer. DO NOT REMOVE.
public void setFieldSize(int fieldSize) {
_fieldSize = fieldSize;
}
@Nullable
public DerivedMetricType getDerivedMetricType() {
return _derivedMetricType;
}
// Required by JSON de-serializer. DO NOT REMOVE.
public void setDerivedMetricType(@Nullable DerivedMetricType derivedMetricType) {
_derivedMetricType = derivedMetricType;
}
@JsonIgnore
@Nonnull
@Override
public FieldType getFieldType() {
return FieldType.METRIC;
}
@Override
public void setSingleValueField(boolean isSingleValueField) {
Preconditions.checkArgument(isSingleValueField, "Unsupported multi-value for metric field.");
}
@JsonIgnore
public boolean isDerivedMetric() {
return _derivedMetricType != null;
}
/**
* The <code>DerivedMetricType</code> enum is assigned for all metric fields to allow derived metric field, a
* customized type which is not included in DataType.
* <p>It is currently used for derived field recognition in star tree <code>MetricBuffer</code>, may have other use
* cases later.
* <p>Generally, a customized type value should be converted to a standard
* {@link com.linkedin.pinot.common.data.FieldSpec.DataType} for storage, and converted back when needed.
*/
public enum DerivedMetricType {
// HLL derived metric type.
HLL
}
@Override
public String toString() {
return "< field type: METRIC, field name: " + getName() + ", data type: " + getDataType() + ", default null value: "
+ getDefaultNullValue() + ", field size: " + getFieldSize() + ", derived metric type: " + _derivedMetricType
+ " >";
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object instanceof MetricFieldSpec) {
MetricFieldSpec that = (MetricFieldSpec) object;
return getName().equals(that.getName())
&& getDataType() == that.getDataType()
&& getDefaultNullValue().equals(that.getDefaultNullValue())
&& getFieldSize() == that.getFieldSize()
&& _derivedMetricType == that._derivedMetricType;
}
return false;
}
@Override
public int hashCode() {
int result = getName().hashCode();
result = EqualityUtils.hashCodeOf(result, getDataType());
result = EqualityUtils.hashCodeOf(result, getDefaultNullValue());
result = EqualityUtils.hashCodeOf(result, getFieldSize());
result = EqualityUtils.hashCodeOf(result, _derivedMetricType);
return result;
}
}