2021-03-16 15:33:34 +01:00
|
|
|
package org.gcube.accounting.analytics.persistence.postgresql;
|
|
|
|
|
|
|
|
import java.io.Serializable;
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Calendar;
|
2021-03-17 17:55:56 +01:00
|
|
|
import java.util.HashSet;
|
2021-03-16 15:33:34 +01:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import org.gcube.accounting.analytics.Filter;
|
|
|
|
import org.gcube.accounting.analytics.TemporalConstraint;
|
|
|
|
import org.gcube.accounting.analytics.TemporalConstraint.AggregationMode;
|
|
|
|
import org.gcube.accounting.analytics.TemporalConstraint.CalendarEnum;
|
2021-03-17 17:55:56 +01:00
|
|
|
import org.gcube.accounting.datamodel.UsageRecord;
|
2021-03-16 15:33:34 +01:00
|
|
|
import org.gcube.accounting.datamodel.aggregation.AggregatedServiceUsageRecord;
|
|
|
|
import org.gcube.documentstore.records.AggregatedRecord;
|
|
|
|
|
|
|
|
public class Query {
|
|
|
|
|
|
|
|
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS Z";
|
2021-03-17 16:08:58 +01:00
|
|
|
public static final String DATE_OF_TIMESERIES_AS_FIELD = AggregatedRecord.START_TIME;
|
2021-03-16 15:33:34 +01:00
|
|
|
|
|
|
|
private Class<? extends AggregatedRecord<?, ?>> clz;
|
|
|
|
private final RecordToDBMapper recordToDBMapper;
|
|
|
|
|
|
|
|
private List<String> requestedTableField;
|
|
|
|
private StringBuffer stringBuffer;
|
|
|
|
|
|
|
|
protected TemporalConstraint temporalConstraint;
|
|
|
|
protected List<Filter> filters;
|
|
|
|
protected Set<String> contexts;
|
|
|
|
|
|
|
|
public Query(Class<? extends AggregatedRecord<?, ?>> clz) throws Exception {
|
|
|
|
this.clz = clz;
|
|
|
|
this.recordToDBMapper = UsageRecordToDBMapping.getRecordToDB(clz);
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<String> getRequestedTableField() {
|
|
|
|
return requestedTableField;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setTemporalConstraint(TemporalConstraint temporalConstraint) {
|
|
|
|
this.temporalConstraint = temporalConstraint;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setFilters(List<Filter> filters) {
|
|
|
|
this.filters = filters;
|
|
|
|
}
|
2021-03-17 17:55:56 +01:00
|
|
|
|
2021-03-16 15:33:34 +01:00
|
|
|
public void setContexts(Set<String> contexts) {
|
|
|
|
this.contexts = contexts;
|
|
|
|
}
|
2021-03-17 17:55:56 +01:00
|
|
|
|
|
|
|
public void addContext(String context) {
|
|
|
|
if(contexts == null) {
|
|
|
|
contexts = new HashSet<>();
|
|
|
|
}
|
|
|
|
contexts.add(context);
|
|
|
|
}
|
|
|
|
|
2021-03-16 15:33:34 +01:00
|
|
|
|
|
|
|
public RecordToDBMapper getRecordToDBMapper() {
|
|
|
|
return recordToDBMapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void appendString(String string) {
|
|
|
|
stringBuffer.append("'");
|
|
|
|
stringBuffer.append(string);
|
|
|
|
stringBuffer.append("'");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String getTableField(String fieldName) {
|
|
|
|
return recordToDBMapper.getTableField(fieldName);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void appendTableField(String fieldName) {
|
|
|
|
stringBuffer.append(getTableField(fieldName));
|
|
|
|
}
|
|
|
|
|
2021-03-17 16:08:58 +01:00
|
|
|
public static String getFormattedDate(Calendar calendar) {
|
|
|
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATETIME_PATTERN);
|
|
|
|
String date = simpleDateFormat.format(calendar.getTime());
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
2021-03-16 15:33:34 +01:00
|
|
|
protected void appendValue(Serializable serializable) {
|
|
|
|
if(serializable instanceof Number) {
|
|
|
|
stringBuffer.append(serializable.toString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(serializable instanceof Calendar) {
|
|
|
|
Calendar calendar = (Calendar) serializable;
|
2021-03-17 16:08:58 +01:00
|
|
|
appendString(getFormattedDate(calendar));
|
2021-03-16 15:33:34 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(serializable instanceof Enum) {
|
|
|
|
Enum<?> e = (Enum<?>) serializable;
|
|
|
|
appendString(e.name());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// String, URI etc
|
|
|
|
appendString(serializable.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addFilters() {
|
|
|
|
if(filters!=null && filters.size()>0) {
|
|
|
|
// The first filter if the time_bucket
|
|
|
|
stringBuffer.append(" AND ");
|
|
|
|
boolean first = true;
|
|
|
|
for(Filter filter : filters) {
|
|
|
|
if(first) {
|
|
|
|
first = false;
|
|
|
|
}else {
|
|
|
|
stringBuffer.append(" AND ");
|
|
|
|
}
|
|
|
|
appendTableField(filter.getKey());
|
|
|
|
stringBuffer.append("=");
|
|
|
|
appendValue(filter.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 17:55:56 +01:00
|
|
|
protected void addContextFilter() {
|
|
|
|
if(contexts!=null && contexts.size()>0) {
|
|
|
|
// The first filter if the time_bucket
|
|
|
|
stringBuffer.append(" AND (");
|
|
|
|
boolean first = true;
|
|
|
|
for(String context : contexts) {
|
|
|
|
if(first) {
|
|
|
|
first = false;
|
|
|
|
}else {
|
|
|
|
stringBuffer.append(" OR ");
|
|
|
|
}
|
|
|
|
appendTableField(UsageRecord.SCOPE);
|
|
|
|
stringBuffer.append("=");
|
|
|
|
appendValue(context);
|
|
|
|
}
|
|
|
|
stringBuffer.append(")");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-16 15:33:34 +01:00
|
|
|
protected void addEmittedFields() throws Exception {
|
|
|
|
Set<String> aggregatedField = clz.newInstance().getAggregatedFields();
|
|
|
|
for(String fieldName : aggregatedField) {
|
|
|
|
String dbField = getTableField(fieldName);
|
|
|
|
switch (fieldName) {
|
|
|
|
case AggregatedRecord.START_TIME:
|
|
|
|
case AggregatedRecord.END_TIME:
|
|
|
|
case AggregatedRecord.AGGREGATED:
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
case AggregatedRecord.OPERATION_COUNT:
|
|
|
|
stringBuffer.append(", SUM(");
|
|
|
|
stringBuffer.append(dbField);
|
|
|
|
stringBuffer.append(") AS ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
// WEIGHTED AVERAGE
|
|
|
|
case AggregatedServiceUsageRecord.DURATION:
|
2021-03-17 14:56:08 +01:00
|
|
|
stringBuffer.append(", ROUND(SUM(");
|
2021-03-16 15:33:34 +01:00
|
|
|
stringBuffer.append(dbField);
|
|
|
|
stringBuffer.append("*");
|
|
|
|
appendTableField(AggregatedRecord.OPERATION_COUNT);
|
|
|
|
stringBuffer.append(")/SUM(");
|
|
|
|
appendTableField(AggregatedRecord.OPERATION_COUNT);
|
2021-03-17 14:56:08 +01:00
|
|
|
stringBuffer.append(")) AS ");
|
2021-03-16 15:33:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AggregatedServiceUsageRecord.MAX_INVOCATION_TIME:
|
|
|
|
stringBuffer.append(", MAX(");
|
|
|
|
stringBuffer.append(dbField);
|
|
|
|
stringBuffer.append(") AS ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AggregatedServiceUsageRecord.MIN_INVOCATION_TIME:
|
|
|
|
stringBuffer.append(", MIN(");
|
|
|
|
stringBuffer.append(dbField);
|
|
|
|
stringBuffer.append(") AS ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
stringBuffer.append(", ");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
stringBuffer.append(dbField);
|
|
|
|
requestedTableField.add(dbField);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String getTimeBucketCalendarInterval(AggregationMode aggregationMode) {
|
|
|
|
CalendarEnum calendarEnum = CalendarEnum.values()[aggregationMode.ordinal()];
|
|
|
|
return calendarEnum.name().toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addTimeBucket() {
|
|
|
|
stringBuffer.append("time_bucket('1 ");
|
|
|
|
String calendarInterval = getTimeBucketCalendarInterval(temporalConstraint.getAggregationMode());
|
|
|
|
stringBuffer.append(calendarInterval);
|
|
|
|
stringBuffer.append("',");
|
|
|
|
appendTableField(AggregatedRecord.START_TIME);
|
|
|
|
stringBuffer.append(") AS ");
|
|
|
|
stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD);
|
|
|
|
requestedTableField.add(DATE_OF_TIMESERIES_AS_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void newQuery() {
|
|
|
|
stringBuffer = new StringBuffer();
|
|
|
|
requestedTableField = new ArrayList<>();
|
|
|
|
stringBuffer.append("SELECT ");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addTemporalConstraintToQuery() {
|
|
|
|
stringBuffer.append(" WHERE ");
|
|
|
|
String tableField = getTableField(AggregatedRecord.START_TIME);
|
|
|
|
stringBuffer.append(tableField);
|
|
|
|
stringBuffer.append(" > ");
|
|
|
|
appendValue(temporalConstraint.getAlignedStartTime());
|
|
|
|
|
|
|
|
stringBuffer.append(" AND ");
|
|
|
|
stringBuffer.append(tableField);
|
|
|
|
stringBuffer.append(" < ");
|
|
|
|
appendValue(temporalConstraint.getAlignedEndTime());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addGropuBy() {
|
|
|
|
stringBuffer.append(" GROUP BY ");
|
|
|
|
stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addOrderBy() {
|
|
|
|
stringBuffer.append(" ORDER BY ");
|
|
|
|
stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD);
|
|
|
|
stringBuffer.append(" ASC");
|
|
|
|
}
|
|
|
|
|
2021-03-17 17:55:56 +01:00
|
|
|
public String getTimeSeriesQuery() throws Exception {
|
2021-03-16 15:33:34 +01:00
|
|
|
newQuery();
|
|
|
|
|
|
|
|
addTimeBucket();
|
|
|
|
|
|
|
|
addEmittedFields();
|
|
|
|
|
|
|
|
stringBuffer.append(" FROM ");
|
|
|
|
stringBuffer.append(recordToDBMapper.getTableName());
|
|
|
|
|
|
|
|
addTemporalConstraintToQuery();
|
|
|
|
|
|
|
|
addFilters();
|
2021-03-17 17:55:56 +01:00
|
|
|
addContextFilter();
|
2021-03-16 15:33:34 +01:00
|
|
|
|
|
|
|
addGropuBy();
|
|
|
|
addOrderBy();
|
|
|
|
|
|
|
|
return stringBuffer.toString();
|
2021-03-17 17:55:56 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 15:33:34 +01:00
|
|
|
}
|