package com.smtaiserver.smtaiserver.javaai.duckdb; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; 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.ast.ASTDimFilter; import com.smtaiserver.smtaiserver.javaai.duckdb.DuckCubeRecs.DuckCubeColTitle; import com.smtaiserver.smtaiserver.javaai.metrics.base.SMTDimensionDef; import com.smtservlet.util.SMTJsonWriter; import com.smtservlet.util.SMTStatic; public class DuckMergeGroupRecord extends DuckMergeGroup { private static class OutputColInfo { public String _title; public String _name; public boolean _isGroup; public int _pos; public boolean _showColumn; public boolean _isCount; public OutputColInfo(String name, String title, boolean isGroup, boolean showColumn, int pos) { _title = title; _name = name; _isGroup = isGroup; _pos = pos; _showColumn = showColumn; } } public String _posXColName; public String _posYColName; public String _devKeyColName; public DuckCubeRecs _astCubeRecs; public List _listDimFilter; @SuppressWarnings("unused") private String getStartDate() { if(_astCubeRecs._timeRange != null && _astCubeRecs._timeRange._startTime != null) return SMTStatic.toString(_astCubeRecs._timeRange._startTime).substring(0, 11); return ""; } private void outputDimFilterToJson(Set setDimNames, DBRecords recsMeta, SMTJsonWriter jsonWr) { if(_listDimFilter != null && _listDimFilter.size() > 0) { jsonWr.beginArray("filter"); for(ASTDimFilter dimFilter : _listDimFilter) { if(!recsMeta.getFieldMap().containsKey(dimFilter._dimDef.getId().toUpperCase()) && !setDimNames.contains(dimFilter._dimDef.getId())) continue; jsonWr.beginMap(null); { String type; switch(dimFilter._dimDef.getType()) { case 'T': type = "time"; break; default: type = "string"; break; } jsonWr.addKeyValue("type", type); jsonWr.addKeyValue("update", "set"); jsonWr.addKeyValue("title", dimFilter._dimDef.getName()); List listValue = dimFilter._dimDef.getValueList(); if(listValue != null) { jsonWr.beginArray("value_list"); for(String value : listValue) { jsonWr.addKeyValue(null, value); } jsonWr.endArray(); } jsonWr.beginArray("path"); { jsonWr.addKeyValue(null, dimFilter._dimPath); } jsonWr.endArray(); } jsonWr.endMap(); } jsonWr.endArray(); } if(_astCubeRecs._timeRange != null) { jsonWr.beginArray("filter"); { jsonWr.beginMap(null); { jsonWr.addKeyValue("type", "time_range"); jsonWr.addKeyValue("update", "set"); jsonWr.addKeyValue("title", "时间范围"); jsonWr.addKeyValue("start_value", _astCubeRecs._timeRange._startTime); jsonWr.addKeyValue("end_value", _astCubeRecs._timeRange._endTime); long deltaDays = (_astCubeRecs._timeRange._endTime.getTime() - _astCubeRecs._timeRange._startTime.getTime()) / 1000 / 24 / 3600 - 60; jsonWr.addKeyValue("time_step", deltaDays > 0 ? "month" : "days"); jsonWr.beginArray("start_path"); { jsonWr.addKeyValue(null, _astCubeRecs._timeRange._pathStartTime); } jsonWr.endArray(); jsonWr.beginArray("end_path"); { jsonWr.addKeyValue(null, _astCubeRecs._timeRange._pathEndTime); } jsonWr.endArray(); } jsonWr.endMap(); } jsonWr.endArray(); } } private void outputHideColumns(LinkedHashMap mapName2ColPos, SMTJsonWriter jsonWr) { OutputColInfo posX = null; OutputColInfo posY = null; OutputColInfo posDevKey = null; if(!SMTStatic.isNullOrEmpty(_posXColName) && !SMTStatic.isNullOrEmpty(_posYColName)) { posX = mapName2ColPos.remove(_posXColName.toUpperCase()); posY = mapName2ColPos.remove(_posYColName.toUpperCase()); } if(!SMTStatic.isNullOrEmpty(_devKeyColName)) { posDevKey = mapName2ColPos.remove(_devKeyColName.toUpperCase()); } if(posX != null && posY != null) { jsonWr.beginMap("map"); { posX._showColumn = false; jsonWr.addKeyValue("pos_x", mapName2ColPos.size()); mapName2ColPos.put(_posXColName.toUpperCase(), posX); posY._showColumn = false; jsonWr.addKeyValue("pos_y", mapName2ColPos.size()); mapName2ColPos.put(_posYColName.toUpperCase(), posY); } jsonWr.endMap(); } if(posDevKey != null) { jsonWr.beginMap("quota_chart"); { posDevKey._showColumn = false; jsonWr.addKeyValue("col", mapName2ColPos.size()); mapName2ColPos.put(_devKeyColName.toUpperCase(), posDevKey); } jsonWr.endMap(); } } @Override public void outputGroupToJson(String agentKey, SMTAIServerRequest tranReq) throws Exception { SMTJsonWriter jsonWrResult = tranReq.getResultJsonWr(); int maxRecs = SMTAIServerApp.getApp().getOutputAITableMax(); // 获取排序SQL String[] orderDim = tranReq.getChatOrderDimName(); // 打开数据库,获取字段列表 SMTDatabase dbResult = tranReq.getResultDB(); DBRecords recsMeta = dbResult.querySQL("SELECT * FROM " + _astCubeRecs._tableName + " LIMIT 0", null); Map mapId2DimDef = SMTAIServerApp.getApp().getDimensionDefMap(); jsonWrResult.beginMap(null); { // 设置基本信息 jsonWrResult.addKeyValue("type", "recordset"); jsonWrResult.addKeyValue("agent_key", agentKey); jsonWrResult.addKeyValue("chart", "table"); jsonWrResult.addKeyValue("title", _title); jsonWrResult.addKeyValue("max_cols", _astCubeRecs._colKeyCount); // 获取维度列表 Set setDimNames = new HashSet<>(); for(String dimName : _astCubeRecs._dimNames) { setDimNames.add(dimName); } // 如果存在过滤条件,则将过滤条件输出 this.outputDimFilterToJson(setDimNames, recsMeta, jsonWrResult); // 生成字段名 LinkedHashMap mapName2ColPos = new LinkedHashMap<>(); // 如果存在维度分组,则将分组字段加入 for(String dimName : _astCubeRecs._dimNames) { int pos = recsMeta.getColIndex(dimName); if(pos < 0) continue; SMTDimensionDef dimDef = mapId2DimDef.get(dimName.toLowerCase()); String title = dimDef == null ? dimName : dimDef.getName(); mapName2ColPos.put(dimName.toUpperCase(), new OutputColInfo(dimName, title, true, true, pos)); } // 如果存在时间字段,则将时间字段加入 if(_astCubeRecs._timeRange != null) { int pos = recsMeta.getColIndex(_astCubeRecs._timeRange._timeField); if(pos >= 0) mapName2ColPos.put( _astCubeRecs._timeRange._timeField.toUpperCase(), new OutputColInfo(_astCubeRecs._timeRange._timeField, "时间", false, true, pos)); } // 加入其余字段 for(Entry entry : recsMeta.getFieldMap().entrySet()) { if(mapName2ColPos.containsKey(entry.getKey())) continue; String dimName = entry.getKey(); SMTDimensionDef dimDef = mapId2DimDef.get(dimName.toLowerCase()); String title; boolean isCount = false; if(dimDef != null) { title = dimDef.getName(); } else { DuckCubeColTitle titleInfo = _astCubeRecs._mapCol2Title.get(entry.getKey()); if(titleInfo != null) { title = titleInfo._title; isCount = titleInfo._isCount; } else title = entry.getKey(); } OutputColInfo colInfo = new OutputColInfo(dimName, title, false, true, entry.getValue()); colInfo._isCount = isCount; mapName2ColPos.put(dimName.toUpperCase(), colInfo); } // 输出隐藏字段 this.outputHideColumns(mapName2ColPos, jsonWrResult); // 输入字段名到前端 jsonWrResult.beginArray("cols"); int colIndex = 0; int colCount = -1; for(OutputColInfo colInfo : mapName2ColPos.values()) { if(!colInfo._showColumn) break; if(colInfo._isCount) colCount = colIndex; jsonWrResult.beginMap(null); { jsonWrResult.addKeyValue("title", colInfo._title); if(!colInfo._isGroup) jsonWrResult.addKeyValue("name", colInfo._name); jsonWrResult.addKeyValue("type", "text"); jsonWrResult.addKeyValue("group", colInfo._isGroup); } jsonWrResult.endMap(); colIndex ++; } jsonWrResult.endArray(); // 输出统计个数那列 if(colCount >= 0) { jsonWrResult.addKeyValue("agg_count_col", colCount); } // 生成查询SQL StringBuilder sbSQL = new StringBuilder(); StringBuilder sbSORT = new StringBuilder(); sbSQL.append("SELECT * FROM " + this._astCubeRecs._tableName); // 如果有维度,则先按维度排序 boolean sortInGroup = false; if(_astCubeRecs._dimNames.size() > 0) { for(int i = 0; i < _astCubeRecs._dimNames.size(); i ++) { if(!mapName2ColPos.containsKey(_astCubeRecs._dimNames.get(i).toUpperCase())) continue; if(sbSORT.length() > 0) sbSORT.append(","); String dimName = _astCubeRecs._dimNames.get(i); if(orderDim != null && orderDim[0].equalsIgnoreCase(dimName)) { sortInGroup = true; sbSORT.append(dimName + " " + orderDim[1]); } else { sbSORT.append(dimName); } } } // 如果排序字段没在分组里,则单独设置 if(!sortInGroup && orderDim != null && mapName2ColPos.containsKey(orderDim[0].toUpperCase())) { if(sbSORT.length() > 0) sbSORT.append(","); sbSORT.append(orderDim[0] + " " + orderDim[1]); } // 如果存在流程测排序,则加入 if(this._astCubeRecs._orderCol != null) { if(sbSORT.length() > 0) sbSORT.append(","); if(recsMeta.getColIndex(this._astCubeRecs._orderCol[0]) >= 0) sbSORT.append(this._astCubeRecs._orderCol[0] + " " + this._astCubeRecs._orderCol[1]); } // 如果有时间,则按照时间排序 if(_astCubeRecs._timeRange != null && mapName2ColPos.containsKey(_astCubeRecs._timeRange._timeField.toUpperCase())) { if(sbSORT.length() > 0) sbSORT.append(","); sbSORT.append(_astCubeRecs._timeRange._timeField); } // 组织出最终的查询sql String sql = sbSQL.toString() + (sbSORT.length() == 0 ? "" : " ORDER BY " + sbSORT.toString()) + " LIMIT " + maxRecs; // 查询结果并输出 jsonWrResult.beginArray("values"); dbResult.querySQLNotify(sql, null, new SMTDatabase.DBQueryNotify() { @Override public boolean onNextRecord(DBRecord rec) throws Exception { jsonWrResult.beginArray(null); for(OutputColInfo colInfo : mapName2ColPos.values()) { jsonWrResult.addKeyValue(null, rec.getString(colInfo._pos)); } jsonWrResult.endArray(); return true; } }); jsonWrResult.endArray(); } jsonWrResult.endMap(); } }