(improvement)(chat) dsl supports revision and fix queryDimensionValue performance (#188)

This commit is contained in:
mainmain
2023-10-10 21:28:42 +08:00
committed by GitHub
parent 3b1cbd4fd7
commit 278af3ce34
3 changed files with 89 additions and 34 deletions

View File

@@ -4,6 +4,10 @@ import lombok.Data;
@Data @Data
public class DimensionValueReq { public class DimensionValueReq {
private Integer agentId;
private Long elementID;
private Long modelId; private Long modelId;
private String bizName; private String bizName;

View File

@@ -16,9 +16,9 @@ import com.tencent.supersonic.chat.api.pojo.request.DimensionValueReq;
import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq; import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq;
import com.tencent.supersonic.chat.api.pojo.request.QueryReq; import com.tencent.supersonic.chat.api.pojo.request.QueryReq;
import com.tencent.supersonic.chat.api.pojo.request.SolvedQueryReq; import com.tencent.supersonic.chat.api.pojo.request.SolvedQueryReq;
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
import com.tencent.supersonic.chat.api.pojo.response.ParseResp; import com.tencent.supersonic.chat.api.pojo.response.ParseResp;
import com.tencent.supersonic.chat.api.pojo.response.QueryResult; import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
import com.tencent.supersonic.chat.parser.llm.dsl.DSLParseResult; import com.tencent.supersonic.chat.parser.llm.dsl.DSLParseResult;
import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO; import com.tencent.supersonic.chat.persistence.dataobject.ChatParseDO;
import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO; import com.tencent.supersonic.chat.persistence.dataobject.ChatQueryDO;
@@ -32,31 +32,39 @@ import com.tencent.supersonic.chat.responder.execute.ExecuteResponder;
import com.tencent.supersonic.chat.responder.parse.ParseResponder; import com.tencent.supersonic.chat.responder.parse.ParseResponder;
import com.tencent.supersonic.chat.service.ChatService; import com.tencent.supersonic.chat.service.ChatService;
import com.tencent.supersonic.chat.service.QueryService; import com.tencent.supersonic.chat.service.QueryService;
import com.tencent.supersonic.common.pojo.QueryColumn;
import com.tencent.supersonic.knowledge.dictionary.MapResult;
import com.tencent.supersonic.knowledge.service.SearchService;
import com.tencent.supersonic.chat.service.StatisticsService; import com.tencent.supersonic.chat.service.StatisticsService;
import com.tencent.supersonic.chat.utils.ComponentFactory; import com.tencent.supersonic.chat.utils.ComponentFactory;
import java.util.Map;
import com.tencent.supersonic.chat.utils.SolvedQueryManager;
import com.tencent.supersonic.common.util.jsqlparser.FilterExpression;
import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import java.util.HashMap;
import java.util.Comparator; import java.util.Comparator;
import java.util.Objects;
import com.tencent.supersonic.chat.utils.SolvedQueryManager;
import com.tencent.supersonic.semantic.api.model.response.ExplainResp;
import com.tencent.supersonic.common.util.jsqlparser.FilterExpression;
import com.tencent.supersonic.common.util.jsqlparser.SqlParserSelectHelper;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.DateConf; import com.tencent.supersonic.common.pojo.DateConf;
import com.tencent.supersonic.common.util.JsonUtil; import com.tencent.supersonic.common.util.JsonUtil;
import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper; import com.tencent.supersonic.common.util.jsqlparser.SqlParserUpdateHelper;
import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp; import com.tencent.supersonic.semantic.api.model.response.QueryResultWithSchemaResp;
import com.tencent.supersonic.semantic.api.query.enums.FilterOperatorEnum;
import com.tencent.supersonic.semantic.api.query.pojo.Filter;
import com.tencent.supersonic.semantic.api.query.request.QueryStructReq; import com.tencent.supersonic.semantic.api.query.request.QueryStructReq;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
@@ -75,6 +83,8 @@ public class QueryServiceImpl implements QueryService {
private StatisticsService statisticsService; private StatisticsService statisticsService;
@Autowired @Autowired
private SolvedQueryManager solvedQueryManager; private SolvedQueryManager solvedQueryManager;
@Autowired
private SearchService searchService;
@Value("${time.threshold: 100}") @Value("${time.threshold: 100}")
private Integer timeThreshold; private Integer timeThreshold;
@@ -264,6 +274,7 @@ public class QueryServiceImpl implements QueryService {
ChatParseDO chatParseDO = chatService.getParseInfo(queryData.getQueryId(), ChatParseDO chatParseDO = chatService.getParseInfo(queryData.getQueryId(),
queryData.getUser().getName(), queryData.getParseId()); queryData.getUser().getName(), queryData.getParseId());
SemanticParseInfo parseInfo = JsonUtil.toObject(chatParseDO.getParseInfo(), SemanticParseInfo.class); SemanticParseInfo parseInfo = JsonUtil.toObject(chatParseDO.getParseInfo(), SemanticParseInfo.class);
SemanticQuery semanticQuery = QueryManager.createQuery(parseInfo.getQueryMode());
if (!parseInfo.getQueryMode().equals(DslQuery.QUERY_MODE)) { if (!parseInfo.getQueryMode().equals(DslQuery.QUERY_MODE)) {
if (CollectionUtils.isNotEmpty(queryData.getDimensions())) { if (CollectionUtils.isNotEmpty(queryData.getDimensions())) {
parseInfo.setDimensions(queryData.getDimensions()); parseInfo.setDimensions(queryData.getDimensions());
@@ -291,24 +302,36 @@ public class QueryServiceImpl implements QueryService {
for (QueryFilter dslQueryFilter : queryData.getDimensionFilters()) { for (QueryFilter dslQueryFilter : queryData.getDimensionFilters()) {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
for (FilterExpression filterExpression : filterExpressionList) { for (FilterExpression filterExpression : filterExpressionList) {
if (filterExpression.getFieldName().equals(dslQueryFilter.getBizName()) if (filterExpression.getFieldName() != null
&& filterExpression.getFieldName().equals(dslQueryFilter.getName())
&& dslQueryFilter.getOperator().getValue().equals(filterExpression.getOperator())) { && dslQueryFilter.getOperator().getValue().equals(filterExpression.getOperator())) {
map.put(filterExpression.getFieldValue().toString(), dslQueryFilter.getValue().toString()); map.put(filterExpression.getFieldValue().toString(), dslQueryFilter.getValue().toString());
parseInfo.getDimensionFilters().stream().forEach(o -> {
if (o.getName().equals(dslQueryFilter.getName())) {
o.setValue(dslQueryFilter.getValue());
}
});
break; break;
} }
} }
filedNameToValueMap.put(dslQueryFilter.getBizName(), map); filedNameToValueMap.put(dslQueryFilter.getName(), map);
} }
for (QueryFilter dslQueryFilter : queryData.getMetricFilters()) { for (QueryFilter dslQueryFilter : queryData.getMetricFilters()) {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
for (FilterExpression filterExpression : filterExpressionList) { for (FilterExpression filterExpression : filterExpressionList) {
if (filterExpression.getFieldName().equals(dslQueryFilter.getBizName()) if (filterExpression.getFieldName() != null
&& filterExpression.getFieldName().equals(dslQueryFilter.getName())
&& dslQueryFilter.getOperator().getValue().equals(filterExpression.getOperator())) { && dslQueryFilter.getOperator().getValue().equals(filterExpression.getOperator())) {
map.put(filterExpression.getFieldValue().toString(), dslQueryFilter.getValue().toString()); map.put(filterExpression.getFieldValue().toString(), dslQueryFilter.getValue().toString());
parseInfo.getMetricFilters().stream().forEach(o -> {
if (o.getName().equals(dslQueryFilter.getName())) {
o.setValue(dslQueryFilter.getValue());
}
});
break; break;
} }
} }
filedNameToValueMap.put(dslQueryFilter.getBizName(), map); filedNameToValueMap.put(dslQueryFilter.getName(), map);
} }
String dateField = "sys_imp_date"; String dateField = "sys_imp_date";
if (Objects.nonNull(queryData.getDateInfo())) { if (Objects.nonNull(queryData.getDateInfo())) {
@@ -316,7 +339,8 @@ public class QueryServiceImpl implements QueryService {
List<String> dateFields = Lists.newArrayList("dayno", "sys_imp_date", "sys_imp_week", "sys_imp_month"); List<String> dateFields = Lists.newArrayList("dayno", "sys_imp_date", "sys_imp_week", "sys_imp_month");
if (queryData.getDateInfo().getStartDate().equals(queryData.getDateInfo().getEndDate())) { if (queryData.getDateInfo().getStartDate().equals(queryData.getDateInfo().getEndDate())) {
for (FilterExpression filterExpression : filterExpressionList) { for (FilterExpression filterExpression : filterExpressionList) {
if (dateFields.contains(filterExpression.getFieldName())) { if (filterExpression.getFieldName() != null
&& dateFields.contains(filterExpression.getFieldName())) {
dateField = filterExpression.getFieldName(); dateField = filterExpression.getFieldName();
map.put(filterExpression.getFieldValue().toString(), map.put(filterExpression.getFieldValue().toString(),
queryData.getDateInfo().getStartDate()); queryData.getDateInfo().getStartDate());
@@ -341,6 +365,7 @@ public class QueryServiceImpl implements QueryService {
} }
} }
filedNameToValueMap.put(dateField, map); filedNameToValueMap.put(dateField, map);
parseInfo.setDateInfo(queryData.getDateInfo());
} }
log.info("filedNameToValueMap:{}", filedNameToValueMap); log.info("filedNameToValueMap:{}", filedNameToValueMap);
correctorSql = SqlParserUpdateHelper.replaceValue(correctorSql, filedNameToValueMap); correctorSql = SqlParserUpdateHelper.replaceValue(correctorSql, filedNameToValueMap);
@@ -350,8 +375,13 @@ public class QueryServiceImpl implements QueryService {
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
properties.put(Constants.CONTEXT, dslParseResult); properties.put(Constants.CONTEXT, dslParseResult);
parseInfo.setProperties(properties); parseInfo.setProperties(properties);
parseInfo.getSqlInfo().setLogicSql(correctorSql);
semanticQuery.setParseInfo(parseInfo);
ExplainResp explain = semanticQuery.explain(user);
if (!Objects.isNull(explain)) {
parseInfo.getSqlInfo().setQuerySql(explain.getSql());
}
} }
SemanticQuery semanticQuery = QueryManager.createQuery(parseInfo.getQueryMode());
semanticQuery.setParseInfo(parseInfo); semanticQuery.setParseInfo(parseInfo);
QueryResult queryResult = semanticQuery.execute(user); QueryResult queryResult = semanticQuery.execute(user);
queryResult.setChatContext(semanticQuery.getParseInfo()); queryResult.setChatContext(semanticQuery.getParseInfo());
@@ -373,27 +403,47 @@ public class QueryServiceImpl implements QueryService {
List<String> groups = new ArrayList<>(); List<String> groups = new ArrayList<>();
groups.add(dimensionValueReq.getBizName()); groups.add(dimensionValueReq.getBizName());
queryStructReq.setGroups(groups); queryStructReq.setGroups(groups);
if (!Objects.isNull(dimensionValueReq.getValue())) { if ((!Objects.isNull(dimensionValueReq.getValue()))
List<Filter> dimensionFilters = new ArrayList<>(); && StringUtils.isNotBlank(dimensionValueReq.getValue().toString())) {
Filter dimensionFilter = new Filter(); return queryHanlpDimensionValue(dimensionValueReq, user);
dimensionFilter.setOperator(FilterOperatorEnum.LIKE);
dimensionFilter.setRelation(Filter.Relation.FILTER);
dimensionFilter.setBizName(dimensionValueReq.getBizName());
dimensionFilter.setValue(dimensionValueReq.getValue());
dimensionFilters.add(dimensionFilter);
queryStructReq.setDimensionFilters(dimensionFilters);
} }
SemanticInterpreter semanticInterpreter = ComponentFactory.getSemanticLayer(); SemanticInterpreter semanticInterpreter = ComponentFactory.getSemanticLayer();
QueryResultWithSchemaResp queryResultWithSchemaResp = semanticInterpreter.queryByStruct(queryStructReq, user); QueryResultWithSchemaResp queryResultWithSchemaResp = semanticInterpreter.queryByStruct(queryStructReq, user);
Set<String> dimensionValues = new HashSet<>(); return queryResultWithSchemaResp;
queryResultWithSchemaResp.getResultList().removeIf(o -> {
if (dimensionValues.contains(o.get(dimensionValueReq.getBizName()))) {
return true;
} else {
dimensionValues.add(o.get(dimensionValueReq.getBizName()).toString());
return false;
} }
public Object queryHanlpDimensionValue(DimensionValueReq dimensionValueReq, User user) throws Exception {
QueryResultWithSchemaResp queryResultWithSchemaResp = new QueryResultWithSchemaResp();
Set<Long> detectModelIds = new HashSet<>();
detectModelIds.add(dimensionValueReq.getModelId());
List<MapResult> mapResultList = SearchService.prefixSearch(dimensionValueReq.getValue().toString(),
2000, dimensionValueReq.getAgentId(), detectModelIds);
log.info("mapResultList:{}", mapResultList);
mapResultList = mapResultList.stream().filter(o -> {
for (String nature : o.getNatures()) {
String[] natureArray = nature.split("_");
if (natureArray[2].equals(dimensionValueReq.getElementID().toString())) {
return true;
}
}
return false;
}).collect(Collectors.toList());
log.info("mapResultList:{}", mapResultList);
List<QueryColumn> columns = new ArrayList<>();
QueryColumn queryColumn = new QueryColumn();
queryColumn.setNameEn(dimensionValueReq.getBizName());
queryColumn.setShowType("CATEGORY");
queryColumn.setAuthorized(true);
queryColumn.setType("CHAR");
columns.add(queryColumn);
List<Map<String, Object>> resultList = new ArrayList<>();
mapResultList.stream().forEach(o -> {
Map<String, Object> map = new HashMap<>();
map.put(dimensionValueReq.getBizName(), o.getName());
resultList.add(map);
}); });
queryResultWithSchemaResp.setColumns(columns);
queryResultWithSchemaResp.setResultList(resultList);
return queryResultWithSchemaResp; return queryResultWithSchemaResp;
} }

View File

@@ -17,13 +17,14 @@ import org.springframework.util.CollectionUtils;
public abstract class BaseSemanticInterpreter implements SemanticInterpreter { public abstract class BaseSemanticInterpreter implements SemanticInterpreter {
protected final Cache<String, List<ModelSchemaResp>> modelSchemaCache = protected final Cache<String, List<ModelSchemaResp>> modelSchemaCache =
CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); CacheBuilder.newBuilder().expireAfterWrite(60, TimeUnit.SECONDS).build();
@SneakyThrows @SneakyThrows
public List<ModelSchemaResp> fetchModelSchema(List<Long> ids, Boolean cacheEnable) { public List<ModelSchemaResp> fetchModelSchema(List<Long> ids, Boolean cacheEnable) {
if (cacheEnable) { if (cacheEnable) {
return modelSchemaCache.get(String.valueOf(ids), () -> { return modelSchemaCache.get(String.valueOf(ids), () -> {
List<ModelSchemaResp> data = doFetchModelSchema(ids); List<ModelSchemaResp> data = doFetchModelSchema(ids);
modelSchemaCache.put(String.valueOf(ids), data);
return data; return data;
}); });
} }