Browse Source

NPE fix for data aggregation function in case of TEXT values

pull/89/head
Andrew Shvayka 10 years ago
parent
commit
7fc712a3f7
  1. 201
      dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java
  2. 1
      dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesDao.java

201
dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.timeseries;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row; import com.datastax.driver.core.Row;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.kv.*; import org.thingsboard.server.common.data.kv.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -26,6 +27,7 @@ import java.util.Optional;
/** /**
* Created by ashvayka on 20.02.17. * Created by ashvayka on 20.02.17.
*/ */
@Slf4j
public class AggregatePartitionsFunction implements com.google.common.base.Function<List<ResultSet>, Optional<TsKvEntry>> { public class AggregatePartitionsFunction implements com.google.common.base.Function<List<ResultSet>, Optional<TsKvEntry>> {
private static final int LONG_CNT_POS = 0; private static final int LONG_CNT_POS = 0;
@ -50,111 +52,118 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct
@Nullable @Nullable
@Override @Override
public Optional<TsKvEntry> apply(@Nullable List<ResultSet> rsList) { public Optional<TsKvEntry> apply(@Nullable List<ResultSet> rsList) {
if (rsList == null || rsList.size() == 0) { try {
return Optional.empty(); log.trace("[{}][{}][{}] Going to aggregate data", key, ts, aggregation);
} if (rsList == null || rsList.size() == 0) {
long count = 0; return Optional.empty();
DataType dataType = null; }
long count = 0;
Boolean bValue = null; DataType dataType = null;
String sValue = null;
Double dValue = null; Boolean bValue = null;
Long lValue = null; String sValue = null;
Double dValue = null;
for (ResultSet rs : rsList) { Long lValue = null;
for (Row row : rs.all()) {
long curCount; for (ResultSet rs : rsList) {
for (Row row : rs.all()) {
Long curLValue = null; long curCount;
Double curDValue = null;
Boolean curBValue = null; Long curLValue = null;
String curSValue = null; Double curDValue = null;
Boolean curBValue = null;
long longCount = row.getLong(LONG_CNT_POS); String curSValue = null;
long doubleCount = row.getLong(DOUBLE_CNT_POS);
long boolCount = row.getLong(BOOL_CNT_POS); long longCount = row.getLong(LONG_CNT_POS);
long strCount = row.getLong(STR_CNT_POS); long doubleCount = row.getLong(DOUBLE_CNT_POS);
long boolCount = row.getLong(BOOL_CNT_POS);
if (longCount > 0) { long strCount = row.getLong(STR_CNT_POS);
dataType = DataType.LONG;
curCount = longCount; if (longCount > 0) {
curLValue = getLongValue(row); dataType = DataType.LONG;
} else if (doubleCount > 0) { curCount = longCount;
dataType = DataType.DOUBLE; curLValue = getLongValue(row);
curCount = doubleCount; } else if (doubleCount > 0) {
curDValue = getDoubleValue(row); dataType = DataType.DOUBLE;
} else if (boolCount > 0) { curCount = doubleCount;
dataType = DataType.BOOLEAN; curDValue = getDoubleValue(row);
curCount = boolCount; } else if (boolCount > 0) {
curBValue = getBooleanValue(row); dataType = DataType.BOOLEAN;
} else if (strCount > 0) { curCount = boolCount;
dataType = DataType.STRING; curBValue = getBooleanValue(row);
curCount = strCount; } else if (strCount > 0) {
curSValue = getStringValue(row); dataType = DataType.STRING;
} else { curCount = strCount;
continue; curSValue = getStringValue(row);
} } else {
continue;
if (aggregation == Aggregation.COUNT) {
count += curCount;
} else if (aggregation == Aggregation.AVG || aggregation == Aggregation.SUM) {
count += curCount;
if (curDValue != null) {
dValue = dValue == null ? curDValue : dValue + curDValue;
} else if (curLValue != null) {
lValue = lValue == null ? curLValue : lValue + curLValue;
} }
} else if (aggregation == Aggregation.MIN) {
if (curDValue != null) { if (aggregation == Aggregation.COUNT) {
dValue = dValue == null ? curDValue : Math.min(dValue, curDValue); count += curCount;
} else if (curLValue != null) { } else if (aggregation == Aggregation.AVG || aggregation == Aggregation.SUM) {
lValue = lValue == null ? curLValue : Math.min(lValue, curLValue); count += curCount;
} else if (curBValue != null) { if (curDValue != null) {
bValue = bValue == null ? curBValue : bValue && curBValue; dValue = dValue == null ? curDValue : dValue + curDValue;
} else if (curSValue != null) { } else if (curLValue != null) {
if (sValue == null || curSValue.compareTo(sValue) < 0) { lValue = lValue == null ? curLValue : lValue + curLValue;
sValue = curSValue;
} }
} } else if (aggregation == Aggregation.MIN) {
} else if (aggregation == Aggregation.MAX) { if (curDValue != null) {
if (curDValue != null) { dValue = dValue == null ? curDValue : Math.min(dValue, curDValue);
dValue = dValue == null ? curDValue : Math.max(dValue, curDValue); } else if (curLValue != null) {
} else if (curLValue != null) { lValue = lValue == null ? curLValue : Math.min(lValue, curLValue);
lValue = lValue == null ? curLValue : Math.max(lValue, curLValue); } else if (curBValue != null) {
} else if (curBValue != null) { bValue = bValue == null ? curBValue : bValue && curBValue;
bValue = bValue == null ? curBValue : bValue || curBValue; } else if (curSValue != null) {
} else if (curSValue != null) { if (sValue == null || curSValue.compareTo(sValue) < 0) {
if (sValue == null || curSValue.compareTo(sValue) > 0) { sValue = curSValue;
sValue = curSValue; }
}
} else if (aggregation == Aggregation.MAX) {
if (curDValue != null) {
dValue = dValue == null ? curDValue : Math.max(dValue, curDValue);
} else if (curLValue != null) {
lValue = lValue == null ? curLValue : Math.max(lValue, curLValue);
} else if (curBValue != null) {
bValue = bValue == null ? curBValue : bValue || curBValue;
} else if (curSValue != null) {
if (sValue == null || curSValue.compareTo(sValue) > 0) {
sValue = curSValue;
}
} }
} }
} }
} }
} if (dataType == null) {
if (dataType == null) {
return Optional.empty();
} else if (aggregation == Aggregation.COUNT) {
return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, (long) count)));
} else if (aggregation == Aggregation.AVG || aggregation == Aggregation.SUM) {
if (count == 0 || (dataType == DataType.DOUBLE && dValue == null) || (dataType == DataType.LONG && lValue == null)) {
return Optional.empty(); return Optional.empty();
} else if (dataType == DataType.DOUBLE) { } else if (aggregation == Aggregation.COUNT) {
return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, aggregation == Aggregation.SUM ? dValue : (dValue / count)))); return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, (long) count)));
} else if (dataType == DataType.LONG) { } else if (aggregation == Aggregation.AVG || aggregation == Aggregation.SUM) {
return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, aggregation == Aggregation.SUM ? lValue : (lValue / count)))); if (count == 0 || (dataType == DataType.DOUBLE && dValue == null) || (dataType == DataType.LONG && lValue == null)) {
} return Optional.empty();
} else if (aggregation == Aggregation.MIN || aggregation == Aggregation.MAX) { } else if (dataType == DataType.DOUBLE) {
if (dataType == DataType.DOUBLE) { return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, aggregation == Aggregation.SUM ? dValue : (dValue / count))));
return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, dValue))); } else if (dataType == DataType.LONG) {
} else if (dataType == DataType.LONG) { return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, aggregation == Aggregation.SUM ? lValue : (lValue / count))));
return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, lValue))); }
} else if (dataType == DataType.STRING) { } else if (aggregation == Aggregation.MIN || aggregation == Aggregation.MAX) {
return Optional.of(new BasicTsKvEntry(ts, new StringDataEntry(key, sValue))); if (dataType == DataType.DOUBLE) {
} else { return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, dValue)));
return Optional.of(new BasicTsKvEntry(ts, new BooleanDataEntry(key, bValue))); } else if (dataType == DataType.LONG) {
return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, lValue)));
} else if (dataType == DataType.STRING) {
return Optional.of(new BasicTsKvEntry(ts, new StringDataEntry(key, sValue)));
} else {
return Optional.of(new BasicTsKvEntry(ts, new BooleanDataEntry(key, bValue)));
}
} }
log.trace("[{}][{}][{}] Aggregated data is empty.", key, ts, aggregation);
return Optional.empty();
}catch (Exception e){
log.error("[{}][{}][{}] Failed to aggregate data", key, ts, aggregation, e);
return Optional.empty();
} }
return null;
} }
private Boolean getBooleanValue(Row row) { private Boolean getBooleanValue(Row row) {

1
dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesDao.java

@ -215,6 +215,7 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao
PreparedStatement proto = getFetchStmt(aggregation); PreparedStatement proto = getFetchStmt(aggregation);
List<ResultSetFuture> futures = new ArrayList<>(partitions.size()); List<ResultSetFuture> futures = new ArrayList<>(partitions.size());
for (Long partition : partitions) { for (Long partition : partitions) {
log.trace("Fetching data for partition [{}] for entityType {} and entityId {}", partition, entityType, entityId);
BoundStatement stmt = proto.bind(); BoundStatement stmt = proto.bind();
stmt.setString(0, entityType); stmt.setString(0, entityType);
stmt.setUUID(1, entityId); stmt.setUUID(1, entityId);

Loading…
Cancel
Save