public class SessionAggrStatAccumulator implements AccumulatorParam<String> { private static final long serialVersionUID = 6311074555136039130L; /** * zero方法,其實主要用於數據的初始化 * 那麼,我們這裏,就返回一個值,就是初始化中,所有範圍區間的數量,都是0 * 各個範圍區間的統計數量的拼接,還是採用一如既往的key=value|key=value的連接串的格式 */ public String zero(String initialValue) { return Constants.SESSION_COUNT + "=0|" + Constants.TIME_PERIOD_1s_3s + "=0|" + Constants.TIME_PERIOD_4s_6s + "=0|" + Constants.TIME_PERIOD_7s_9s + "=0|" + Constants.TIME_PERIOD_10s_30s + "=0|" + Constants.TIME_PERIOD_30s_60s + "=0|" + Constants.TIME_PERIOD_1m_3m + "=0|" + Constants.TIME_PERIOD_3m_10m + "=0|" + Constants.TIME_PERIOD_10m_30m + "=0|" + Constants.TIME_PERIOD_30m + "=0|" + Constants.STEP_PERIOD_1_3 + "=0|" + Constants.STEP_PERIOD_4_6 + "=0|" + Constants.STEP_PERIOD_7_9 + "=0|" + Constants.STEP_PERIOD_10_30 + "=0|" + Constants.STEP_PERIOD_30_60 + "=0|" + Constants.STEP_PERIOD_60 + "=0"; } /** * addInPlace和addAccumulator * 可以理解爲是一樣的 * * 這兩個方法,其實主要就是實現,v1可能就是我們初始化的那個連接串 * v2,就是我們在遍歷session的時候,判斷出某個session對應的區間,然後會用Constants.TIME_PERIOD_1s_3s * 所以,我們,要做的事情就是 * 在v1中,找到v2對應的value,累加1,然後再更新回連接串裏面去 * */ public String addAccumulator(String v1, String v2) { return add(v1,v2); } public String addInPlace(String v1, String v2) { return add(v1,v2); } /** * session統計計算邏輯 * @param v1 連接串 * @param v2 範圍區間 * @return 更新以後的連接串 */ private String add(String v1, String v2){ // 校驗:v1爲空的話,直接返回v2 if(StringUtils.isEmpty(v1)) { return v2; } // 使用StringUtils工具類,從v1中,提取v2對應的值,並累加1 String oldValue = StringUtils.getFieldFromConcatString(v1, "\\|", v2); if(oldValue != null) { // 將範圍區間原有的值,累加1 int newValue = Integer.valueOf(oldValue) + 1; // 使用StringUtils工具類,將v1中,v2對應的值,設置成新的累加後的值 return StringUtils.setFieldInConcatString(v1, "\\|", v2, String.valueOf(newValue)); } return v1; }
}
工具類:
/** * 字符串工具類 * @author Administrator * */ public class StringUtils { /** * 判斷字符串是否爲空 * @param str 字符串 * @return 是否爲空 */ public static boolean isEmpty(String str) { return str == null || "".equals(str); } /** * 判斷字符串是否不爲空 * @param str 字符串 * @return 是否不爲空 */ public static boolean isNotEmpty(String str) { return str != null && !"".equals(str); } /** * 截斷字符串兩側的逗號 * @param str 字符串 * @return 字符串 */ public static String trimComma(String str) { if(str.startsWith(",")) { str = str.substring(1); } if(str.endsWith(",")) { str = str.substring(0, str.length() - 1); } return str; } /** * 補全兩位數字 * @param str * @return */ public static String fulfuill(String str) { if(str.length() == 2) { return str; } else { return "0" + str; } } /** * 從拼接的字符串中提取字段 * @param str 字符串 * @param delimiter 分隔符 * @param field 字段 * @return 字段值 */ public static String getFieldFromConcatString(String str, String delimiter, String field) { try { String[] fields = str.split(delimiter); for(String concatField : fields) { // searchKeywords=|clickCategoryIds=1,2,3 if(concatField.split("=").length == 2) { String fieldName = concatField.split("=")[0]; String fieldValue = concatField.split("=")[1]; if(fieldName.equals(field)) { return fieldValue; } } } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 從拼接的字符串中給字段設置值 * @param str 字符串 * @param delimiter 分隔符 * @param field 字段名 * @param newFieldValue 新的field值 * @return 字段值 */ public static String setFieldInConcatString(String str, String delimiter, String field, String newFieldValue) { String[] fields = str.split(delimiter); for(int i = 0; i < fields.length; i++) { String fieldName = fields[i].split("=")[0]; if(fieldName.equals(field)) { String concatField = fieldName + "=" + newFieldValue; fields[i] = concatField; break; } } StringBuffer buffer = new StringBuffer(""); for(int i = 0; i < fields.length; i++) { buffer.append(fields[i]); if(i < fields.length - 1) { buffer.append("|"); } } return buffer.toString(); } }
測試類:
public class AccumuletorTest { public static void main(String[] args) { // 構建Spark上下文 SparkConf conf = new SparkConf() .setAppName("AccumuletorTest") .setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); final Accumulator<String> sessionAggrStatAccumulator = sc.accumulator( "", new SessionAggrStatAccumulator()); List<Long> seq= new ArrayList<Long>(); for (int i = 0; i < 1000; i++) { seq.add(Long.valueOf((int) (Math.random() * 1000))); } JavaRDD<Long> rdd=sc.parallelize(seq); //必須用RDD執行 rdd.foreach(new VoidFunction<Long>() { public void call(Long aLong) throws Exception { sessionAggrStatAccumulator.add(Constants.SESSION_COUNT); calculateVisitLength(aLong); calculateStepLength(aLong); } /** * 計算訪問時長範圍 * @param visitLength */ private void calculateVisitLength(long visitLength) { if (visitLength >= 1 && visitLength <= 3) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_1s_3s); } else if (visitLength >= 4 && visitLength <= 6) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_4s_6s); } else if (visitLength >= 7 && visitLength <= 9) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_7s_9s); } else if (visitLength >= 10 && visitLength <= 30) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_10s_30s); } else if (visitLength > 30 && visitLength <= 60) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_30s_60s); } else if (visitLength > 60 && visitLength <= 180) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_1m_3m); } else if (visitLength > 180 && visitLength <= 600) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_3m_10m); } else if (visitLength > 600 && visitLength <= 1800) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_10m_30m); } else if (visitLength > 1800) { sessionAggrStatAccumulator.add(Constants.TIME_PERIOD_30m); } } /** * 計算訪問步長範圍 * @param stepLength */ private void calculateStepLength(long stepLength) { if (stepLength >= 1 && stepLength <= 3) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_1_3); } else if (stepLength >= 4 && stepLength <= 6) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_4_6); } else if (stepLength >= 7 && stepLength <= 9) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_7_9); } else if (stepLength >= 10 && stepLength <= 30) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_10_30); } else if (stepLength > 30 && stepLength <= 60) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_30_60); } else if (stepLength > 60) { sessionAggrStatAccumulator.add(Constants.STEP_PERIOD_60); } } }); System.out.println("accumuletor2:"+sessionAggrStatAccumulator.value()); } }