package com.smtaiserver.smtaiserver.javaai.qwen.agent;
|
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.Iterator;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.TreeMap;
|
import java.util.Map.Entry;
|
|
import org.apache.commons.text.similarity.JaccardSimilarity;
|
import org.apache.log4j.LogManager;
|
import org.apache.log4j.Logger;
|
import org.dom4j.Document;
|
import org.dom4j.Element;
|
import org.dom4j.Node;
|
import org.dom4j.tree.DefaultText;
|
import org.duckdb.DuckDBAppender;
|
import org.duckdb.DuckDBConnection;
|
|
import com.smtaiserver.smtaiserver.core.SMTAIServerApp;
|
import com.smtaiserver.smtaiserver.core.SMTAIServerRequest;
|
import com.smtaiserver.smtaiserver.database.SMTDatabase;
|
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecord;
|
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords;
|
import com.smtaiserver.smtaiserver.javaai.SMTJavaAIError;
|
import com.smtaiserver.smtaiserver.javaai.ast.ASTDBMap;
|
import com.smtaiserver.smtaiserver.javaai.duckdb.DuckCubeRecs;
|
import com.smtaiserver.smtaiserver.javaai.duckdb.DuckCubeRecs.DuckCubeColTitle;
|
import com.smtaiserver.smtaiserver.javaai.duckdb.DuckCubeRecs.DuckCubeRecsType;
|
import com.smtaiserver.smtaiserver.javaai.duckdb.DuckMergeResult;
|
import com.smtaiserver.smtaiserver.javaai.duckdb.DuckResult;
|
import com.smtaiserver.smtaiserver.javaai.llm.core.SMTLLMConnect;
|
import com.smtaiserver.smtaiserver.javaai.metrics.base.SMTDimensionDef;
|
import com.smtaiserver.smtaiserver.javaai.metrics.base.SMTDuckTimeGroupName;
|
import com.smtaiserver.smtaiserver.javaai.metrics.base.SMTMetricsDef;
|
import com.smtservlet.util.Json;
|
import com.smtservlet.util.SMTJsonWriter;
|
import com.smtservlet.util.SMTStatic;
|
|
public class SMTQwenAgentDuckMetric extends SMTQwenAgent
|
{
|
//////////////////////////////////////////////////////////////////
|
private boolean _questionToStep = false;
|
private String _promptVPROP;
|
private List<String> _metricsAlisList = new ArrayList<>();
|
private static Map<String, String[]> _mapGroupType2Match = new HashMap<>();
|
private static Map<String, String[]> _mapDiffType2Match = new HashMap<>();
|
private static Logger _logger = LogManager.getLogger(SMTQwenAgentDuckMetric.class);
|
|
static
|
{
|
_mapGroupType2Match.put("AVG", new String[]{"平均值", "平均", "AVG","实时"});
|
_mapGroupType2Match.put("SUM", new String[]{"累计值", "累计", "SUM","求和", "总和", "总累计"});
|
_mapGroupType2Match.put("MAX", new String[]{"最大值", "最大", "MAX", "max"});
|
_mapGroupType2Match.put("MIN", new String[]{"最小值", "最小", "MIN", "min"});
|
_mapGroupType2Match.put("COUNT", new String[]{"个数", "COUNT", "count"});
|
|
_mapDiffType2Match.put("ADD", new String[]{"求和", "ADD","相加", "累计", "总和", "总累计"});
|
_mapDiffType2Match.put("SUB", new String[]{"求差", "SUB","相减", "差值"});
|
_mapDiffType2Match.put("YOY", new String[]{"同比", "YOY"});
|
_mapDiffType2Match.put("MOM", new String[]{"环比", "MOM"});
|
}
|
|
private String getDimNameList() throws Exception
|
{
|
Set<String> setExistDim = new HashSet<>();
|
StringBuilder sbResult = new StringBuilder();
|
Map<String, SMTMetricsDef> mapId2Metrics = SMTAIServerApp.getApp().getMetricsMap(this.getAgentId());
|
for(SMTMetricsDef metricsDef : mapId2Metrics.values())
|
{
|
Map<String, SMTDimensionDef> mapId2DimDef = metricsDef.getDimensionMap();
|
if(mapId2DimDef == null)
|
continue;
|
|
for(SMTDimensionDef dimDef : mapId2DimDef.values())
|
{
|
if(setExistDim.contains(dimDef.getId()))
|
continue;
|
setExistDim.add(dimDef.getId());
|
sbResult.append(" " + dimDef.getId() + ":" + dimDef.getPrompt() + "\n");
|
}
|
}
|
|
return sbResult.toString();
|
}
|
|
@Override
|
public SMTJavaAIError callSupervisorJson(String agentId, String jsonPath, Json jsonAST, SMTAIServerRequest tranReq) throws Exception
|
{
|
tranReq.traceLLMDebug("callAgents:[\n" + SMTStatic.formatJson(jsonAST) + "\n]");
|
|
SMTJsonWriter jsonWrResult = tranReq.getResultJsonWr();
|
jsonWrResult.addKeyValue("answer_type", "summary");
|
jsonWrResult.beginArray("summary");
|
SMTJavaAIError aiError = queryRecordByAST(jsonPath, jsonAST.asJsonList(), tranReq);
|
jsonWrResult.endArray();
|
|
return aiError;
|
}
|
|
private String getMetricsAliasList() throws Exception
|
{
|
Set<String> setAlias = new HashSet<>();
|
StringBuilder sbResult = new StringBuilder();
|
Map<String, SMTMetricsDef> mapId2Metrics = SMTAIServerApp.getApp().getMetricsMap(this.getAgentId());
|
for(SMTMetricsDef metricsDef : mapId2Metrics.values())
|
{
|
metricsDef.addMetricsAliasToSet(setAlias);
|
}
|
|
for(String alias : setAlias)
|
{
|
sbResult.append(alias + "\n");
|
}
|
|
return sbResult.toString();
|
}
|
|
private String replacePromptSectionDefine(Node nodeFunction, String key, String value) throws Exception
|
{
|
for(Node nodeDefine : nodeFunction.selectNodes("DEFINE"))
|
{
|
String id = SMTStatic.getXmlAttr((Element)nodeDefine, "id");
|
value = value.replace("{{{" + id + "}}}" , ((Element)nodeDefine).getText());
|
}
|
|
if(value.indexOf("{{{") >= 0)
|
throw new Exception("undefine macro : " + nodeFunction.getName() + " : " + key + "\n" + value);
|
|
return value;
|
}
|
|
private void loadPromptSection(Element xmlPromptSection) throws Exception
|
{
|
StringBuilder sbPrompt = new StringBuilder();
|
for (Iterator<Node> iterInner = xmlPromptSection.nodeIterator(); iterInner.hasNext();)
|
{
|
Node nodeInner = iterInner.next();
|
if(nodeInner.getNodeType() == Node.TEXT_NODE)
|
{
|
String text = ((DefaultText)nodeInner).getText();
|
sbPrompt.append(text);
|
}
|
else if(nodeInner.getNodeType() == Node.ELEMENT_NODE)
|
{
|
Element xmlInner = (Element)nodeInner;
|
|
String name = xmlInner.getName().toUpperCase();
|
if("CONFIG".equals(name))
|
{
|
String key = SMTStatic.getXmlAttr(xmlInner, "key");
|
String value = (String) SMTAIServerApp.getApp().getGlobalConfig(key);
|
value = replacePromptSectionDefine(xmlInner, key, value);
|
sbPrompt.append(value);
|
}
|
else if("DIM_NAME_LIST".equals(name))
|
{
|
sbPrompt.append("以下是可用于函数调用参数的维度列表:\n" + getDimNameList());
|
}
|
else if("METRICS_NAME_LIST".equals(name))
|
{
|
sbPrompt.append("以下是可用于解析的指标列表::\n" + getMetricsAliasList());
|
}
|
else if("FUNCTION_LIST".equals(name))
|
{
|
sbPrompt.append("以下是可以用于解析语法树的函数,请在这些函数中选择需要的操作,禁止捏造不存在的函数\n");
|
for(Node nodeFunction : xmlInner.selectNodes("FUNCTION"))
|
{
|
String key = SMTStatic.getXmlAttr((Element)nodeFunction, "name");
|
if(!key.startsWith("prompt_section"))
|
key = "prompt_section.function." + key;
|
String value = (String) SMTAIServerApp.getApp().getGlobalConfig(key);
|
|
value = replacePromptSectionDefine(nodeFunction, key, value);
|
|
sbPrompt.append(value + "\n");
|
}
|
}
|
else if("SAMPLE_LIST".equals(name))
|
{
|
sbPrompt.append("以下是语法树例子:\n");
|
for(Node nodeSample : xmlInner.selectNodes("SAMPLE"))
|
{
|
String key = SMTStatic.getXmlAttr((Element)nodeSample, "name");
|
if(!key.startsWith("prompt_section"))
|
key = "prompt_section.sample." + key;
|
String value = (String) SMTAIServerApp.getApp().getGlobalConfig(key);
|
|
value = replacePromptSectionDefine(nodeSample, key, value);
|
|
sbPrompt.append(value + "\n");
|
}
|
}
|
else
|
{
|
throw new Exception("unknow PROPMT_SECTION : " + name);
|
}
|
}
|
}
|
|
_promptVPROP = sbPrompt.toString();
|
_logger.info("prompt for metric : " + this.getAgentId() + "[\n" + sbPrompt.toString() + "\n]\n");
|
}
|
|
@Override
|
public void initInstance(DBRecord rec) throws Exception
|
{
|
super.initInstance(rec);
|
|
try
|
{
|
Document doc = SMTStatic.convStrToXmlDoc("<ROOT>" + rec.getString("clz_arguments") + "</ROOT>");
|
|
|
Element xmlPromptSection = (Element)doc.selectSingleNode("ROOT/PROMPT_SECTION");
|
if(xmlPromptSection != null)
|
{
|
loadPromptSection(xmlPromptSection);
|
}
|
else
|
{
|
Element xmlPrompt = (Element)doc.selectSingleNode("ROOT/PROMPT");
|
if(xmlPrompt != null)
|
{
|
_questionToStep = "true".equals(SMTStatic.getXmlAttr(xmlPrompt, "question_to_step", "false"));
|
|
_promptVPROP = SMTStatic.trimStrLines(xmlPrompt.getText())
|
.replace("{{{DIM_NAME_LIST}}}", getDimNameList())
|
.replace("{{{METRICS_NAME_LIST}}}", getMetricsAliasList())
|
;
|
}
|
else
|
{
|
throw new Exception("agent can't find PROMPT or PROMPT_SECTION : " + this.getAgentId());
|
}
|
}
|
|
|
|
Node nodeMetricsAlias = doc.selectSingleNode("ROOT/METRICS_ALIAS");
|
if(nodeMetricsAlias != null)
|
{
|
String sMetricsAlias = SMTStatic.getXmlAttr((Element)nodeMetricsAlias, "names");
|
if(!SMTStatic.isNullOrEmpty(sMetricsAlias))
|
{
|
for(String s : sMetricsAlias.split(","))
|
{
|
_metricsAlisList.add(s);
|
}
|
}
|
}
|
}
|
catch(Exception ex)
|
{
|
throw new Exception("init mertic agent error : " + this._agentId, ex);
|
}
|
}
|
|
private void replaceRefAstJson(Json jsonASTItem, Map<String, Json> mapId2JsonRef)
|
{
|
if(jsonASTItem.isArray())
|
{
|
for(Json jsonASTSubItem : jsonASTItem.asJsonList())
|
{
|
replaceRefAstJson(jsonASTSubItem, mapId2JsonRef);
|
}
|
}
|
else if(jsonASTItem.isObject())
|
{
|
for(Entry<String, Json> entry : jsonASTItem.asJsonMap().entrySet())
|
{
|
String key = entry.getKey();
|
if(("recordset".equals(key) || "recordset1".equals(key) || "recordset2".equals(key)) && entry.getValue().isString())
|
{
|
String refId = entry.getValue().asString();
|
Json jsonRef = mapId2JsonRef.get(refId);
|
if(jsonRef != null)
|
{
|
jsonASTItem.set(key, jsonRef);
|
}
|
}
|
else
|
{
|
replaceRefAstJson(entry.getValue(), mapId2JsonRef);
|
}
|
}
|
}
|
}
|
|
private Json mergeRefAstJson(Json jsonAST)
|
{
|
if(!jsonAST.isArray())
|
return jsonAST;
|
|
// 将输出列表和引用列表分离出来
|
List<Json> listJsonOutput = new ArrayList<>();
|
Map<String, Json> mapId2JsonRef = new HashMap<>();
|
for(Json jsonASTItem : jsonAST.asJsonList())
|
{
|
if(jsonASTItem.getJson("args").safeGetBoolean("is_output", true))
|
{
|
listJsonOutput.add(jsonASTItem);
|
}
|
String refId = jsonASTItem.safeGetStr("ref_id", null);
|
if(!SMTStatic.isNullOrEmpty(refId))
|
{
|
mapId2JsonRef.put(refId, jsonASTItem);
|
}
|
}
|
|
// 将引用替换成实体json
|
for(Json jsonASTItem : jsonAST.asJsonList())
|
{
|
replaceRefAstJson(jsonASTItem, mapId2JsonRef);
|
}
|
|
return Json.array(listJsonOutput.toArray(new Object[listJsonOutput.size()]));
|
}
|
|
@Override
|
public SMTJavaAIError callAgents(String jsonPath, Json jsonArgs, SMTLLMConnect llm, String question, SMTAIServerRequest tranReq) throws Exception
|
{
|
long tick = System.currentTimeMillis();
|
|
// 如果发生要把问题变成步骤,调用大模型
|
if(_questionToStep)
|
{
|
tranReq.sendChunkedBlock("begin", "将问题拆解成步骤");
|
String promptToStep = (String)SMTAIServerApp.getApp().getGlobalConfig("prompt.question_to_step");
|
question = llm.callWithMessage(new String[] {promptToStep}, question, tranReq).replace("\r", "");
|
tranReq.traceLLMDebug("questionToStep:[\n" + question + "\n]");
|
tranReq.traceLLMPrompt(promptToStep);
|
tranReq.sendChunkedBlock("end", "拆解后的步骤是:" + question.replace("\r", "").replace("\n", " "));
|
}
|
|
tranReq.traceLLMPrompt(_promptVPROP);
|
boolean set = tranReq.setSendStarStream(true);
|
Json jsonAST;
|
try
|
{
|
String answer = llm.callWithMessage(new String[] {_promptVPROP}, question, tranReq).replace("\r", "");
|
jsonAST = SMTStatic.convLLMAnswerToJson(answer, true);
|
jsonAST = mergeRefAstJson(jsonAST);
|
}
|
finally
|
{
|
tranReq.setSendStarStream(set);
|
}
|
|
if(jsonAST.isArray())
|
{
|
for(Json jsonASTItem : jsonAST.asJsonList())
|
{
|
if(jsonASTItem.isObject())
|
{
|
jsonASTItem.set("agent_id", this.getAgentId());
|
}
|
}
|
}
|
|
tranReq.appendCallFuncJson(jsonPath, jsonAST);
|
tranReq.traceLLMDebug("callAgents:[" + ((double)(System.currentTimeMillis() - tick) / 1000) + "秒] [\n" + SMTStatic.formatJson(jsonAST) + "\n]");
|
|
if(jsonAST.isObject())
|
{
|
String error = jsonAST.safeGetStr("error", "未知错误:" + jsonAST.toString());
|
return this.queryUnknowQuestion(error, llm, question, tranReq);
|
|
}
|
else if(!jsonAST.isArray())
|
{
|
String error = "未知错误:" + jsonAST.asString();
|
return this.queryUnknowQuestion(error, llm, question, tranReq);
|
}
|
|
return this.callAgentsByAST(jsonPath, jsonArgs, jsonAST, tranReq);
|
}
|
|
public SMTJavaAIError callAgentsByAST(String jsonPath, Json jsonArgs, Json jsonAST, SMTAIServerRequest tranReq) throws Exception
|
{
|
SMTJsonWriter jsonWrResult = tranReq.getResultJsonWr();
|
jsonWrResult.addKeyValue("answer_type", "summary");
|
jsonWrResult.beginArray("summary");
|
SMTJavaAIError aiError = queryRecordByAST(jsonPath, jsonAST.asJsonList(), tranReq);
|
jsonWrResult.endArray();
|
|
return aiError;
|
}
|
|
private SMTJavaAIError queryRecordByAST(String jsonPath, List<Json> jsonASTList, SMTAIServerRequest tranReq) throws Exception
|
{
|
ASTDBMap dbMap = new ASTDBMap();
|
try
|
{
|
DuckResult astResult = new DuckResult();
|
|
// 解析所有语法树
|
boolean existAST = false;
|
int count = jsonASTList.size();
|
for(int jsonIdx = 0; jsonIdx < count; jsonIdx ++)
|
{
|
Json jsonAST = jsonASTList.get(jsonIdx);
|
|
// 如果当前is_output = false
|
if(!jsonAST.getJson("args").safeGetBoolean("is_output", true))
|
{
|
// 如果已经存在执行器,则忽略
|
if(existAST)
|
continue;
|
|
// 如果当前执行器不是最后一个,则跳过
|
if(jsonIdx < (count -1))
|
continue;
|
}
|
|
|
existAST = true;
|
|
// 如果发现语法树报错,则直接返回错误
|
{
|
String error;
|
error = jsonAST.safeGetStr("error", null);
|
if(!SMTStatic.isNullOrEmpty(error))
|
return new SMTJavaAIError(error);
|
}
|
|
// 解析语法树
|
DuckResult curAstResult = new DuckResult();
|
SMTJavaAIError error = queryRecordAST2SQLTree("#" + SMTStatic.toString(jsonIdx) + "/", dbMap, jsonAST, null, tranReq, curAstResult);
|
if(error != null)
|
return error;
|
|
for(DuckCubeRecs cubeRecs : curAstResult._listRecordset)
|
{
|
astResult._listRecordset.add(cubeRecs);
|
}
|
}
|
|
// 合并输出结果
|
DuckMergeResult mergeResult = new DuckMergeResult();
|
mergeResult.outputResultToJson(jsonPath, astResult, tranReq);
|
|
}
|
finally
|
{
|
dbMap.close();
|
}
|
|
return null;
|
}
|
|
private SMTJavaAIError call_query_base_info(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
SMTJavaAIError error = null;
|
|
String metricsId = jsonAST.safeGetStr("metrics", null);
|
|
|
SMTMetricsDef metricsDef = null;
|
|
// 如果未配置指标,则取出第一个指标,且本配置只需要一个指标
|
if(SMTStatic.isNullOrEmpty(metricsId))
|
{
|
Map<String, SMTMetricsDef> mapId2Metrics = SMTAIServerApp.getApp().getMetricsMap(this.getAgentId());
|
|
if(mapId2Metrics.size() != 1)
|
throw new Exception("call_query_base_info only one metrics : " + this.getAgentId());
|
|
for(SMTMetricsDef curMetricsDef : mapId2Metrics.values())
|
{
|
metricsDef = curMetricsDef;
|
break;
|
}
|
}
|
else
|
{
|
metricsDef = queryMetricsType(metricsId);
|
if(metricsDef == null)
|
return new SMTJavaAIError("未发现指标:" + metricsId);
|
}
|
|
if((error = metricsDef.queryMetrics(jsonPath, dbMap, jsonAST, extArg, tranReq, r_result)) != null)
|
return error;
|
|
return null;
|
}
|
|
private String[] matchGroupType(String operate, Map<String, String[]> mapGroupType2Match)
|
{
|
JaccardSimilarity jaccardSimilarity = new JaccardSimilarity();
|
|
String maxTitle = null;
|
String maxKey = null;
|
double maxMatch = 0;
|
for(Entry<String, String[]> entry : mapGroupType2Match.entrySet())
|
{
|
String curKey = entry.getKey();
|
for(String line : entry.getValue())
|
{
|
double curMatch = jaccardSimilarity.apply(line, operate);
|
if(curMatch == 1)
|
{
|
return new String[] {curKey, entry.getValue()[0]};
|
}
|
if(curMatch >= 0.8 && curMatch > maxMatch)
|
{
|
maxKey = curKey;
|
maxTitle = entry.getValue()[0];
|
maxMatch = curMatch;
|
}
|
}
|
}
|
|
if(maxKey == null)
|
return null;
|
|
return new String[] {maxKey, maxTitle};
|
}
|
|
|
private SMTMetricsDef queryMetricsType(String metricsName) throws Exception
|
{
|
double minSimValue = SMTStatic.toDouble(SMTAIServerApp.getApp().getGlobalConfig("history.math.ratio"));
|
|
// 匹配指标定义
|
double maxSim = 0;
|
SMTMetricsDef matchMetrics = null;
|
TreeMap<Double, SMTMetricsDef> mapSim2Metrics = new TreeMap<>();
|
Map<String, SMTMetricsDef> mapId2Metrics = SMTAIServerApp.getApp().getMetricsMap(this.getAgentId());
|
JaccardSimilarity jaccardSimilarity = new JaccardSimilarity();
|
for(SMTMetricsDef metricsDef : mapId2Metrics.values())
|
{
|
double curSim = metricsDef.matchMetrics(metricsName, jaccardSimilarity);
|
if(curSim == 1)
|
{
|
maxSim = 1;
|
matchMetrics = metricsDef;
|
break;
|
}
|
else if(curSim >= minSimValue)
|
{
|
if(maxSim <= curSim)
|
{
|
maxSim = curSim;
|
matchMetrics = metricsDef;
|
}
|
}
|
|
mapSim2Metrics.put(curSim, metricsDef);
|
}
|
|
if(maxSim < minSimValue)
|
return null;
|
|
return matchMetrics;
|
}
|
|
private Object queryMetricsType(ASTDBMap dbMap, Json jsonAST, SMTAIServerRequest tranReq) throws Exception
|
{
|
|
// 从参数中获取用户输入的指标类型
|
String metricsName = jsonAST.safeGetStr("metrics", "");
|
if(SMTStatic.isNullOrEmpty(metricsName))
|
{
|
for(String metricsAilas : _metricsAlisList)
|
{
|
metricsName = jsonAST.safeGetStr(metricsAilas, "");
|
if(!SMTStatic.isNullOrEmpty(metricsName))
|
{
|
SMTDimensionDef dimDef = SMTAIServerApp.getApp().getDimensionDef(metricsAilas);
|
if(dimDef == null)
|
continue;
|
JaccardSimilarity jaccardSimilarity = new JaccardSimilarity();
|
metricsName = dimDef.matchDimension(metricsName, jaccardSimilarity);
|
if(metricsName == null)
|
continue;
|
break;
|
}
|
}
|
|
if(SMTStatic.isNullOrEmpty(metricsName))
|
return new SMTJavaAIError("未解析出指标信息");
|
}
|
|
SMTMetricsDef metricsDef = queryMetricsType(metricsName);
|
if(metricsDef != null)
|
return metricsDef;
|
|
if(metricsName.startsWith("监测") && jsonAST.has("device"))
|
{
|
metricsName = jsonAST.getJson("device").asString() + jsonAST.safeGetStr("metrics", "");
|
metricsDef = queryMetricsType(metricsName);
|
}
|
|
if(metricsDef != null)
|
return metricsDef;
|
|
return new SMTJavaAIError("未找到匹配的指标:" + metricsName);
|
}
|
|
|
private SMTJavaAIError call_query_metrics(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
// 获取指标对象
|
Object oMetrics = queryMetricsType(dbMap, jsonAST, tranReq);
|
if(oMetrics instanceof SMTJavaAIError)
|
return (SMTJavaAIError)oMetrics;
|
SMTMetricsDef matchMetrics = (SMTMetricsDef)oMetrics;
|
SMTJavaAIError error = matchMetrics.queryMetrics(jsonPath, dbMap, jsonAST, extArg, tranReq, r_result);
|
return error;
|
}
|
|
private SMTJavaAIError call_query_only_metrics(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
// 获取指标对象
|
SMTMetricsDef matchMetrics = null;
|
Map<String, SMTMetricsDef> mapId2Metrics = SMTAIServerApp.getApp().getMetricsMap(this.getAgentId());
|
for(SMTMetricsDef curMatchMetrics : mapId2Metrics.values())
|
{
|
matchMetrics = curMatchMetrics;
|
break;
|
}
|
|
SMTJavaAIError error = matchMetrics.queryMetrics(jsonPath, dbMap, jsonAST, extArg, tranReq, r_result);
|
return error;
|
}
|
|
private SMTJavaAIError call_diff_metrics_VALUE(DuckCubeRecs astCubeRecs1, DuckCubeRecs astCubeRecs2, String[] operate, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
// 创建结果记录集,并将结果记录集和原始记录集都加入
|
DuckCubeRecs diffRecs = astCubeRecs1.cloneCubeRecs();
|
r_result._listRecordset.add(diffRecs);
|
r_result._listRecordset.add(astCubeRecs1);
|
r_result._listRecordset.add(astCubeRecs2);
|
astCubeRecs1._isRawRS = true;
|
astCubeRecs2._isRawRS = true;
|
|
// 修改结果的标题和表名
|
diffRecs._title = diffRecs._title + operate[1];
|
diffRecs._tableName = "t_" + SMTStatic.newUUID();
|
|
// 将第二个结果集时间作为time2,前端可以作为第二个对比的过滤条件
|
diffRecs._timeRange.copyToTimeRange2(astCubeRecs2._timeRange);
|
|
// 计算时间差
|
String subTimeSQL = "";
|
String subUnit = "minutes";
|
long subValue = (astCubeRecs1._timeRange._startTime.getTime() - astCubeRecs2._timeRange._startTime.getTime()) / 1000 / 60;
|
if(subValue != 0)
|
{
|
if((subValue % 60) == 0)
|
{
|
subValue /= 60;
|
subUnit = "hours";
|
|
if((subValue % 24) == 0)
|
{
|
subValue /= 24;
|
subUnit = "days";
|
}
|
}
|
|
subTimeSQL = " + '" + subValue + " " + subUnit + "'";
|
}
|
|
|
// 生成查询SQL
|
String colTime1 = astCubeRecs1._timeRange._timeField;
|
String colTime2 = astCubeRecs2._timeRange._timeField;
|
String colValue1 = astCubeRecs1._timeRange._valueField;
|
String colValue2 = astCubeRecs2._timeRange._valueField;
|
|
StringBuilder sbSQL = new StringBuilder();
|
sbSQL.append("SELECT T1 AS " + colTime1 + ", (");
|
if("ADD".equals(operate[0]))
|
{
|
sbSQL.append("V1 + V2");
|
}
|
else if("SUB".equals(operate[0]))
|
{
|
sbSQL.append("V1 - V2");
|
}
|
else if("YOY".equals(operate[0]))
|
{
|
sbSQL.append("CASE WHEN V2 <> 0 THEN (V1 - V2) / V2 ELSE 0 END");
|
}
|
else if("MOM".equals(operate[0]))
|
{
|
sbSQL.append("CASE WHEN V2 <> 0 THEN (V1 - V2) / V2 ELSE 0 END");
|
}
|
else
|
throw new Exception("未支持的差分:" + operate[1]);
|
sbSQL.append(") AS " + colValue1);
|
sbSQL.append(" FROM (SELECT " + colTime1 + " AS T1, " + colValue1 + " AS V1 FROM " + astCubeRecs1._tableName + ") TT1");
|
sbSQL.append(" INNER JOIN (SELECT (" + colTime2 + subTimeSQL + ") AS T2, " + colValue2 + " AS V2 FROM " + astCubeRecs2._tableName + ") TT2");
|
sbSQL.append(" ON T1=T2");
|
|
tranReq.traceLLMDebug("\n" + sbSQL.toString());
|
|
// 执行查询,并将结果导入新的结果集
|
SMTDatabase dbResult = tranReq.getResultDB();
|
DuckDBAppender[] appender = new DuckDBAppender[1];
|
try
|
{
|
dbResult.querySQLNotify(sbSQL.toString(), null, new SMTDatabase.DBQueryNotifyMeta()
|
{
|
@Override
|
public boolean onMetaInfo(DBRecords metaInfo, String[] colTypes) throws Exception
|
{
|
SMTDatabase dbResult = tranReq.createResultTable(diffRecs._tableName, metaInfo, colTypes);
|
appender[0] = ((DuckDBConnection)dbResult.getConnection()).createAppender(DuckDBConnection.DEFAULT_SCHEMA, diffRecs._tableName);
|
return true;
|
|
}
|
|
@Override
|
public boolean onNextRecord(DBRecord rec) throws Exception
|
{
|
Object[] values = rec.getValues();
|
appender[0].beginRow();
|
for(Object value : values)
|
{
|
if(value == null)
|
appender[0].append(null);
|
else
|
appender[0].append(SMTStatic.toString(value));
|
}
|
appender[0].endRow();
|
return true;
|
}
|
|
|
});
|
}
|
finally
|
{
|
if(appender[0] != null)
|
{
|
appender[0].close();
|
appender[0] = null;
|
}
|
}
|
|
return null;
|
}
|
|
private SMTJavaAIError call_diff_metrics_RECORD(String diffDimName, DuckCubeRecs astCubeRecs1, DuckCubeRecs astCubeRecs2, String[] operate, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
SMTDatabase dbResult = tranReq.getResultDB();
|
|
// 获取两个表的字段名检查是否一致
|
DBRecords recsMeta1 = dbResult.querySQL("SELECT * FROM " + astCubeRecs1._tableName + " WHERE 1=0", null);
|
DBRecords recsMeta2 = dbResult.querySQL("SELECT * FROM " + astCubeRecs2._tableName + " WHERE 1=0", null);
|
|
// 判断字段个数
|
if(recsMeta1.getColCount() != recsMeta2.getColCount())
|
return new SMTJavaAIError("两个记录集的字段个数不一致");
|
|
// 判断字段是否一致
|
for(String field : recsMeta1.getFieldMap().keySet())
|
{
|
if(recsMeta2.getColIndex(field) < 0)
|
return new SMTJavaAIError("两个记录集的字段名称不一致");
|
}
|
|
// 根据维度信息获取需要JOIN对比的维度
|
if(astCubeRecs1._listGroupNameInfo == null || astCubeRecs1._listGroupNameInfo == null)
|
return new SMTJavaAIError("记录集无法做对比");
|
|
// 获取需要做关联的字段名列表
|
List<String> joinDimNames = new ArrayList<>();
|
for(SMTDuckTimeGroupName groupName : astCubeRecs1._listGroupNameInfo)
|
{
|
if(recsMeta1.getColIndex(groupName._titleCol) < 0)
|
continue;
|
joinDimNames.add(groupName._titleCol);
|
}
|
|
// 创建结果记录集
|
DuckCubeRecs diffRecs = astCubeRecs1.cloneCubeRecs();
|
r_result._listRecordset.add(diffRecs);
|
|
// 修改结果的标题和表名
|
diffRecs._title = diffRecs._title + operate[1];
|
diffRecs._tableName = "t_" + SMTStatic.newUUID();
|
|
// 将第二个结果集时间作为time2,前端可以作为第二个对比的过滤条件
|
diffRecs._timeRange.copyToTimeRange2(astCubeRecs2._timeRange);
|
|
// 计算时间差
|
String subTimeSQL = "";
|
String subUnit = "minutes";
|
long subValue = (astCubeRecs1._timeRange._startTime.getTime() - astCubeRecs2._timeRange._startTime.getTime()) / 1000 / 60;
|
if(subValue != 0)
|
{
|
if((subValue % 60) == 0)
|
{
|
subValue /= 60;
|
subUnit = "hours";
|
|
if((subValue % 24) == 0)
|
{
|
subValue /= 24;
|
subUnit = "days";
|
}
|
}
|
|
subTimeSQL = " + '" + subValue + " " + subUnit + "'";
|
}
|
|
|
// 生成查询SQL
|
String colTime1 = astCubeRecs1._timeRange._timeField;
|
String colTime2 = astCubeRecs2._timeRange._timeField;
|
String colValue1 = diffDimName;
|
String colValue2 = diffDimName;
|
|
StringBuilder sbSQLColumns = new StringBuilder();
|
StringBuilder sbSQLJoin = new StringBuilder();
|
for(String dimName : joinDimNames)
|
{
|
sbSQLColumns.append("TT1." + dimName + ",");
|
sbSQLJoin.append(" AND TT1." + dimName + "=" + "TT2." + dimName);
|
}
|
|
StringBuilder sbSQL = new StringBuilder();
|
sbSQL.append("SELECT T1 AS " + colTime1 + "," + sbSQLColumns.toString() + " (");
|
if("ADD".equals(operate[0]))
|
{
|
sbSQL.append("V1 + V2");
|
}
|
else if("SUB".equals(operate[0]))
|
{
|
sbSQL.append("V1 - V2");
|
}
|
else if("YOY".equals(operate[0]))
|
{
|
sbSQL.append("CASE WHEN V2 <> 0 THEN (V1 - V2) / V2 ELSE 0 END");
|
}
|
else if("MOM".equals(operate[0]))
|
{
|
sbSQL.append("CASE WHEN V2 <> 0 THEN (V1 - V2) / V2 ELSE 0 END");
|
}
|
else
|
throw new Exception("未支持的差分:" + operate[1]);
|
sbSQL.append(") AS " + colValue1);
|
sbSQL.append(" FROM (SELECT " + colTime1 + "::timestamp AS T1, " + sbSQLColumns.toString() + colValue1 + " AS V1 FROM " + astCubeRecs1._tableName + " TT1) TT1");
|
sbSQL.append(" INNER JOIN (SELECT (" + colTime2 + "::timestamp" + subTimeSQL + ") AS T2, " + sbSQLColumns.toString() + colValue2 + " AS V2 FROM " + astCubeRecs2._tableName + " TT1) TT2");
|
sbSQL.append(" ON T1=T2" + sbSQLJoin.toString());
|
|
tranReq.traceLLMDebug("\n" + sbSQL.toString());
|
|
// 执行查询,并将结果导入新的结果集
|
DuckDBAppender[] appender = new DuckDBAppender[1];
|
try
|
{
|
dbResult.querySQLNotify(sbSQL.toString(), null, new SMTDatabase.DBQueryNotifyMeta()
|
{
|
@Override
|
public boolean onMetaInfo(DBRecords metaInfo, String[] colTypes) throws Exception
|
{
|
SMTDatabase dbResult = tranReq.createResultTable(diffRecs._tableName, metaInfo, colTypes);
|
appender[0] = ((DuckDBConnection)dbResult.getConnection()).createAppender(DuckDBConnection.DEFAULT_SCHEMA, diffRecs._tableName);
|
return true;
|
|
}
|
|
@Override
|
public boolean onNextRecord(DBRecord rec) throws Exception
|
{
|
Object[] values = rec.getValues();
|
appender[0].beginRow();
|
for(Object value : values)
|
{
|
if(value == null)
|
appender[0].append(null);
|
else
|
appender[0].append(SMTStatic.toString(value));
|
}
|
appender[0].endRow();
|
return true;
|
}
|
|
|
});
|
}
|
finally
|
{
|
if(appender[0] != null)
|
{
|
appender[0].close();
|
appender[0] = null;
|
}
|
}
|
|
return null;
|
}
|
|
private SMTJavaAIError call_diff_metrics(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
SMTJavaAIError error = null;
|
|
tranReq.sendChunkedBlock("begin", "对比记录中...");
|
|
// 查询子结果集1
|
DuckResult childResult1 = new DuckResult();
|
error = queryRecordAST2SQLTree(jsonPath + "recordset1/", dbMap, jsonAST.getJson("recordset1"), extArg, tranReq, childResult1);
|
if(error != null)
|
return error;
|
|
// 查询子结果集2
|
DuckResult childResult2 = new DuckResult();
|
error = queryRecordAST2SQLTree(jsonPath + "recordset2/", dbMap, jsonAST.getJson("recordset2"), extArg, tranReq, childResult2);
|
if(error != null)
|
return error;
|
|
// 判断是否可以对比
|
if(childResult1._listRecordset.size() != 1 || childResult2._listRecordset.size() != 1)
|
return new SMTJavaAIError("查询出多个结果集无法对比");
|
|
// 获取结果集
|
DuckCubeRecs astCubeRecs1 = childResult1._listRecordset.get(0);
|
DuckCubeRecs astCubeRecs2 = childResult2._listRecordset.get(0);
|
|
if(astCubeRecs1._dimNames.size() > 0 || astCubeRecs2._dimNames.size() > 0)
|
return new SMTJavaAIError("查询多维度结果集无法对比");
|
|
// 获取对比方式
|
String userOperate = jsonAST.safeGetStr("operate", "").toUpperCase();
|
if(SMTStatic.isNullOrEmpty(userOperate))
|
return new SMTJavaAIError("未指定对比方式");
|
String[] operate = matchGroupType(userOperate, _mapDiffType2Match);
|
if(operate == null)
|
return new SMTJavaAIError("对比方式" + userOperate + "不支持");
|
|
|
String diffDim = jsonAST.safeGetStr("dim_name", null);
|
if(astCubeRecs1._recsType == DuckCubeRecsType.VALUE && astCubeRecs2._recsType == DuckCubeRecsType.VALUE)
|
error = this.call_diff_metrics_VALUE(astCubeRecs1, astCubeRecs2, operate, tranReq, r_result);
|
else if(astCubeRecs1._recsType == DuckCubeRecsType.RECORD || astCubeRecs1._recsType == DuckCubeRecsType.RECORD)
|
{
|
if(SMTStatic.isNullOrEmpty(diffDim))
|
error = new SMTJavaAIError("未指定要对比的字段名");
|
error = this.call_diff_metrics_RECORD(diffDim, astCubeRecs1, astCubeRecs2, operate, tranReq, r_result);
|
}
|
else
|
error = new SMTJavaAIError("记录集类型无法对比");
|
|
return null;
|
}
|
|
|
private SMTJavaAIError call_agg_metrics(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
tranReq.sendChunkedBlock("begin", "聚合操作中...");
|
|
// 获取聚合操作
|
String[] operate = null;
|
String userOperate = jsonAST.safeGetStr("operate", "").toUpperCase();
|
if(SMTStatic.isNullOrEmpty(userOperate))
|
{
|
operate = new String[]{"AVG", "平均"};
|
}
|
else
|
{
|
operate = matchGroupType(userOperate, _mapGroupType2Match);
|
if(operate == null)
|
{
|
operate = new String[]{"AVG", "平均"};
|
}
|
}
|
|
// 获取时间步长
|
String userStep = jsonAST.safeGetStr("step_time", "");
|
|
// 如果存在时间步长,且子操作是:query_metrics,则将其传递到子对象参数
|
boolean groupInQuery = false;
|
Json jsonRS = jsonAST.getJson("recordset");
|
String childCall = jsonRS.safeGetStr("call", "");
|
//if(!SMTStatic.isNullOrEmpty(userStep))
|
{
|
if("query_metrics".equals(childCall))
|
{
|
Json jsonRSArgs = jsonRS.getJson("args");
|
|
jsonRSArgs.set("step_op_key", operate[0]);
|
jsonRSArgs.set("step_op_title", operate[1]);
|
if(!SMTStatic.isNullOrEmpty(userStep))
|
{
|
jsonRSArgs.set("step_time_path", jsonPath + "step_time");
|
jsonRSArgs.set("step_time", userStep);
|
}
|
String stepDim = jsonAST.safeGetStr("dim_name", null);
|
if(!SMTStatic.isNullOrEmpty(stepDim))
|
jsonRSArgs.set("step_dim_name", stepDim);
|
groupInQuery = true;
|
}
|
|
}
|
|
// 如果存在分组,且子操作是query_base_info,则将其传递到子对象参数
|
if(operate != null && ("query_base_info".equals(childCall) || "query_only_metrics".equals(childCall)))
|
{
|
Json jsonRSArgs = jsonRS.getJson("args");
|
jsonRSArgs.set("step_op_key", operate[0]);
|
jsonRSArgs.set("step_op_title", operate[1]);
|
jsonRSArgs.set("step_time_path", jsonPath + "step_time");
|
String stepDim = jsonAST.safeGetStr("dim_name", null);
|
if(!SMTStatic.isNullOrEmpty(stepDim))
|
jsonRSArgs.set("step_dim_name", stepDim);
|
groupInQuery = true;
|
}
|
|
|
// 查询子结果集
|
SMTJavaAIError error = queryRecordAST2SQLTree(jsonPath + "recordset/", dbMap, jsonRS, null, tranReq, r_result);
|
if(error != null)
|
return error;
|
|
// 聚合操作
|
if(!groupInQuery)
|
{
|
// COUNT的话不用管汇总字段名
|
if("COUNT".equals(operate[0]))
|
{
|
tranReq.sendChunkedBlock("begin", "统计结果个数");
|
|
// 对所有结果汇总
|
for(DuckCubeRecs astRecs : r_result._listRecordset)
|
{
|
if(astRecs._isRawRS || astRecs._recsType == DuckCubeRecsType.SUMMARY)
|
continue;
|
|
SMTDatabase db = tranReq.getResultDB();
|
String oldTableName = "d_" + SMTStatic.newUUID();
|
db.executeSQL("ALTER TABLE " + astRecs._tableName + " RENAME TO " + oldTableName, null);
|
db.executeSQL("CREATE TABLE " + astRecs._tableName + "(__CNT__ bigint)", null);
|
db.executeSQL("INSERT INTO " + astRecs._tableName + "(__CNT__) SELECT COUNT(*) AS __CNT__ FROM " + oldTableName, null);
|
db.executeSQL("DROP TABLE " + oldTableName, null);
|
astRecs._mapCol2Title.put("__CNT__", new DuckCubeColTitle("个数", true, true));
|
astRecs._recsType = DuckCubeRecsType.SUMMARY;
|
astRecs._title = astRecs._title + (astRecs._chartTitle == null ? "" : ("-" + astRecs._chartTitle)) + operate[1];
|
}
|
}
|
else
|
{
|
tranReq.sendChunkedBlock("begin", "对结果做" + operate[0] + "汇总");
|
|
// 对所有结果汇总
|
for(DuckCubeRecs astRecs : r_result._listRecordset)
|
{
|
if(astRecs._isRawRS || astRecs._recsType == DuckCubeRecsType.SUMMARY)
|
continue;
|
|
String aggField = null;
|
if(astRecs._recsType == DuckCubeRecsType.VALUE)
|
{
|
aggField = astRecs._timeRange._valueField;
|
}
|
else if(astRecs._recsType == DuckCubeRecsType.RECORD)
|
{
|
aggField = jsonAST.safeGetStr("dim_name", null);
|
if(SMTStatic.isNullOrEmpty(aggField))
|
continue;
|
}
|
else
|
{
|
continue;
|
}
|
|
|
SMTDatabase dbResult = tranReq.getResultDB();
|
String oldTableName = "d_" + SMTStatic.newUUID();
|
dbResult.executeSQL("ALTER TABLE " + astRecs._tableName + " RENAME TO " + oldTableName, null);
|
|
String aggType = "";
|
if("SUM".equals(operate[0]) || "AVG".equals(operate[0]))
|
aggType = "::float8";
|
|
String sql = "SELECT " + operate[0] + "(" + aggField + ")" + aggType + " AS __CNT__ FROM " + oldTableName;
|
tranReq.traceLLMDebug(sql);
|
DuckDBAppender[] appender = new DuckDBAppender[1];
|
try
|
{
|
tranReq.traceLLMDebug("call_agg_metrics SQL:\n" + sql);
|
dbResult.querySQLNotify(sql, null, new SMTDatabase.DBQueryNotifyMeta()
|
{
|
@Override
|
public boolean onMetaInfo(DBRecords metaInfo, String[] colTypes) throws Exception
|
{
|
SMTDatabase dbResult = tranReq.createResultTable(astRecs._tableName, metaInfo, colTypes);
|
appender[0] = ((DuckDBConnection)dbResult.getConnection()).createAppender(DuckDBConnection.DEFAULT_SCHEMA, astRecs._tableName);
|
|
return true;
|
}
|
|
@Override
|
public boolean onNextRecord(DBRecord rec) throws Exception
|
{
|
Object[] values = rec.getValues();
|
|
appender[0].beginRow();
|
for(Object value : values)
|
{
|
if(value == null)
|
appender[0].append(null);
|
else
|
appender[0].append(SMTStatic.toString(value));
|
}
|
|
appender[0].endRow();
|
return true;
|
}
|
});
|
|
dbResult.executeSQL("DROP TABLE " + oldTableName, null);
|
astRecs._mapCol2Title.put("__CNT__", new DuckCubeColTitle(operate[1], true, true));
|
astRecs._recsType = DuckCubeRecsType.SUMMARY;
|
astRecs._title = astRecs._title + (astRecs._chartTitle == null ? "" : ("-" + astRecs._chartTitle)) + operate[1];
|
}
|
finally
|
{
|
if(appender[0] != null)
|
{
|
appender[0].close();
|
appender[0] = null;
|
}
|
}
|
|
}
|
}
|
}
|
|
return null;
|
}
|
|
private SMTJavaAIError call_top_metrics(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
|
|
int limit = jsonAST.safeGetInt("limit", 5);
|
String sortBy = jsonAST.safeGetStr("sort_by", "ASC");
|
|
// 查询子结果集
|
SMTJavaAIError error = queryRecordAST2SQLTree(jsonPath + "recordset/", dbMap, jsonAST.getJson("recordset"), extArg, tranReq, r_result);
|
if(error != null)
|
return error;
|
|
for(DuckCubeRecs astRecs : r_result._listRecordset)
|
{
|
if(astRecs._isRawRS)
|
continue;
|
|
String sql = null;
|
String oldTableName = "d_" + SMTStatic.newUUID();
|
if(astRecs._recsType == DuckCubeRecsType.VALUE)
|
{
|
sql =
|
" SELECT * FROM " + oldTableName
|
+ " ORDER BY " + astRecs._timeRange._valueField + " " + sortBy
|
+ " LIMIT " + limit;
|
|
SMTDimensionDef dimDef = SMTAIServerApp.getApp().getDimensionDefMap().get(astRecs._timeRange._valueField.toLowerCase());
|
String fieldName = dimDef != null ? dimDef.getName() : astRecs._timeRange._valueField;
|
|
tranReq.sendChunkedBlock("begin", "按照" + fieldName + "的" + sortBy + "顺序排序后,获取前" + limit + "条记录");
|
}
|
else if(astRecs._recsType == DuckCubeRecsType.RECORD)
|
{
|
String sortDim = jsonAST.safeGetStr("sort_dim", null);
|
if(SMTStatic.isNullOrEmpty(sortDim))
|
return new SMTJavaAIError("未指定排序维度名");
|
|
sql =
|
" SELECT * FROM " + oldTableName
|
+ " ORDER BY " + sortDim + " " + sortBy
|
+ " LIMIT " + limit;
|
|
SMTDimensionDef dimDef = SMTAIServerApp.getApp().getDimensionDefMap().get(sortDim);
|
String fieldName = dimDef != null ? dimDef.getName() : sortDim;
|
|
tranReq.sendChunkedBlock("begin", "按照" + fieldName + "的" + sortBy + "顺序排序后,获取前" + limit + "条记录");
|
|
|
astRecs._orderCol = new String[] {sortDim, sortBy};
|
}
|
else
|
{
|
continue;
|
}
|
|
SMTDatabase dbResult = tranReq.getResultDB();
|
dbResult.executeSQL("ALTER TABLE " + astRecs._tableName + " RENAME TO " + oldTableName, null);
|
|
DuckDBAppender[] appender = new DuckDBAppender[1];
|
try
|
{
|
tranReq.traceLLMDebug(sql);
|
|
dbResult.querySQLNotify(sql, null, new SMTDatabase.DBQueryNotifyMeta()
|
{
|
@Override
|
public boolean onMetaInfo(DBRecords metaInfo, String[] colTypes) throws Exception
|
{
|
SMTDatabase dbResult = tranReq.createResultTable(astRecs._tableName, metaInfo, colTypes);
|
appender[0] = ((DuckDBConnection)dbResult.getConnection()).createAppender(DuckDBConnection.DEFAULT_SCHEMA, astRecs._tableName);
|
|
return true;
|
}
|
|
@Override
|
public boolean onNextRecord(DBRecord rec) throws Exception
|
{
|
Object[] values = rec.getValues();
|
|
appender[0].beginRow();
|
for(Object value : values)
|
{
|
if(value == null)
|
appender[0].append(null);
|
else
|
appender[0].append(SMTStatic.toString(value));
|
}
|
|
appender[0].endRow();
|
return true;
|
}
|
|
|
});
|
}
|
finally
|
{
|
if(appender[0] != null)
|
{
|
appender[0].close();
|
appender[0] = null;
|
}
|
}
|
|
dbResult.executeSQL("DROP TABLE " + oldTableName, null);
|
}
|
|
return null;
|
}
|
|
private SMTJavaAIError queryRecordAST2SQLTree(String jsonPath, ASTDBMap dbMap, Json jsonAST, Map<String, String> extArg, SMTAIServerRequest tranReq, DuckResult r_result) throws Exception
|
{
|
SMTJavaAIError aiError = null;
|
String call = jsonAST.getJson("call").asString();
|
Json jsonArgs = jsonAST.getJson("args");
|
|
if("query_base_info".equals(call))
|
{
|
aiError = call_query_base_info(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else if("agg_metrics".equals(call))
|
{
|
aiError = call_agg_metrics(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else if("query_metrics".equals(call))
|
{
|
aiError = call_query_metrics(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else if("query_only_metrics".equals(call))
|
{
|
aiError = call_query_only_metrics(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else if("diff_metrics".equals(call))
|
{
|
aiError = call_diff_metrics(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else if("top_metrics".equals(call))
|
{
|
aiError = call_top_metrics(jsonPath + "args/", dbMap, jsonArgs, extArg, tranReq, r_result);
|
}
|
else
|
{
|
return new SMTJavaAIError("未知调用:" + call);
|
}
|
|
return aiError;
|
|
}
|
}
|