[improvement][headless]Introduce new time mode CURRENT. #1692

This commit is contained in:
jerryjzhang
2024-09-21 13:14:47 +08:00
parent 26ca5300f4
commit b6765387f5
7 changed files with 138 additions and 224 deletions

View File

@@ -1,95 +1,65 @@
package com.tencent.supersonic.headless.chat.corrector;
import com.tencent.supersonic.common.pojo.enums.DatePeriodEnum;
import com.tencent.supersonic.common.pojo.enums.QueryType;
import com.tencent.supersonic.common.pojo.enums.TimeMode;
import com.tencent.supersonic.common.util.DateUtils;
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
import com.tencent.supersonic.headless.api.pojo.TimeDefaultConfig;
import com.tencent.supersonic.headless.chat.ChatQueryContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
public class S2SqlDateHelper {
public static String getReferenceDate(ChatQueryContext chatQueryContext, Long dataSetId) {
String defaultDate = DateUtils.getBeforeDate(0);
if (Objects.isNull(dataSetId)) {
return defaultDate;
}
DataSetSchema dataSetSchema =
chatQueryContext.getSemanticSchema().getDataSetSchemaMap().get(dataSetId);
if (dataSetSchema == null || dataSetSchema.getTagTypeTimeDefaultConfig() == null) {
return defaultDate;
}
TimeDefaultConfig tagTypeTimeDefaultConfig = dataSetSchema.getTagTypeTimeDefaultConfig();
String partitionTimeFormat = dataSetSchema.getPartitionTimeFormat();
return getDefaultDate(defaultDate, tagTypeTimeDefaultConfig, partitionTimeFormat).getLeft();
public static Pair<String, String> calculateDateRange(
TimeDefaultConfig timeConfig, String timeFormat) {
return calculateDateRange(DateUtils.getBeforeDate(0), timeConfig, timeFormat);
}
public static Pair<String, String> getStartEndDate(
ChatQueryContext chatQueryContext, Long dataSetId, QueryType queryType) {
String defaultDate = DateUtils.getBeforeDate(0);
if (Objects.isNull(dataSetId)) {
return Pair.of(defaultDate, defaultDate);
}
DataSetSchema dataSetSchema =
chatQueryContext.getSemanticSchema().getDataSetSchemaMap().get(dataSetId);
if (Objects.isNull(dataSetSchema)) {
return Pair.of(defaultDate, defaultDate);
}
TimeDefaultConfig defaultConfig = dataSetSchema.getMetricTypeTimeDefaultConfig();
if (QueryType.DETAIL.equals(queryType) && defaultConfig.getUnit() >= 0) {
defaultConfig = dataSetSchema.getTagTypeTimeDefaultConfig();
}
String partitionTimeFormat = dataSetSchema.getPartitionTimeFormat();
return getDefaultDate(defaultDate, defaultConfig, partitionTimeFormat);
}
private static Pair<String, String> getDefaultDate(
String defaultDate, TimeDefaultConfig defaultConfig, String partitionTimeFormat) {
if (defaultConfig == null) {
return Pair.of(null, null);
}
Integer unit = defaultConfig.getUnit();
if (unit == null) {
return Pair.of(defaultDate, defaultDate);
}
// If the unit is set to less than 0, then do not add relative date.
if (unit < 0) {
public static Pair<String, String> calculateDateRange(
String currentDate, TimeDefaultConfig timeConfig, String timeFormat) {
Integer unit = timeConfig.getUnit();
if (timeConfig == null || unit == null || unit < 0) {
return Pair.of(null, null);
}
String period = defaultConfig.getPeriod();
TimeMode timeMode = defaultConfig.getTimeMode();
DatePeriodEnum datePeriodEnum = DatePeriodEnum.get(period);
String startDate = DateUtils.getBeforeDate(unit, datePeriodEnum);
String endDate = DateUtils.getBeforeDate(0, DatePeriodEnum.DAY);
if (unit == 0 || TimeMode.LAST.equals(timeMode)) {
endDate = startDate;
TimeMode timeMode = timeConfig.getTimeMode();
DatePeriodEnum datePeriod = DatePeriodEnum.get(timeConfig.getPeriod());
String startDate;
String endDate;
switch (timeMode) {
case CURRENT:
startDate = DateUtils.getBeforeDate(currentDate, datePeriod);
endDate = currentDate;
break;
case RECENT:
startDate = DateUtils.getBeforeDate(currentDate, unit, datePeriod);
endDate = currentDate;
break;
case LAST:
default:
startDate = DateUtils.getBeforeDate(currentDate, unit, datePeriod);
endDate = DateUtils.getBeforeDate(currentDate, unit, datePeriod);
break;
}
if (StringUtils.isNotBlank(partitionTimeFormat)) {
startDate = formatDate(startDate, partitionTimeFormat);
endDate = formatDate(endDate, partitionTimeFormat);
if (StringUtils.isNotBlank(timeFormat)) {
startDate = reformatDate(startDate, timeFormat);
endDate = reformatDate(endDate, timeFormat);
}
return Pair.of(startDate, endDate);
}
private static String formatDate(String dateStr, String format) {
private static String reformatDate(String dateStr, String format) {
try {
// Assuming the input date format is "yyyy-MM-dd"
SimpleDateFormat inputFormat = new SimpleDateFormat(DateUtils.DATE_FORMAT);
Date date = inputFormat.parse(dateStr);
SimpleDateFormat outputFormat = new SimpleDateFormat(format);
return outputFormat.format(date);
} catch (Exception e) {
} catch (ParseException e) {
// Handle the exception, maybe log it and return the original dateStr
return dateStr;
}

View File

@@ -4,9 +4,12 @@ import com.tencent.supersonic.common.jsqlparser.DateVisitor.DateBoundInfo;
import com.tencent.supersonic.common.jsqlparser.SqlAddHelper;
import com.tencent.supersonic.common.jsqlparser.SqlDateSelectHelper;
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
import com.tencent.supersonic.common.pojo.enums.QueryType;
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
import com.tencent.supersonic.headless.api.pojo.QueryConfig;
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
import com.tencent.supersonic.headless.api.pojo.TimeDefaultConfig;
import com.tencent.supersonic.headless.chat.ChatQueryContext;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
@@ -27,10 +30,10 @@ public class TimeCorrector extends BaseSemanticCorrector {
public void doCorrect(ChatQueryContext chatQueryContext, SemanticParseInfo semanticParseInfo) {
if (containsPartitionDimensions(chatQueryContext, semanticParseInfo)) {
addDateIfNotExist(chatQueryContext, semanticParseInfo);
addLowerBoundDate(semanticParseInfo);
} else {
removeDateIfExist(chatQueryContext, semanticParseInfo);
}
addLowerBoundDate(semanticParseInfo);
}
private void addDateIfNotExist(
@@ -48,15 +51,21 @@ public class TimeCorrector extends BaseSemanticCorrector {
}
String partitionDimension = dataSetSchema.getPartitionDimension().getName();
if (CollectionUtils.isEmpty(whereFields) || !whereFields.contains(partitionDimension)) {
Pair<String, String> startEndDate =
S2SqlDateHelper.getStartEndDate(
chatQueryContext, dataSetId, semanticParseInfo.getQueryType());
TimeDefaultConfig timeConfig;
QueryConfig queryConfig = dataSetSchema.getQueryConfig();
if (QueryType.METRIC.equals(semanticParseInfo.getQueryType())) {
timeConfig = queryConfig.getMetricTypeDefaultConfig().getTimeDefaultConfig();
} else {
timeConfig = queryConfig.getTagTypeDefaultConfig().getTimeDefaultConfig();
}
if (isValidDateRange(startEndDate)) {
String timeFormat = dataSetSchema.getPartitionTimeFormat();
Pair<String, String> dateRange =
S2SqlDateHelper.calculateDateRange(timeConfig, timeFormat);
if (isValidDateRange(dateRange)) {
correctS2SQL = SqlAddHelper.addParenthesisToWhere(correctS2SQL);
String startDateLeft = startEndDate.getLeft();
String endDateRight = startEndDate.getRight();
String startDateLeft = dateRange.getLeft();
String endDateRight = dateRange.getRight();
String condExpr =
String.format(
" ( %s >= '%s' and %s <= '%s' )",

View File

@@ -1,134 +1,79 @@
package com.tencent.supersonic.headless.chat.utils;
import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.enums.QueryType;
import com.tencent.supersonic.common.pojo.enums.TimeMode;
import com.tencent.supersonic.common.util.DateUtils;
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
import com.tencent.supersonic.headless.api.pojo.QueryConfig;
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
import com.tencent.supersonic.headless.api.pojo.SemanticSchema;
import com.tencent.supersonic.headless.api.pojo.TimeDefaultConfig;
import com.tencent.supersonic.headless.chat.ChatQueryContext;
import com.tencent.supersonic.headless.chat.corrector.S2SqlDateHelper;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Assert;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
@Disabled
class S2SqlDateHelperTest {
@Test
void getReferenceDate() {
Long dataSetId = 1L;
ChatQueryContext chatQueryContext = buildQueryContext(dataSetId);
String referenceDate = S2SqlDateHelper.getReferenceDate(chatQueryContext, null);
Assert.assertEquals(referenceDate, DateUtils.getBeforeDate(0));
referenceDate = S2SqlDateHelper.getReferenceDate(chatQueryContext, dataSetId);
Assert.assertEquals(referenceDate, DateUtils.getBeforeDate(0));
DataSetSchema dataSetSchema =
chatQueryContext.getSemanticSchema().getDataSetSchemaMap().get(dataSetId);
QueryConfig queryConfig = dataSetSchema.getQueryConfig();
void testCurrentTimeMode() {
TimeDefaultConfig timeDefaultConfig = new TimeDefaultConfig();
timeDefaultConfig.setTimeMode(TimeMode.LAST);
timeDefaultConfig.setPeriod(Constants.DAY);
timeDefaultConfig.setUnit(20);
queryConfig.getTagTypeDefaultConfig().setTimeDefaultConfig(timeDefaultConfig);
timeDefaultConfig.setTimeMode(TimeMode.CURRENT);
timeDefaultConfig.setPeriod(Constants.MONTH);
referenceDate = S2SqlDateHelper.getReferenceDate(chatQueryContext, dataSetId);
Assert.assertEquals(referenceDate, DateUtils.getBeforeDate(20));
Pair<String, String> dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-09-01");
assert dateRange.getRight().equals("2024-09-21");
timeDefaultConfig.setUnit(1);
referenceDate = S2SqlDateHelper.getReferenceDate(chatQueryContext, dataSetId);
Assert.assertEquals(referenceDate, DateUtils.getBeforeDate(1));
timeDefaultConfig.setUnit(-1);
referenceDate = S2SqlDateHelper.getReferenceDate(chatQueryContext, dataSetId);
Assert.assertNull(referenceDate);
timeDefaultConfig.setPeriod(Constants.YEAR);
dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-01-01");
assert dateRange.getRight().equals("2024-09-21");
}
@Test
void getStartEndDate() {
Long dataSetId = 1L;
ChatQueryContext chatQueryContext = buildQueryContext(dataSetId);
void testRecentTimeMode() {
TimeDefaultConfig timeDefaultConfig = new TimeDefaultConfig();
timeDefaultConfig.setTimeMode(TimeMode.RECENT);
timeDefaultConfig.setUnit(3);
timeDefaultConfig.setPeriod(Constants.DAY);
Pair<String, String> startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, null, QueryType.DETAIL);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(0));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(0));
Pair<String, String> dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-09-18");
assert dateRange.getRight().equals("2024-09-21");
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.DETAIL);
Assert.assertNotNull(startEndDate.getLeft());
Assert.assertNotNull(startEndDate.getRight());
timeDefaultConfig.setPeriod(Constants.MONTH);
dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-06-21");
assert dateRange.getRight().equals("2024-09-21");
DataSetSchema dataSetSchema =
chatQueryContext.getSemanticSchema().getDataSetSchemaMap().get(dataSetId);
QueryConfig queryConfig = dataSetSchema.getQueryConfig();
timeDefaultConfig.setPeriod(Constants.YEAR);
dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2021-09-21");
assert dateRange.getRight().equals("2024-09-21");
}
@Test
void testLastTimeMode() {
TimeDefaultConfig timeDefaultConfig = new TimeDefaultConfig();
timeDefaultConfig.setTimeMode(TimeMode.LAST);
timeDefaultConfig.setUnit(3);
timeDefaultConfig.setPeriod(Constants.DAY);
timeDefaultConfig.setUnit(20);
queryConfig.getTagTypeDefaultConfig().setTimeDefaultConfig(timeDefaultConfig);
queryConfig.getMetricTypeDefaultConfig().setTimeDefaultConfig(timeDefaultConfig);
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.DETAIL);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(20));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(20));
Pair<String, String> dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-09-18");
assert dateRange.getRight().equals("2024-09-18");
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.METRIC);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(20));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(20));
timeDefaultConfig.setPeriod(Constants.MONTH);
dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2024-06-21");
assert dateRange.getRight().equals("2024-06-21");
timeDefaultConfig.setUnit(2);
timeDefaultConfig.setTimeMode(TimeMode.RECENT);
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.METRIC);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(2));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(1));
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.DETAIL);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(2));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(1));
timeDefaultConfig.setUnit(-1);
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.METRIC);
Assert.assertNull(startEndDate.getLeft());
Assert.assertNull(startEndDate.getRight());
timeDefaultConfig.setTimeMode(TimeMode.LAST);
timeDefaultConfig.setPeriod(Constants.DAY);
timeDefaultConfig.setUnit(5);
startEndDate =
S2SqlDateHelper.getStartEndDate(chatQueryContext, dataSetId, QueryType.METRIC);
Assert.assertEquals(startEndDate.getLeft(), DateUtils.getBeforeDate(5));
Assert.assertEquals(startEndDate.getRight(), DateUtils.getBeforeDate(5));
}
private ChatQueryContext buildQueryContext(Long dataSetId) {
ChatQueryContext chatQueryContext = new ChatQueryContext();
List<DataSetSchema> dataSetSchemaList = new ArrayList<>();
DataSetSchema dataSetSchema = new DataSetSchema();
QueryConfig queryConfig = new QueryConfig();
dataSetSchema.setQueryConfig(queryConfig);
SchemaElement schemaElement = new SchemaElement();
schemaElement.setDataSetId(dataSetId);
dataSetSchema.setDataSet(schemaElement);
dataSetSchemaList.add(dataSetSchema);
SemanticSchema semanticSchema = new SemanticSchema(dataSetSchemaList);
chatQueryContext.setSemanticSchema(semanticSchema);
return chatQueryContext;
timeDefaultConfig.setPeriod(Constants.YEAR);
dateRange =
S2SqlDateHelper.calculateDateRange("2024-09-21", timeDefaultConfig, "yyyy-MM-dd");
assert dateRange.getLeft().equals("2021-09-21");
assert dateRange.getRight().equals("2021-09-21");
}
}