com.datastax.insight.core.action.ActionHandler Maven / Gradle / Ivy
The newest version!
package com.datastax.insight.core.action;
import com.datastax.insight.core.Consts;
import com.datastax.insight.core.conf.Component;
import com.datastax.insight.core.conf.Constants;
import com.datastax.insight.core.entity.Context;
import com.datastax.insight.core.service.PersistService;
import com.datastax.insight.core.dag.*;
import com.datastax.util.lang.ReflectUtil;
import com.datastax.util.lang.StringUtil;
import com.google.common.base.Strings;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.log4j.LogManager;
import org.apache.spark.ml.PipelineStage;
import org.apache.spark.sql.Dataset;
import javax.validation.constraints.NotNull;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
public class ActionHandler {
private static List allActions = null;
private static RunMode mode = RunMode.RUN;
private static int hits = 0;
private static String nodeId = null;
private static String explorationFile = null;
private final static String DatumLoader="com.datastax.insight.ml.spark.data.DatumLoader";
private final static String DataSetWriter="com.datastax.insight.ml.spark.data.dataset.DataSetWriter";
private final static String TransformationHandler="com.datastax.insight.ml.spark.data.dataset.TransformationHandler";
private final static String PipelineHandler="com.datastax.insight.ml.spark.ml.pipeline.PipelineHandler";
private final static String ParamGridBuilderWrapper="com.datastax.insight.ml.spark.ml.tuning.ParamGridBuilderWrapper";
private static final Logger logger = LogManager.getLogger(ActionHandler.class);
/**
* 运行流程图
* @param dag DAG
* @param mode 运行模式
* @param hits 采样数
* @param nodeId 节点ID
* @return
*/
public static Object invoke(DAG dag, RunMode mode, int hits, String nodeId, String explorationFile) {
ActionHandler.mode = mode;
ActionHandler.hits = hits;
ActionHandler.nodeId = nodeId;
ActionHandler.explorationFile = explorationFile;
Action action=parseDAG(dag);
List actions=new ArrayList<>();
actions.add(action);
logger.info("===datastax-Insight Action Invoker Started===");
System.out.println("===datastax-Insight Action Invoker Started===");
Object ret= invoke(actions);
logger.info("===datastax-Insight Action Invoker Ended===");
System.out.println("===datastax-Insight Action Invoker Ended===");
return ret;
}
public static Object invoke(Action action,Object[] parameters){
try {
Object ret = ReflectUtil.invokeMethod(action.getClassName(),
action.getMethodName(),
action.getParamTypes(), parameters);
action.setResult(ret);
return ret;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//深度优先
public static Object invoke(Action action) {
Object ret=null;
if(!action.getName().equals(DAG.START_VERTEX) && !action.getName().equals(DAG.END_VERTEX)) {
Object[] parameters=prepareParams(action, null);
ret=invoke(action,parameters);
}
for(Action a : action.getNextActions()){
ret=invoke(a);
a.setResult(ret);
}
return ret;
}
//广度优先
public static Object invoke(List actions){
Object ret=null;
boolean flag=true;
for(Action action : actions) {
//20180104 fix bug: 节点遍历是有可能引起多次执行
//如果节点已经执行过,则跳过执行
if(action.getResult() != null) {
continue;
}
if (!action.getName().equals(DAG.START_VERTEX) && !action.getName().equals(DAG.END_VERTEX)) {
logger.info("===datastax-Insight Component Started==="+
action.getId()+":"+action.getType()+"===");
System.out.println("===datastax-Insight Component Started==="+
action.getId()+":"+action.getType()+"===");
try {
Object[] parameters = prepareParams(action, null);
ret = invoke(action, parameters);
sample(action);
//update flow status
PersistService.invoke("com.datastax.insight.agent.dao.InsightDAO",
"updateFlowStatus",
new String[]{Long.class.getTypeName(), Long.class.getTypeName(), Integer.class.getTypeName()},
new Object[]{PersistService.getFlowId(), PersistService.getBatchId(), 0});
if (ret == null) {
Method method = ReflectUtil.findMethod(Class.forName(action.getClassName()), action.getMethodName(), action.getParamTypes());
if (!method.getReturnType().isAssignableFrom(void.class)) {
logger.info("===datastax-Insight Component Ended==="+
action.getId()+":0"+":"+action.getType()+"===");
System.out.println("===datastax-Insight Component Ended==="+
action.getId()+":0"+":"+action.getType()+"===");
throw new Exception("Error here");
} else {
logger.info("===datastax-Insight Component Ended==="+
action.getId()+":1"+":"+action.getType()+"===");
System.out.println("===datastax-Insight Component Ended==="+
action.getId()+":1"+":"+action.getType()+"===");
}
} else {
logger.info("===datastax-Insight Component Ended==="+
action.getId()+":1"+":"+action.getType()+"===");
System.out.println("===datastax-Insight Component Ended==="+
action.getId()+":1"+":"+action.getType()+"===");
}
//// TODO: 2018/2/5 nodeId stop and write hdfs
if (!RunMode.RUN.equals(mode)
&& (nodeId != null && !nodeId.trim().isEmpty())
&& action.getId() == Long.valueOf(nodeId)) {
//stop
flag = false;
//write hdfs
if (RunMode.RUN_EXPLORATION.equals(mode)) {
writeExploration(action);
//log
}
}
} catch (Exception ex){
//update the flow status if execution failed
PersistService.invoke("com.datastax.insight.agent.dao.InsightDAO",
"updateFlowStatus",
new String[]{Long.class.getTypeName(), Long.class.getTypeName(), Integer.class.getTypeName()},
new Object[]{PersistService.getFlowId(), PersistService.getBatchId(), -1});
for(StackTraceElement element : ex.getStackTrace()) {
logger.info(element.toString());
System.out.println(element.toString());
}
flag=false;
break;
}
}
}
if(flag) {
for (Action action : actions) {
List subActions = action.getNextActions();
if (subActions != null && subActions.size() > 0) {
ret = invoke(subActions);
}
}
}
return ret;
}
/**
* 为Action准备参数,参数分为三类:
* 1、前一个Action的输出
* 2、设置的固定值
* 3、容器的全局设置值(主要有pipeline和transformer两种容器)
* @param action 当前的Action
* @param containerData 容器的全局设置值(容器中的控件通过pipeline.data或者transformer.data可以获取)
* @return Action的参数列表
*/
private static Object[] prepareParams(Action action, Object containerData){
if(action.getClassName().equals(PipelineHandler) && action.getMethodName().equals("fit")){
return preparePipelineParams(action);
}
if(action.getClassName().equals(TransformationHandler)) {
return prepareTransformerParams(action);
}
if(action.getClassName().equals(ParamGridBuilderWrapper)) {
return prepareParamGridParams(action);
}
Object[] parameters=action.getParamValues();
if(parameters==null) return null;
Object[] ps=new Object[parameters.length];
int index=0;
for(int i=0;i
//throw new Exception("parameter is not correct!");
}
} else {
Object result = getPreActionResult(action, matcher.group(1), -1);
String fieldName = matcher.group(2);
// if (!Strings.isNullOrEmpty(fieldName)) {
// Field field = ReflectUtil.findField(result.getClass(), fieldName);
//
// if (field != null) {
// field.setAccessible(true);
// ps[i]= ReflectUtil.getField(field, result);
// } else {
// Method method = ReflectUtil.findMethod(result.getClass(), fieldName);
//
// if(method != null) {
// ps[i]= ReflectUtil.invokeMethod(method, result);
// }
// }
//
// ps[i]=ReflectUtil.getField(field, result);
// } else {
// ps[i]=result;
// }
if(Strings.isNullOrEmpty(fieldName)) {
ps[i]=result;
} else {
ps[i] = getPropertyValue(result, fieldName);
}
}
}else if(p instanceof String && p.toString().contains(Constants.OUTPUT_ATUO)){ //用户无需维护索引
// long paramActionId=action.getParamOrders()[index];
long paramActionId = action.getPreActionId(index);
Object result=getPreActionResult(action,p.toString(),paramActionId);
index++;
ps[i]=result;
}else if(p instanceof String && p.toString().contains(Constants.PIPELINE_DATA)){
if(containerData != null) {
ps[i] = containerData;
} else {
//获取管道Action
// Action pipelineAction=getPipelineAction2(action);
Action pipelineAction = getAction(action, "pipeline");
//pipeline.data需要从管道参数中获取(第一个参数)
String dataParameter = pipelineAction.getParamValues()[0].toString();
//判断参数值是否需要计算,如果是${output}_格式的,就需要进行实时计算获取参数值
if (dataParameter.contains(Constants.OUTPUT)) {
ps[i] = getPreActionResult(pipelineAction, dataParameter, -1);
} else {
ps[i] = pipelineAction.getParamValues()[0];
}
}
}else if(p instanceof String && p.toString().contains(Constants.TRANSFORMER_DATA)) {
if(containerData != null) {
ps[i] = containerData;
} else {
//获取transformerAction
Action transformerAction= getAction(action, "transformer");
//transformer.data需要从transformer参数中获取(第一个参数)
String dataParameter = transformerAction.getParamValues()[0].toString();
//判断参数值是否需要计算,如果是${output}_格式的,就需要进行实时计算获取参数值
if(dataParameter.contains(Constants.OUTPUT)) {
ps[i] = getPreActionResult(transformerAction, dataParameter, -1);
} else {
ps[i] = transformerAction.getParamValues()[0];
}
}
}
//是否是系统变量,20180731,andershong
//-----需要在Insight管理系统中的两个地方进行变量控制
//-----1、用户登录后,要把当前用户的变量写入上下文中;2、用户修改自己的配置时
else if(p instanceof String && isSysProp(p.toString())) {
String prop=getSystProp(p.toString());
ps[i]=((String) p).replace(prop, Context.SYSTEM_PROPERTIES.get(prop).toString());
}else {
//20171219 修改tab问题:组件参数输入tab,不做转换则json解析会出错,所以在保存json钱先做encode,执行时再做decode
// ps[i]=p;
if(p instanceof String) {
try {
ps[i] = URLDecoder.decode(p.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
ps[i] = p;
}
} else {
ps[i] = p;
}
}
}
return ps;
}
private static boolean isSysProp(String parameter){
for(String key : Context.SYSTEM_PROPERTIES.keySet()){
if(parameter.contains(key)) return true;
}
return false;
}
private static String getSystProp(String parameter){
for(String key : Context.SYSTEM_PROPERTIES.keySet()){
if(parameter.contains(key)) return key;
}
return null;
}
//管道的参数解析
private static Object[] preparePipelineParams(Action action) {
Object[] parameters = action.getParamValues();
long[] actionIds = action.getActions();
//管道训练包含两个参数,其中第一个参数是数据,第二个参数是PipelineStage数组
Object[] result = new Object[2];
//第一个参数为数据
if (parameters != null && parameters.length > 0) {
//判断参数值是否需要计算,如果是${output}_格式的,就需要进行实时计算获取参数值
String p = parameters[0].toString();
// if (p.contains(Constants.OUTPUT)) {
// result[0] = getPreActionResult(action, p, -1);
// } else if(p.equals("${output}")) {
// long paramActionId = action.getPreActionId(0);
// result[0] = getPreActionResult(action,p.toString(),paramActionId);
// } else {
// result[0] = parameters[0];
// }
//添加对${output}._x、${output}._x[y]、${output}._x.y、${output}.x、${output}.[x]的支持
if (p.startsWith(Constants.OUTPUT)) {
result[0] = getPreActionResult(action, p, -1);
} else if(p.startsWith(Constants.OUTPUT_ATUO)) {
long paramActionId = action.getPreActionId(0);
result[0] = getPreActionResult(action, p, paramActionId);
} else {
result[0] = parameters[0];
}
}
//第二个参数为PipelineStage数组(管道内组件)
PipelineStage[] pipelineStages = new PipelineStage[actionIds.length];
result[1] = pipelineStages;
//管道内组件
// for (int i = 0; i < actionIds.length; i++) {
// long actionId = actionIds[i];
// Action subAction = getActionFromList(actionId);
// try {
// pipelineStages[i] = (PipelineStage) invoke(subAction, prepareParams(subAction));
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
//管道内的组件顺序没有办法保证,需要在运行时按照level进行排序
List pipelineActions = orderByLevel(actionIds);
for (int i = 0; i < pipelineActions.size(); i++) {
Action subAction = pipelineActions.get(i);
try {
pipelineStages[i] = (PipelineStage) invoke(subAction, prepareParams(subAction, result[0]));
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
private static Object[] prepareTransformerParams(Action action) {
Object[] parameters = action.getParamValues();
long[] actionIds = action.getActions();
//Transformer包含一个参数: Dataset
Object[] result = new Object[1];
Object transformerData = null;
if (parameters != null && parameters.length > 0) {
//判断参数值是否需要计算,如果是${output}_格式的,就需要进行实时计算获取参数值
String p = parameters[0].toString();
if (p.contains(Constants.OUTPUT)) {
transformerData = getPreActionResult(action, p, -1);
} else {
transformerData = parameters[0];
}
}
//Transformer内组件按顺序依次执行
for (long id : actionIds) {
Action subAction = getActionFromList(id);
transformerData = invoke(subAction, prepareParams(subAction, transformerData));
}
return new Object[] { transformerData };
}
private static Object[] prepareParamGridParams(Action action) {
Object[] parameters = action.getParamValues();
// if(parameters == null || parameters.length != 2) {
// return null;
// }
String args = parameters[0].toString();
String[] grids = args.split("::");
Map