package com.smtaiserver.smtaiserver.javaai.qwen.agent.script; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.mozilla.javascript.Context; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.ScriptableObject; import com.smtaiserver.smtaiserver.core.SMTAIServerApp; import com.smtaiserver.smtaiserver.core.SMTAIServerRequest; import com.smtaiserver.smtaiserver.javaai.ast.ASTDBMap; import com.smtservlet.util.Json; import com.smtservlet.util.SMTJsonWriter; import com.smtservlet.util.SMTStatic; import com.smtservlet.util.SMTStatic.SMTCalcTime; import com.smtaiserver.smtaiserver.database.SMTDatabase; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBQueryNotify; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecord; public class SMTQwenAgentScriptScope extends ImporterTopLevel { private Json _jsonArgs; private ASTDBMap _dbMap; @SuppressWarnings("unused") private SMTQwenAgentScriptJet _scriptJet; private SMTAIServerRequest _tranReq; private static Pattern _patTimeStep = java.util.regex.Pattern.compile("(\\d+)\\s+(days|years|months)"); public SMTQwenAgentScriptScope(Json jsonArgs, ASTDBMap dbMap, SMTQwenAgentScriptJet scriptJet, SMTAIServerRequest tranReq) { _dbMap = dbMap; _jsonArgs = jsonArgs; _scriptJet = scriptJet; _tranReq = tranReq; } public void __init__(Context cx) throws Exception { // Define some global functions particular to the shell. Note // that these functions are not part of ECMA. initStandardObjects(cx, false); String[] funcListArr = new String[]{ "getArgValue", "queryRecord", "outputTimeChart", "outputTable", "outputError", "joinRecordset" }; defineRunFunctions(this.getClass(), funcListArr); } protected void defineRunFunctions(Class clz, String[] names) { defineFunctionProperties(names, clz, ScriptableObject.DONTENUM); } public String getArgValue(String key) { Json jsonValue = _jsonArgs.getJson(key); return jsonValue.asString(); } // joinRecordset(记录集1, 记录集2, 对比字段名, 相差的时间范围) // 功能: // 将两个记录集按照对比字段进行合并,合并后的结果是:[[记录集1中相同字段记录, 记录集2中相同字段记录], .....] // 参数: // 记录集1:由queryRecord函数返回的记录集1 // 记录集2:由queryRecord函数返回的记录集2 // 相差的时间范围 : 如果要join的两组记录并不是来自同一个时间范围的,则需要计算:记录集2的起始时间-记录集1的起始时间,用 1 months, 1 days等形式表示,如果相同则为null // 返回: // 合并后的结果集 // 格式:[[记录集1中相同字段记录, 记录集2中相同字段记录], .....] public NativeArray joinRecordset(NativeArray arrRecs1, NativeArray arrRecs2, String keyColumn, String diffTime) throws Exception { Map mapKey2Recs = new LinkedHashMap<>(); int timeStep = 0; SMTCalcTime timeUnit = null; if(!SMTStatic.isNullOrEmpty(diffTime)) { Matcher m = _patTimeStep.matcher(diffTime); if(!m.find()) throw new Exception("time step error : " + diffTime); timeStep = SMTStatic.toInt(m.group(1)); String sUnit = m.group(2); if("years".equals(sUnit)) timeUnit = SMTCalcTime.ADD_YEAR; else if("days".equals(sUnit)) timeUnit = SMTCalcTime.ADD_DATE; else if("months".equals(sUnit)) timeUnit = SMTCalcTime.ADD_MONTH; else throw new Exception("time step unsupport : " + diffTime); } // 加入第一个记录集 for(int i = 0; i < arrRecs1.size(); i ++) { NativeObject nvRec = (NativeObject) SMTAIServerApp.unwrapObject(arrRecs1.get(i)); String key = (String) SMTAIServerApp.getJSValue(nvRec, keyColumn); mapKey2Recs.put(key, new NativeObject[] {nvRec, null}); } // 加入第二个记录集 for(int i = 0; i < arrRecs2.size(); i ++) { NativeObject nvRec = (NativeObject) SMTAIServerApp.unwrapObject(arrRecs2.get(i)); String key = (String) SMTAIServerApp.getJSValue(nvRec, keyColumn); if(timeStep != 0) { key = SMTStatic.toString(SMTStatic.calculateTime(SMTStatic.toDate(key), timeUnit, timeStep)); } NativeObject[] arrRecs = mapKey2Recs.get(key); if(arrRecs == null) continue; arrRecs[1] = nvRec; } // 生成最终结果 List list = new ArrayList<>(); for(NativeObject[] recList : mapKey2Recs.values()) { if(recList[1] == null) continue; list.add(new NativeArray(recList)); } return new NativeArray(list.toArray(new NativeArray[list.size()])); } // queryRecord(表名, 字段列表, 时间分组, 排序字段列表, 限制记录信息, 查询过滤条件) // 功能: // 查询带时间范围的SQL语句,返回查询结果集。 // 参数: // 表名: 要查询的表名 // 字段列表: 要查询的字段名列表: [字段1, 字段2, 字段3... ],这里只能放字段名,不能放任何运算操作 // 时间分组: 用于聚合操作的时间分组。 // 格式:{"col":时间字段, "agg":聚合方式(例如:AVG,SUM,MAX,MIN等), "time":分组时间段(例如:1 hours, 1 days,如果问题中未提到时间步长,则不设置。禁止捏造不存在的时间步长)},如果不存在,则设置为null // 排序字段列表: 用于排序的字段及排序信息。 // 格式:[{"col":第一个排序字段名, "order":第一个排序字段顺序(ASC,DESC)], ....] ,如果不存在则设置为null // 限制记录信息: 用于限制输出条目数的配置。 // 格式:{"start":限制记录的起始位置,"limit":限制记录的条目数}, 如果不存在则设置为null // 查询过滤条件: 用于过滤查询SQL的条件信息 // 格式:[{"col":查询条件字段名1, "op":查询条件操作符1, "value":查询值1}, ....],如果查询操作符是IN,BETWEEN之类有多个值的,那查询值就是["值1","值2"...],否者查询值就是一个字符串。如果要查询时间,请直接指定查询时间的范围,不允许吧时间拆成年月日分别判断。 // 返回: // 将查询后的结果返回 // 格式:[{字段1:值1, 字段2:值2},{字段1:值3, 字段2:值4}...] public NativeArray queryRecord(String tableName, NativeArray arrColumns, NativeObject nvTimeGroup, NativeArray arrOrderColumns, NativeObject nvLimit, NativeArray arrFilters) throws Exception { String sqlColTime = null; if(nvTimeGroup != null) { sqlColTime = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "col"); } // 加入字段 StringBuilder sbColumn = new StringBuilder(); java.util.Set setExistCols = new HashSet<>(); for(int i = 0; i < arrColumns.size(); i ++) { String colName = SMTStatic.toString(SMTAIServerApp.unwrapObject(arrColumns.get(i))); setExistCols.add(colName.toUpperCase()); if(i > 0) sbColumn.append(","); sbColumn.append(colName); } if(sqlColTime != null && !setExistCols.contains(sqlColTime.toUpperCase())) { sbColumn.append("," + sqlColTime); } // 加入表名 StringBuilder sbTable = new StringBuilder(); boolean isDevice = false; if("dev_names".equalsIgnoreCase(tableName)) { tableName = " (SELECT\r\n" + " '压力计' AS DEVICE_TYPE,\r\n" + " 'XXX' AS FACTORY,\r\n" + " N.title AS DEVICE_NAME,\r\n" + " Q.otype AS QUOTA_TYPE,\r\n" + " Q.oname AS QUOTA_NAME\r\n" + " FROM\r\n" + " (SELECT * FROM sd_names.sd_dev_pressure WHERE ver_timee = '5000-01-01'::timestamp) N\r\n" + " INNER JOIN\r\n" + " (SELECT * FROM sd_names.sd_quota_names WHERE ver_timee = '5000-01-01'::timestamp) Q\r\n" + " ON\r\n" + " N.otype = Q.ptype AND N.oname = Q.pname" + ") T"; isDevice = true; } else if("quota_value".equalsIgnoreCase(tableName)) { tableName = "(SELECT otime, sdval, otype as QUOTA_TYPE, oname as QUOTA_NAME FROM sd_values.sd_raws_match) T"; } sbTable.append(tableName); // 加入过滤条件 StringBuilder sbWhere = new StringBuilder(); if(arrFilters != null && arrFilters.size() > 0) { for(int i = 0; i < arrFilters.size(); i ++) { if(sbWhere.length() > 0) sbWhere.append(" AND "); NativeObject nvFilter = (NativeObject) SMTAIServerApp.unwrapObject(arrFilters.get(i)); String colName = (String)SMTAIServerApp.getJSValue(nvFilter, "col"); String filterOP = (String)SMTAIServerApp.getJSValue(nvFilter, "op"); if("BETWEEN".equalsIgnoreCase(filterOP)) { sbWhere.append(colName + " BETWEEN "); NativeArray arrValues = (NativeArray)SMTAIServerApp.getJSValue(nvFilter, "value"); sbWhere.append("'" + SMTStatic.toString(SMTAIServerApp.unwrapObject(arrValues.get(0))).replace("'", "''") + "'"); sbWhere.append(" AND "); sbWhere.append("'" + SMTStatic.toString(SMTAIServerApp.unwrapObject(arrValues.get(1))).replace("'", "''") + "'"); } else { if(isDevice) { if("DEVICE_NAME".equalsIgnoreCase(colName)) { if("IN".equalsIgnoreCase(filterOP)) { NativeArray arrValues = (NativeArray)SMTAIServerApp.getJSValue(nvFilter, "value"); sbWhere.append("("); for(int ii = 0; ii < arrValues.size(); ii ++) { if(ii > 0) sbWhere.append(" OR "); sbWhere.append("DEVICE_NAME LIKE '%"); sbWhere.append(SMTStatic.toString(SMTAIServerApp.unwrapObject(arrValues.get(ii))).replace("'", "''")); sbWhere.append("%'"); } sbWhere.append(")"); } else { sbWhere.append("DEVICE_NAME LIKE '%"); sbWhere.append(SMTStatic.toString(SMTAIServerApp.unwrapObject(SMTAIServerApp.getJSValue(nvFilter, "value"))).replace("'", "''")); sbWhere.append("%'"); } } else if("QUOTA_TYPE".equalsIgnoreCase(colName)) { sbWhere.append("QUOTA_TYPE = 'SDVAL_PRESS_W'"); } else { sbWhere.append(colName + " " + filterOP + " "); sbWhere.append("'" + SMTStatic.toString(SMTAIServerApp.unwrapObject(SMTAIServerApp.getJSValue(nvFilter, "value"))).replace("'", "''") + "'"); } } else { sbWhere.append(colName + " " + filterOP + " "); sbWhere.append("'" + SMTStatic.toString(SMTAIServerApp.unwrapObject(SMTAIServerApp.getJSValue(nvFilter, "value"))).replace("'", "''") + "'"); } } sbWhere.append("\n"); } } // 加入排序信息 StringBuilder sbOrder = new StringBuilder(); if(arrOrderColumns != null) { for(int i = 0; i < arrOrderColumns.size(); i ++) { if(sbOrder.length() > 0) sbOrder.append(","); NativeObject nvOrderColumn = (NativeObject) SMTAIServerApp.unwrapObject(arrOrderColumns.get(i)); String colName = (String) SMTAIServerApp.getJSValue(nvOrderColumn, "col"); String orderDir= (String) SMTAIServerApp.getJSValue(nvOrderColumn, "order"); sbOrder.append(colName + " " + orderDir); } } // 加入limit StringBuilder sbLimit = new StringBuilder(); if(nvLimit != null) { SMTAIServerApp.getApp(); Object oLimit = SMTAIServerApp.getJSValue(nvLimit, "limit", null); if(oLimit != null) { int limit = SMTStatic.toInt(oLimit); sbLimit.append("LIMIT " + limit); Object oStart = SMTAIServerApp.getJSValue(nvLimit, "start", null); if(oStart != null) sbLimit.append(" OFFSET " + SMTStatic.toInt(oStart)); } } // 整合SQL StringBuilder sbSQL = new StringBuilder(); sbSQL.append("SELECT \n"); sbSQL.append(sbColumn.toString() + "\n"); sbSQL.append("FROM " + sbTable.toString() + "\n"); if(sbWhere.length() > 0) sbSQL.append("WHERE " + sbWhere.toString() + "\n"); String sql = sbSQL.toString(); // {"col":时间字段, "agg":聚合方式(例如:AVG,SUM,MAX,MIN等), "time":分组时间段(例如:1 hours, 1 days,如果问题中未提到时间步长,则不设置。禁止捏造不存在的时间步长)},如果不存在,则设置为null if(nvTimeGroup != null) { String colTime = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "col"); String funcAgg = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "agg_func"); String colAgg = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "agg_col"); String aliasName = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "alias_col"); String timeStep = (String) SMTAIServerApp.getJSValue(nvTimeGroup, "time", null); if(SMTStatic.isNullOrEmpty(timeStep)) { sql = "SELECT " + funcAgg + "(" + colAgg + ") AS " + aliasName + " FROM (" + sql + ") T"; } else { sql = " SELECT time_bucket('" + timeStep + "', " + colTime + ") AS " + colTime + "," + funcAgg + "(" + colAgg + ") AS " + aliasName + " FROM (" + sql + ") T" + " GROUP BY time_bucket('" + timeStep + "', " + colTime + ")" ; } sql = "SELECT * FROM (\n" + sql + "\n) T\n"; } if(sbOrder.length() > 0) sql += "ORDER BY " + sbOrder.toString() + "\n"; if(sbLimit.length() > 0) sql += " " + sbLimit.toString(); SMTDatabase db = _dbMap.getDatabase("DS_43"); List recList = new ArrayList<>(); System.out.println("=================>\n" + sql + "\n<====================\n"); db.querySQLNotify(sql, null, new DBQueryNotify() { @Override public boolean onNextRecord(DBRecord rec) throws Exception { NativeObject nvRec = new NativeObject(); recList.add(nvRec); for(Entry entry : rec.getFieldMap().entrySet()) { SMTAIServerApp.putJSNotNullValue(nvRec, entry.getKey(), rec.getString(entry.getValue())); } return true; } }); return new NativeArray(recList.toArray(new NativeObject[recList.size()])); } // outputTimeChart(记录集, 名称字段名, 时间字段名, 值字段名,标题名) // 功能: // 以曲线结果记录形式将多组同类型的记录集输出到客户 // 参数: // 记录集: 要输出的由queryRecord函数返回的相同类型的记录集 // 名称字段名 : 曲线结果中代表指标名称的字段名 // 时间字段名 : 用于记录时间的字段名 // 值字段名: 用于记录值的字段名 // 标题名 : 当前输出曲线的标题名 // 返回: // 无 public void outputTimeChart(NativeArray arrRecs, String nameColumn, String timeColumn, String valueColumn, String chartTitle) throws Exception { String title = (String) chartTitle; SMTJsonWriter jsonWrResult = _tranReq.getResultJsonWr(); jsonWrResult.addKeyValue("answer_type", "summary"); jsonWrResult.beginArray("summary"); { jsonWrResult.beginMap(null); { // 加入基本信息 jsonWrResult.addKeyValue("type", "recordset"); jsonWrResult.addKeyValue("agent_key", "#0/" + SMTStatic.newUUID()); jsonWrResult.addKeyValue("chart", "muli_line"); jsonWrResult.addKeyValue("title", title); // 加入字段名 jsonWrResult.beginArray("cols"); { jsonWrResult.beginMap(null); { jsonWrResult.addKeyValue("title", "时间"); jsonWrResult.addKeyValue("type", "time"); } jsonWrResult.endMap(); jsonWrResult.beginMap(null); { jsonWrResult.addKeyValue("title", "名称"); jsonWrResult.addKeyValue("type", "name"); } jsonWrResult.endMap(); jsonWrResult.beginMap(null); { jsonWrResult.addKeyValue("title", "值"); jsonWrResult.addKeyValue("type", "value"); } jsonWrResult.endMap(); } jsonWrResult.endArray(); // 加入值 jsonWrResult.beginArray("values"); for(int i = 0; i < arrRecs.size(); i ++) { NativeObject nvRec = (NativeObject)SMTAIServerApp.unwrapObject(arrRecs.get(i)); jsonWrResult.beginArray(null); { jsonWrResult.addKeyValue(null, SMTAIServerApp.getJSValue(nvRec, timeColumn, null)); jsonWrResult.addKeyValue(null, SMTAIServerApp.getJSValue(nvRec, nameColumn, null)); jsonWrResult.addKeyValue(null, SMTAIServerApp.getJSValue(nvRec, valueColumn, null)); } jsonWrResult.endArray(); } jsonWrResult.endArray(); } jsonWrResult.endMap(); } jsonWrResult.endArray(); _tranReq.sendChunkedResultBlock(); } public void outputError(String message) throws Exception { _tranReq.sendChunkedBlock("begin", message); } // outputTable(记录集, 表格标题名, 字段名列表, 字段标题列表, 分组字段名列表) // 功能: // 以表格形式输出记录集到客户 // 参数: // 记录集: 要输出的由queryRecord函数返回的记录集 // 表格标题名 : 表格输出时候定义的名字 // 字段名列表 : 要输出的字段名列表,[字段1,字段2,...] // 字段标题列表: 字段名对应的标题列表, 如果标题不存在,则用字段名填充 [标题1, 标题2...] // 分组字段名列表: 如果记录集中包含分组字段,则输出分组字段列表,否则设置为null // 返回: // 无 public void outputTable(NativeArray arrRS, String tableTitle, NativeArray arrColNames, NativeArray arrColTitles, NativeArray arrGroupName) throws Exception { String title = tableTitle; NativeArray arrRecs = arrRS; SMTJsonWriter jsonWrResult = _tranReq.getResultJsonWr(); jsonWrResult.addKeyValue("answer_type", "summary"); jsonWrResult.beginArray("summary"); { jsonWrResult.beginMap(null); { // 加入基本信息 jsonWrResult.addKeyValue("type", "recordset"); jsonWrResult.addKeyValue("agent_key", "#0/" + SMTStatic.newUUID()); jsonWrResult.addKeyValue("chart", "table"); jsonWrResult.addKeyValue("title", title); // 加入字段列 List listColName = new ArrayList<>(); jsonWrResult.beginArray("cols"); for(int i = 0; i < arrColNames.size(); i ++) { String colName = (String)SMTAIServerApp.unwrapObject(arrColNames.get(i)); String colTitle = arrColTitles == null ? colName : (String)SMTAIServerApp.unwrapObject(arrColTitles.get(i)); jsonWrResult.beginMap(null); { jsonWrResult.addKeyValue("title", colTitle); jsonWrResult.addKeyValue("name", colName); jsonWrResult.addKeyValue("type", "text"); jsonWrResult.addKeyValue("group", false); listColName.add(colName); } jsonWrResult.endMap(); } jsonWrResult.endArray(); // 加入值列 jsonWrResult.beginArray("values"); for(int i = 0; i < arrRecs.size(); i ++) { NativeObject nvRec = (NativeObject)SMTAIServerApp.unwrapObject(arrRecs.get(i)); jsonWrResult.beginArray(null); { for(int j = 0; j < listColName.size(); j ++) { String colName = listColName.get(j); jsonWrResult.addKeyValue(null, SMTAIServerApp.getJSValue(nvRec, colName, null)); } } jsonWrResult.endArray(); } jsonWrResult.endArray(); } jsonWrResult.endMap(); } jsonWrResult.endArray(); _tranReq.sendChunkedResultBlock(); } }