package com.taobao.top.analysis.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.PriorityQueue; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.taobao.top.analysis.exception.AnalysisException; import com.taobao.top.analysis.statistics.data.Alias; import com.taobao.top.analysis.statistics.data.ObjectColumn; import com.taobao.top.analysis.statistics.data.Report; import com.taobao.top.analysis.statistics.data.ReportEntry; import com.taobao.top.analysis.statistics.data.ReportOrderComparator; import com.taobao.top.analysis.statistics.data.impl.SimpleCalculator; import com.taobao.top.analysis.statistics.reduce.IReducer.ReduceType; import com.taobao.top.analysis.statistics.reduce.group.AvgFunction; /** * 报表工具类 * * @author fangweng * */ public class ReportUtil { private static final Log logger = LogFactory.getLog(ReportUtil.class); private static final Log clusterLogger = LogFactory.getLog("cluster"); private static Map<Object, Object> localCache = new ConcurrentHashMap<Object, Object>(); public final static String RETURN = "\r\n"; public final static String MASTER_LOG = "master"; public final static String SLAVE_LOG = "slave"; public final static Threshold threshold = new Threshold(5000); private static String ip; private static String separator; static { try { ip = InetAddress.getLocalHost().getHostAddress(); separator = System.getProperty("line.separator"); } catch (UnknownHostException e) { } } public static String getIp() { return ip; } public static String getSeparator() { return separator; } public static void clusterLog(String log) { clusterLogger.info(log + RETURN); } public static InputStream getInputStreamFromFile(String file) throws IOException { InputStream in = null; String localdir = new StringBuilder() .append(System.getProperty("user.dir")) .append(File.separatorChar).toString(); ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (file.startsWith("file:")) { try { in = new java.io.FileInputStream(new File(file.substring(file .indexOf("file:") + "file:".length()))); } catch (Exception e) { logger.error(e, e); } if (in == null) in = new java.io.FileInputStream(new File(localdir + file.substring(file.indexOf("file:") + "file:".length()))); } else { URL url = loader.getResource(file); if (url == null) { String error = "configFile: " + file + " not exist !"; logger.error(error); throw new java.lang.RuntimeException(error); } in = url.openStream(); } return in; } public static byte generateOperationFlag(String operation) throws AnalysisException { if (operation .startsWith(AnalysisConstants.CONDITION_EQUALORGREATER_STR)) { return AnalysisConstants.CONDITION_EQUALORGREATER; } if (operation.startsWith(AnalysisConstants.CONDITION_EQUALORLESSER_STR)) { return AnalysisConstants.CONDITION_EQUALORLESSER; } if (operation.startsWith(AnalysisConstants.CONDITION_NOT_EQUAL_STR)) { return AnalysisConstants.CONDITION_NOT_EQUAL; } if (operation.startsWith(AnalysisConstants.CONDITION_EQUAL_STR)) { return AnalysisConstants.CONDITION_EQUAL; } if (operation.startsWith(AnalysisConstants.CONDITION_GREATER_STR)) { return AnalysisConstants.CONDITION_GREATER; } if (operation.startsWith(AnalysisConstants.CONDITION_LESSER_STR)) { return AnalysisConstants.CONDITION_LESSER; } if (operation.startsWith(AnalysisConstants.CONDITION_ISNUMBER_STR)) { return AnalysisConstants.CONDITION_ISNUMBER; } if (operation.startsWith(AnalysisConstants.CONDITION_IN_STR)) { return AnalysisConstants.CONDITION_IN; } if(operation.startsWith(AnalysisConstants.CONDITION_LIKE_STR)) { return AnalysisConstants.CONDITION_LIKE; } throw new AnalysisException("Entry Operation not support!"); } public static byte generateOperationFlag(char operation) throws AnalysisException { if (operation == AnalysisConstants.OPERATE_DIVIDE_CHAR) { return AnalysisConstants.OPERATE_DIVIDE; } if (operation == AnalysisConstants.OPERATE_MINUS_CHAR) { return AnalysisConstants.OPERATE_MINUS; } if (operation == AnalysisConstants.OPERATE_PLUS_CHAR) { return AnalysisConstants.OPERATE_PLUS; } if (operation == AnalysisConstants.OPERATE_RIDE_CHAR) { return AnalysisConstants.OPERATE_RIDE; } throw new AnalysisException("Entry Operation not support!"); } // /** // * 根据定义获取对应日志行产生的key // * // * @param entry // * @param contents // * @return // */ // public static String generateKey(ReportEntry entry, String[] // contents,List<InnerKey> innerKeyPool) { // StringBuilder key = new StringBuilder(); // // try { // boolean checkResult = false; // // if (entry.getConditionKStack() != null // && entry.getConditionKStack().size() > 0) { // for (int i = 0; i < entry.getConditionKStack().size(); i++) { // // Object conditionKey = entry.getConditionKStack().get(i); // byte operator = entry.getConditionOpStack().get(i); // Object conditionValue = entry.getConditionVStack().get(i); // int k = -1; // // // 长度condition特殊处理,没有指定的key列 // if (!conditionKey.equals(AnalysisConstants.RECORD_LENGTH)) { // k = (Integer) conditionKey; // } // // checkResult = checkKeyCondition(operator, k, // conditionValue, contents); // // if (entry.isAndCondition() && !checkResult) // return AnalysisConstants.IGNORE_PROCESS; // // if (!entry.isAndCondition() && checkResult) // break; // } // } // // if (!entry.isAndCondition() && !checkResult) // return AnalysisConstants.IGNORE_PROCESS; // // for (int c : entry.getKeys()) { // // 全局统计,没有key // if (c == AnalysisConstants.GLOBAL_KEY) // return AnalysisConstants.GLOBAL_KEY_STR; // // key.append(innerKeyReplace(c,contents[c - // 1],innerKeyPool)).append(AnalysisConstants.SPLIT_KEY); // } // // } catch (Exception ex) { // logger.error("generateKey error",ex); // return AnalysisConstants.IGNORE_PROCESS; // } // // return key.toString(); // } // private static String innerKeyReplace(int key,String value,List<InnerKey> // innerKeyPool) // { // String result = value; // // if (innerKeyPool == null || (innerKeyPool != null && innerKeyPool.size() // == 0)) // return result; // // for(InnerKey ik : innerKeyPool) // { // if (ik.getKey() == key) // { // if (ik.getInnerKeys().get(value) != null) // result = ik.getInnerKeys().get(value); // // break; // } // } // // return result; // } // /** // * 返回是否符合条件 // * // * @param operator // * @param conditionKey // * @param conditionValue // * @param contents // * @return // */ // private static boolean checkKeyCondition(byte operator, int conditionKey, // Object conditionValue, String[] contents) { // boolean result = false; // // if (operator == AnalysisConstants.CONDITION_EQUAL) { // if (conditionKey > 0) // result = contents[conditionKey - 1].equals(conditionValue); // else // result = contents.length == (Integer)conditionValue; // } else if (operator == AnalysisConstants.CONDITION_NOT_EQUAL) { // if (conditionKey > 0) // result = !contents[conditionKey - 1].equals(conditionValue); // else // result = contents.length != (Integer)conditionValue; // } else { // double cmpValue = 0; // // if (conditionKey > 0) // cmpValue = Double.valueOf(contents[conditionKey - 1]) // - (Double)conditionValue; // else // cmpValue = contents.length - (Integer)conditionValue; // // if (operator == AnalysisConstants.CONDITION_EQUALORGREATER) // return cmpValue >= 0; // // if (operator == AnalysisConstants.CONDITION_EQUALORLESSER) // return cmpValue <= 0; // // if (operator == AnalysisConstants.CONDITION_GREATER) // return cmpValue > 0; // // if (operator == AnalysisConstants.CONDITION_LESSER) // return cmpValue < 0; // // } // // return result; // } private static java.text.DateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); public static String formateDateTime(long time) { java.util.Calendar cal = java.util.Calendar.getInstance(); cal.setTimeInMillis(time); return df.format(cal.getTime()); } /** * 简单的从column 的json对象中获得对应属性的结果 * @param column * @param subKeyName */ public static String getValueFromJosnObj(String column, String subKeyName) { String k = new StringBuilder("\"").append(subKeyName).append("\":").toString(); if (column.indexOf(k) <= 0) return null; String v = column.substring(column.indexOf(k) + k.length()); if (v.indexOf(",") > 0) { v = v.substring(0,v.indexOf(",")); } if (v.indexOf("[") >= 0) v = v.substring(v.indexOf("[")+1); if (v.indexOf("]") > 0) v = v.substring(0,v.indexOf("]")); if (v.indexOf("\"") >= 0) v = v.substring(v.indexOf("\"")+1); if (v.endsWith("\"")) v = v.substring(0,v.length()-1); return v; } /** * 根据别名定义来转换报表模型中定义的key,直接转换为实际的列号 * * @param keys * @param aliasPool */ public static int[] transformVars(String[] keys, Map<String, Alias> aliasPool,List<ObjectColumn> subKeys) { if (keys != null && keys.length > 0) { int[] tKeys = new int[keys.length]; for (int i = 0; i < keys.length; i++) { if (aliasPool != null && aliasPool.size() > 0 && aliasPool.get(keys[i]) != null) tKeys[i] = aliasPool.get(keys[i]).getKey(); else if (keys[i].equals(AnalysisConstants.GLOBAL_KEY_STR)) tKeys[i] = AnalysisConstants.GLOBAL_KEY; else if(aliasPool != null && aliasPool.size() > 0 && keys[i].indexOf(".") > 0 && aliasPool.get(keys[i].substring(0, keys[i].indexOf("."))) != null)//列是复杂对象 { tKeys[i] = AnalysisConstants.Object_KEY; subKeys.add(new ObjectColumn(aliasPool.get(keys[i].substring(0, keys[i].indexOf("."))).getKey(), keys[i].substring(keys[i].indexOf(".") + 1))); } else tKeys[i] = Integer.parseInt(keys[i]); } return tKeys; } else return new int[0]; } /** * 根据别名定义来转换报表模型中定义的key,直接转换为实际的列号 * * @param key * @param aliasPool * @return */ public static Object transformVar(String key, Map<String, Alias> aliasPool) { Object result = key; if (aliasPool != null && aliasPool.size() > 0 && aliasPool.get(key) != null) { result = aliasPool.get(key).getKey(); } return result; } /** * 根据接口定义获取实际的接口实现实例 * * @param <I> * @param interfaceDefinition * @param classLoader * @param className * @param needCache * @return */ @SuppressWarnings("unchecked") public static <I> I getInstance(Class<I> interfaceDefinition, ClassLoader classLoader, String className, boolean needCache) { // 获取缓存的情况,或者移除缓存 if (needCache) { Object instance = localCache.get(className); if (instance == null) { instance = newInstance(interfaceDefinition, className, classLoader); localCache.put(className, instance); } return (I) instance; } else { return newInstance(interfaceDefinition, className, classLoader); } } /** * 创建实例 * * @param <I> * @param interfaceDefinition * @param className * @param classLoader * @return */ @SuppressWarnings("unchecked") private static <I> I newInstance(Class<I> interfaceDefinition, String className, ClassLoader classLoader) { try { Class<I> spiClass; if (classLoader == null) { spiClass = (Class<I>) Class.forName(className); } else { spiClass = (Class<I>) classLoader.loadClass(className); } return spiClass.newInstance(); } catch (ClassNotFoundException x) { throw new java.lang.RuntimeException("Provider " + className + " not found", x); } catch (Exception ex) { throw new java.lang.RuntimeException("Provider " + className + " could not be instantiated: " + ex, ex); } } /** * 排序 * * @param list * @param orders */ public static void doOrder(ArrayList<Object[]> list, String[] orders, Report report) { if (orders == null || (orders != null && (orders.length == 0))) return; int[] columns = new int[orders.length]; boolean[] isDesc = new boolean[orders.length]; for (int i = 0; i < isDesc.length; i++) { isDesc[i] = true; } int index = 0; for (String order : orders) { if (order.startsWith("+") || order.startsWith("-")) { if (order.startsWith("+")) isDesc[index] = false; order = order.substring(1); } for (ReportEntry entry : report.getReportEntrys()) { if (order.equals(entry.getName())) { break; } columns[index] += 1; } if (columns[index] >= report.getReportEntrys().size()) columns[index] = 0; index += 1; } Collections.sort(list, new ReportOrderComparator<Object[]>(columns, isDesc)); } /** * 格式化结果,很消耗... * * @param formatStack * @param value * @return */ public static Object formatValue(List<String> formatStack, Object value) { Object result = value; try { for (String filter : formatStack) { if (filter.startsWith(AnalysisConstants.CONDITION_ROUND_STR)) { int round = Integer.valueOf(filter .substring(AnalysisConstants.CONDITION_ROUND_STR .length())); double r = Math.pow(10, round); if (value instanceof Double) { result = (Double) (Math.round((Double) value * r) / r); } else result = (Double) (Math.round((Double.valueOf(value .toString()) * r)) / r); continue; } } } catch (Exception ex) { logger.error(ex, ex); } return result; } // /** // * 检查参数是否符合过滤器定义 // * // * @param valuefilterOpStack // * @param valuefilterStack // * @param value // * @return // */ // public static boolean checkValue(List<Byte> valuefilterOpStack, // List<Object> valuefilterStack, Object value) { // boolean result = true; // // if (valuefilterStack == null // || (valuefilterStack != null && valuefilterStack.size() == 0)) // return result; // // try { // for (int i = 0; i < valuefilterStack.size(); i++) { // Object filterValue = valuefilterStack.get(i); // Byte filterOpt = valuefilterOpStack.get(i); // // if (filterOpt == AnalysisConstants.CONDITION_ISNUMBER) { // Double.parseDouble(value.toString()); // } // // if (filterOpt == AnalysisConstants.CONDITION_EQUAL) { // if (value.equals(filterValue)) { // continue; // } else // return false; // } // // if (filterOpt == AnalysisConstants.CONDITION_EQUALORGREATER) { // Double v = Double.valueOf(value.toString()); // Double compareValue = (Double)filterValue; // // if (v >= compareValue) { // continue; // } else // return false; // } // // if (filterOpt == AnalysisConstants.CONDITION_EQUALORLESSER) { // Double v = Double.valueOf(value.toString()); // Double compareValue = (Double)filterValue; // // if (v <= compareValue) { // continue; // } else // return false; // } // // if (filterOpt == AnalysisConstants.CONDITION_GREATER) { // Double v = Double.valueOf(value.toString()); // Double compareValue = (Double)filterValue; // // if (v > compareValue) { // continue; // } else // return false; // } // // if (filterOpt == AnalysisConstants.CONDITION_LESSER) { // Double v = Double.valueOf(value.toString()); // Double compareValue = (Double)filterValue; // // if (v < compareValue) { // continue; // } else // return false; // } // // if (filterOpt == AnalysisConstants.CONDITION_NOT_EQUAL) { // if (!value.equals(filterValue)) { // continue; // } else // return false; // } // // } // } catch (Exception ex) { // result = false; // } // // return result; // } /** * 合并结果集 * * @param resultPools * @param entryPool * @return */ public static Map<String, Map<String, Object>> mergeEntryResult( Map<String, Map<String, Object>>[] resultPools, Map<String, ReportEntry> entryPool, boolean needMergeLazy,ReduceType reduceType) { if (resultPools == null || (resultPools != null && resultPools.length == 0)) return null; Map<String, Map<String, Object>> result = null; result = merge(resultPools, entryPool,reduceType); if (result == null || (result != null && result.size() <= 0)) return result; if (needMergeLazy) { lazyMerge(result, entryPool); } return result; } public static void cleanLazyData(Map<String, Map<String, Object>> result, Map<String, ReportEntry> entryPool) { if (entryPool != null) { Iterator<String> entryKeys = entryPool.keySet().iterator(); while (entryKeys.hasNext()) { String entryId = entryKeys.next(); ReportEntry entry = entryPool.get(entryId); if (entry.isLazy()) { Map<String, Object> t = result.remove(entryId); if (t != null) t.clear(); } } } } public static void cleanPeriodData(Map<String, Map<String, Object>> result, Map<String, ReportEntry> entryPool) { if (entryPool != null) { Iterator<String> entryKeys = entryPool.keySet().iterator(); while (entryKeys.hasNext()) { String entryId = entryKeys.next(); ReportEntry entry = entryPool.get(entryId); if (entry.isPeriod()) { Map<String, Object> t = result.remove(entryId); if (t != null) t.clear(); } //遍历删除平均值计算 if(entry.getGroupFunction() != null && entry.getGroupFunction() instanceof AvgFunction) { if(result.get(entryId) == null) continue; Iterator<Map.Entry<String, Object>> entries = result.get(entryId).entrySet().iterator(); while(entries.hasNext()) { Entry<String, Object> en = entries.next(); String key = en.getKey(); if(!key.startsWith(AnalysisConstants.PREF_SUM) && !key.startsWith(AnalysisConstants.PREF_COUNT)) { entries.remove(); } } } } } } public static void lazyMerge(Map<String, Map<String, Object>> result, Map<String, ReportEntry> entryPool) { // 增加对于lazy entry的处理 ArrayList<String> entryKeys = new ArrayList<String>(); entryKeys.addAll(entryPool.keySet()); // 二级lazy的优先顺序保证 Collections.sort(entryKeys); for (String entryId : entryKeys) { ReportEntry entry = entryPool .get(entryId); if (entry.isLazy()) { if (result.get(entryId) == null) result.put(entryId, new HashMap<String, Object>()); SimpleCalculator c = (SimpleCalculator)entry.getCalculator(); if (c.getBindingStack() != null && c.getBindingStack().size() > 0) { List<Object> _bindingStack = c.getBindingStack(); int size = _bindingStack.size(); String leftEntryId = (String) _bindingStack.get(0); Map<String, Object> leftMap = result.get(leftEntryId); if (leftMap == null || (leftMap != null && leftMap.size() <= 0)) { continue; } Iterator<String> iter = leftMap.keySet().iterator(); java.util.Map<String, Double> cacheMap = new java.util.HashMap<String, Double>(); while (iter.hasNext()) { try { String nodekey = iter.next(); Object nodevalue = result.get(leftEntryId).get( nodekey); Object rightvalue = null; for (int i = 0; i < size - 1; i++) { String rightkey = (String) _bindingStack .get(i + 1); if (rightkey.startsWith("sum:")) { rightkey = rightkey.substring(rightkey .indexOf("sum:") + "sum:".length()); double sumValue = 0; if (cacheMap.get(rightkey) != null) { sumValue = cacheMap.get(rightkey); } else { Iterator<Object> rValues = result .get(rightkey).values() .iterator(); while (rValues.hasNext()) { Object rv = rValues.next(); if (rv != null) { if (rv instanceof String) sumValue += Double .valueOf((String) rv); else { sumValue += (Double) rv; } } } cacheMap.put(rightkey, sumValue); } rightvalue = sumValue; } else { // 简单实现只支持两位计算,同时是+或者- if (rightkey .indexOf(AnalysisConstants.OPERATE_PLUS_CHAR) > 0 || rightkey .indexOf(AnalysisConstants.OPERATE_MINUS_CHAR) > 0) { String l; String r; if (rightkey .indexOf(AnalysisConstants.OPERATE_PLUS_CHAR) > 0) { l = rightkey .substring( 0, rightkey.indexOf(AnalysisConstants.OPERATE_PLUS_CHAR)) .trim(); r = rightkey .substring( rightkey.indexOf(AnalysisConstants.OPERATE_PLUS_CHAR) + 1) .trim(); if (result.get(l) == null || result.get(r) == null || (result.get(l) != null && result .get(l) .get(nodekey) == null) || (result.get(r) != null && result .get(r) .get(nodekey) == null)) continue; rightvalue = Double.valueOf(result .get(l).get(nodekey) .toString()) + Double.valueOf(result .get(r) .get(nodekey) .toString()); } else { l = rightkey .substring( 0, rightkey.indexOf(AnalysisConstants.OPERATE_MINUS_CHAR)) .trim(); r = rightkey .substring( rightkey.indexOf(AnalysisConstants.OPERATE_MINUS_CHAR) + 1) .trim(); if (result.get(l) == null || result.get(r) == null || (result.get(l) != null && result .get(l) .get(nodekey) == null) || (result.get(r) != null && result .get(r) .get(nodekey) == null)) continue; rightvalue = Double.valueOf(result .get(l).get(nodekey) .toString()) - Double.valueOf(result .get(r) .get(nodekey) .toString()); } } else { try { rightvalue = result.get(rightkey).get(nodekey); } catch (Throwable e) { if(!threshold.sholdBlock()) logger.error("resultkey is null" + rightkey, e); } } } if (rightvalue != null) { if (nodevalue != null) { if (c.getOperatorStack().get(i) == AnalysisConstants.OPERATE_PLUS) { if (nodevalue instanceof Double || rightvalue instanceof Double) nodevalue = Double .valueOf(nodevalue .toString()) + Double.valueOf(rightvalue .toString()); else nodevalue = (Long) nodevalue + (Long) rightvalue; continue; } if (c.getOperatorStack().get(i) == AnalysisConstants.OPERATE_MINUS) { if (nodevalue instanceof Double || rightvalue instanceof Double) nodevalue = Double .valueOf(nodevalue .toString()) - Double.valueOf(rightvalue .toString()); else nodevalue = (Long) nodevalue - (Long) rightvalue; continue; } if (c.getOperatorStack().get(i) == AnalysisConstants.OPERATE_RIDE) { if (nodevalue instanceof Double || rightvalue instanceof Double) nodevalue = Double .valueOf(nodevalue .toString()) * Double.valueOf(rightvalue .toString()); else nodevalue = (Long) nodevalue * (Long) rightvalue; continue; } if (c.getOperatorStack().get(i) == AnalysisConstants.OPERATE_DIVIDE) { nodevalue = Double .valueOf(nodevalue .toString()) / Double.valueOf(rightvalue .toString()); continue; } } else { // nodevalue=rightvalue; } } } result.get(entryId).put(nodekey, nodevalue); } catch (Exception ex) { logger.error( new StringBuilder("entry : ").append( entry.getName()).append( " lazy process error!"), ex); continue; } } cacheMap.clear(); } } else //处理average的情况 if (entry.getGroupFunction() instanceof AvgFunction) { Map<String,Object> av = result.get(entryId); Map<String,Object> tv = new HashMap<String,Object>(); if (av != null) { Iterator<String> avKeys = av.keySet().iterator(); while(avKeys.hasNext()) { String ak = avKeys.next(); if (ak.startsWith(AnalysisConstants.PREF_SUM)) { String key = ak.substring(AnalysisConstants.PREF_SUM.length()); tv.put(key, (Double)av.get(ak)/ (Double)av.get(new StringBuilder().append(AnalysisConstants.PREF_COUNT).append(key) .toString())); } } if (tv.size() > 0) av.putAll(tv); tv.clear(); } } } } protected static Map<String, Map<String, Object>> merge( Map<String, Map<String, Object>>[] entryPools, Map<String, ReportEntry> entryConfig,ReduceType reduceType) { Map<String, Map<String, Object>> result = null; int _index = 0; // 过滤一下最前面的空的结果 for (int i = 0; i < entryPools.length; i++) { _index = i; if (entryPools[i] != null) { result = entryPools[i]; break; } } //对深度merge时,只有单个结果集合的时候也做一次深层扫描 if (reduceType == ReduceType.DEEP_MERGE && (_index == entryPools.length - 1)) { result = new HashMap<String,Map<String,Object>>(); _index = entryPools.length - 2; } // 直接用resultPools的第一个作为基础数组,从第二个数组开始 for (int i = _index+1; i < entryPools.length; i++) { Map<String, Map<String, Object>> node = entryPools[i]; if (node == null || (node != null && node.size() == 0)) continue; Iterator<String> iter = node.keySet().iterator(); while (iter.hasNext()) { String entryId = iter.next(); ReportEntry entry = entryConfig.get(entryId); if (entry == null || (entry != null && entry.isLazy())) continue; if (result.get(entryId) == null) result.put(entryId, new HashMap<String, Object>()); Map<String, Object> content = node.get(entryId); Iterator<String> keyIter = content.keySet().iterator(); while (keyIter.hasNext()) { String key = keyIter.next(); Object value = content.get(key); if (key == null || value == null) continue; try { entry.getReduceClass().reducer(entry, key, value, result.get(entryId), reduceType); } catch (Throwable e) { logger.error("reduce error entryName:" + entry.getName() + ", key:" + key + ",value:" + value + "," + entry.getReports().toString(), e); } } } } return result; } /** * 获得报表文件存储路径 * * @param 报表名称 * @param 输出目录 * @param 报表日期 * @param 是否需要有后缀 * @return */ public static String getReportFileLocation(String reportname, String targetDir, long date, boolean needsuffix) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(date); String currentTime = new StringBuilder() .append(calendar.get(Calendar.YEAR)).append("-") .append(calendar.get(Calendar.MONTH) + 1).append("-") .append(calendar.get(Calendar.DAY_OF_MONTH)).toString(); StringBuilder result = new StringBuilder(); if (!targetDir.endsWith(File.separator)) result.append(targetDir).append(File.separator).append(currentTime) .append(File.separator).toString(); else result.append(targetDir).append(currentTime).append(File.separator) .toString(); if (needsuffix) { calendar.add(Calendar.DAY_OF_MONTH, -1); String stattime = new StringBuilder() .append(calendar.get(Calendar.YEAR)).append("-") .append(calendar.get(Calendar.MONTH) + 1).append("-") .append(calendar.get(Calendar.DAY_OF_MONTH)).toString(); result.append(reportname).append("_").append(stattime) .append(".csv").toString(); } else { result.append(reportname).append(".csv").toString(); } return result.toString(); } /** * @param inputFile * @return */ public static String createReportHtml(String inputFile, String title, int countNum) { StringBuilder result = new StringBuilder(); java.io.BufferedReader br = null; try { File file = new File(inputFile); if (!file.exists()) throw new java.lang.RuntimeException("chart file not exist : " + inputFile); br = new BufferedReader(new InputStreamReader(new FileInputStream( file), "gb2312")); String line = null; int index = 0; result.append("<br/>").append(title).append("<br/>"); while ((line = br.readLine()) != null) { String[] contents = line.split(","); if (index == 0) { result.append("<table border=\"1\">"); } result.append("<tr>"); for (String c : contents) { if (index == 0) result.append("<th>").append(c).append("</th>"); else result.append("<td>").append(c).append("</td>"); } result.append("</tr>"); index += 1; if (countNum > 0 && index > countNum) break; } result.append("</table>"); } catch (Exception ex) { logger.error(ex, ex); } finally { if (br != null) { try { br.close(); } catch (IOException e) { logger.error(e, e); } } } return result.toString(); } /** * 将对象写入文件 * * @param o * @param file */ public static void writeObjectToFile(Object o, String file) { java.io.ObjectOutputStream out = null; try { new File(file).createNewFile(); File f = new File(file); out = new ObjectOutputStream(new FileOutputStream(f)); out.writeObject(o); } catch (Exception ex) { logger.error(ex, ex); } finally { if (out != null) try { out.close(); } catch (IOException e) { logger.error(e, e); } } } /** * 简单的支持双向权重的分配算法 * @param 资源要分配的对象,支持member split weight的表示方法 * @param 对象要获得的资源,支持resource split weight的表示方法 * @return resource:member */ public static Map<String,String> SimpleAllocationAlgorithm(List<String> member,List<String> resource,String split) { Map<String,String> result = new HashMap<String,String>(); if (member == null || resource == null || (member != null && member.size() == 0) || (resource != null && resource.size() == 0)) return result; if (member.size() == 1) { String m = StringUtils.splitByWholeSeparator(member.get(0),split)[0]; for(String r : resource) { result.put(r, m); } return result; } PriorityQueue<MemberWeight> memberWeights = new PriorityQueue<MemberWeight>(); PriorityQueue<ResourceWeight> resourceWeights = new PriorityQueue<ResourceWeight>(); //先将member中带有权重的情况打散 for(int i = 0 ; i < member.size(); i++) { String m = member.get(i); memberWeights.add(new MemberWeight(m,split)); } for(int i = 0 ; i < resource.size(); i++) { String res = resource.get(i); resourceWeights.add(new ResourceWeight(res,split)); } ResourceWeight _res = null; while((_res = resourceWeights.poll()) != null) { MemberWeight _member = memberWeights.poll(); _member.setTaskWeight(_member.getTaskWeight() + _res.getWeight()); memberWeights.add(_member); result.put(_res.getKey(), _member.getKey()); } return result; } public static void main(String[] args) { List<String> member = new ArrayList<String>(); List<String> resource = new ArrayList<String>(); member.add("analysis1"); member.add("analysis2"); member.add("analysis3"); resource.add("job1"); resource.add("job2"); resource.add("job3"); resource.add("job4"); resource.add("job5"); Map<String,String> r2m = SimpleAllocationAlgorithm(member,resource,":"); for(Entry<String,String> t : r2m.entrySet()) { System.out.println(t.getKey() + ":" + t.getValue()); } System.out.println("-----------------"); member.clear(); resource.clear(); r2m.clear(); member.add("analysis1"); member.add("analysis2"); member.add("analysis3"); resource.add("job1"); resource.add("job2"); resource.add("job3:4"); resource.add("job4"); resource.add("job5:2"); resource.add("job6"); resource.add("job7"); resource.add("job8"); r2m = SimpleAllocationAlgorithm(member,resource,":"); for(Entry<String,String> t : r2m.entrySet()) { System.out.println(t.getKey() + ":" + t.getValue()); } System.out.println("-----------------"); member.clear(); resource.clear(); r2m.clear(); member.add("analysis1:4"); member.add("analysis2"); member.add("analysis3"); resource.add("job1"); resource.add("job2"); resource.add("job3:4"); resource.add("job4"); resource.add("job5:2"); resource.add("job6"); resource.add("job7"); resource.add("job8"); resource.add("job9:20"); r2m = SimpleAllocationAlgorithm(member,resource,":"); for(Entry<String,String> t : r2m.entrySet()) { System.out.println(t.getKey() + ":" + t.getValue()); } } /** * 读取对象从文件 * * @param file * @return */ public static Object readObjectFromFile(String file) { Object result = null; ObjectInputStream bin = null; try { File f = new File(file); bin = new ObjectInputStream(new FileInputStream(f)); result = bin.readObject(); } catch (Exception ex) { logger.error(ex, ex); } finally { if (bin != null) try { bin.close(); } catch (IOException e) { logger.error(e, e); } } return result; } // 用于不可逆压缩字符串的字典 static String[] dict = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "<", ">" }; /** * 不可逆方式压缩字符串,存在一定重复的可能性,指定的compressedLength越小,越容易重复,compress当前最大长度限制为10 * md5后的16byte做压缩,得到指定的压缩长度 然后再将中间字母和长度拼接在压缩字符串上 * * @param origin * @param compressedLength * ,需要压缩到多少位,小于等于20,当等于0的时候,判断原始字符串是否大于32,如果是,则直接用md5转换为Hex串 * @return */ public static String compressString(String origin, int compressedLength) { // 特殊处理0 if (compressedLength == 0 && (origin != null && origin.length() > 32)) { return DigestUtils.md5Hex(origin); } if (origin == null || (origin != null && (origin.length() < compressedLength + 1 + String.valueOf(origin.length()).length()))) return origin; if (compressedLength > 20) { compressedLength = 20; logger.warn("compressString function compressedLength must less 20"); } StringBuilder result = new StringBuilder(); result.append(origin.length()).append( origin.charAt(origin.length() / 2)); try { byte[] dest = DigestUtils.md5(origin); long destLong1 = 0; long destLong2 = 0; for (int i = 0; i < 8; i++) { destLong1 |= dest[i] & 0xff; destLong1 <<= 8; } for (int i = 8; i < 15; i++) { destLong2 |= dest[i] & 0xff; destLong2 <<= 8; } if (compressedLength <= 10) { for (int j = 0; j < compressedLength; j++) { long index = destLong1 & 0x0000003F; result.append(dict[(int) index]); destLong1 >>= 6; } } else { for (int j = 0; j < 10; j++) { long index = destLong1 & 0x0000003F; result.append(dict[(int) index]); destLong1 >>= 6; } for (int j = 0; j < compressedLength - 10; j++) { long index = destLong2 & 0x0000003F; result.append(dict[(int) index]); destLong2 >>= 6; } } } catch (Exception ex) { logger.error("comporessString error !", ex); } return result.toString(); } // public static void main(String[] args) { // String test = "1234567890abcdefg"; // System.out.println(compressString(test, 8)); // System.out.println(compressString(test, 10)); // System.out.println(compressString(test, 14)); // } } class MemberWeight implements java.lang.Comparable<MemberWeight> { private static final Log logger = LogFactory.getLog(MemberWeight.class); String key; int weight; int taskWeight; public MemberWeight(String memWeight,String split) { if (memWeight.indexOf(split) <= 0) init(memWeight,1); else { String[] marr = StringUtils.splitByWholeSeparator(memWeight,split); try { init(marr[0], Integer.valueOf(marr[1])); } catch(Exception ex) { logger.error("SimpleAllocationAlgorithm error",ex); } } } public MemberWeight(String key,int weight) { init(key,weight); } void init(String key,int weight) { this.key = key; if(weight <= 0) this.weight = 1; else this.weight = weight; this.taskWeight = 0; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getTaskWeight() { return taskWeight; } public void setTaskWeight(int taskWeight) { this.taskWeight = taskWeight; } @Override public int compareTo(MemberWeight o) { if (taskWeight == 0) return 1/weight - 1/o.weight; else return taskWeight/weight - o.taskWeight/o.weight; } } class ResourceWeight extends MemberWeight { @Override public int compareTo(MemberWeight o) { return o.weight - this.weight; } public ResourceWeight(String memWeight,String split) { super(memWeight, split); } }