All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.graph.DragService Maven / Gradle / Ivy

package org.jgrapht.graph;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.tuple.Pair;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.spring.boxes.dollar.JSONUtils;
import com.spring.boxes.dollar.support.MoreStream;

import org.jgrapht.graph.beans.DragonPipeline;
import org.jgrapht.graph.beans.DragonPipeline.BasePipeline;
import org.jgrapht.graph.beans.DragonPipeline.DragonOperator;
import org.jgrapht.graph.beans.DragonPipeline.PipelineManagerConfig;
import org.jgrapht.graph.beans.DagVertex;
import org.jgrapht.graph.beans.DagWeave;
import org.jgrapht.graph.dagger.VertexDataset;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DragService {

    /**
     * 获取DAG入口结点编号 和 出口结点编号 "只能有一个开始节点", 出口结点原则上只能有一个(许可多出口结点,串行结点1个用于最终)
     * @param vertexIdMap 入度结点
     * @return DAG入口结点编号
     */
    private static Pair getEndpointVertexId(Map vertexIdMap) {
        Set allVertexIdSet = vertexIdMap.keySet();
        Set hasInDegreeNodeIdSet = new HashSet<>();
        List stopNodes = Lists.newArrayList();
        for (String vertexId : allVertexIdSet) {
            List subProcessorIds = vertexIdMap.get(vertexId).getDownstreamProcessor();
            // 统计入度顶点
            if (CollectionUtils.isNotEmpty(subProcessorIds)) {
                hasInDegreeNodeIdSet.addAll(subProcessorIds);
            }
            // 统计出度结点
            if(CollectionUtils.isEmpty(subProcessorIds)){
                stopNodes.add(vertexId);
            }
        }
        // 这里认为不会出现环
        List startNodes = allVertexIdSet.stream().filter(uniqueId -> !hasInDegreeNodeIdSet.contains(uniqueId)).collect(Collectors.toList());
        Preconditions.checkArgument(startNodes.size() == 1, "只能有一个开始节点");
        Preconditions.checkArgument(stopNodes.size() == 1, "只能有一个结束节点");
        return Pair.of(startNodes.get(0), stopNodes.get(0));
    }

    /**
     * 将配置数据转换成有向无环图
     * @param dragonfly Dag编排结构
     * @return
     */
    public static DagWeave toDirectedAcyclicGraph(String dragonfly) {
        DragonPipeline dragonPipeline = JSONUtils.fromJSON(dragonfly, DragonPipeline.class);
        // 获取结点拓扑关系
        Map processorMap = Optional.ofNullable(dragonPipeline)
                .map(DragonPipeline::getPipelineManagerConfig)
                .map(PipelineManagerConfig::getBasePipeline)
                .map(BasePipeline::getProcessor)
                .orElse(Maps.newHashMap());
        Preconditions.checkArgument(MapUtils.isNotEmpty(processorMap), "DAG缺少执行结点(算子)");

        // 获取入口&出口结点
        Pair endpointVertexId = getEndpointVertexId(processorMap);
        log.info("[DAG] [出/入端点] {} --> {}", endpointVertexId.getLeft(), endpointVertexId.getRight());

        // 转换为有向无环图
        DirectedAcyclicGraph directedAcyclicGraph = new DirectedAcyclicGraph<>(DefaultEdge.class);

        // 添加所有DAG顶点
        processorMap.forEach((k, v) -> {
            directedAcyclicGraph.addVertex(new DagVertex(k, v.getTypeName()));
        });

        // 顶点辅助,For映射
        Map vertexHash = MoreStream
                .toMap(directedAcyclicGraph.vertexSet(), DagVertex::getVertexId, Function.identity());

        // 添加DAG的边
        processorMap.forEach((k, v) -> {
            DagVertex sourceVertex = MapUtils.getObject(vertexHash, k);
            v.getDownstreamProcessor().forEach(e -> {
                DagVertex targetVertex = MapUtils.getObject(vertexHash, e);
                Preconditions.checkArgument(Objects.nonNull(sourceVertex) && Objects.nonNull(targetVertex), "DAG缺少执行结点(算子)");
                log.info("[DAG] [构建有向边] {} --> {}", sourceVertex.getVertexId(), targetVertex.getVertexId());
                directedAcyclicGraph.addEdge(sourceVertex, targetVertex);
            });
        });

        DagVertex startVertex = MapUtils.getObject(vertexHash, endpointVertexId.getLeft());
        DagVertex stopVertex = MapUtils.getObject(vertexHash, endpointVertexId.getRight());

        DagWeave dagWeave = new DagWeave();
        dagWeave.setVertexHash(vertexHash);
        dagWeave.setStartVertex(startVertex);
        dagWeave.setStopVertex(stopVertex);
        dagWeave.setDirectedAcyclicGraph(directedAcyclicGraph);
        return dagWeave;
    }

    public static void main(String[] args) {
        String source = "{\n"
                + "  \"pipeline_manager_config\": {\n"
                + "    \"base_pipeline\": {\n"
                + "      \"processor\": {\n"
                + "        \"resourceAbTestInstanceWorker_5\": {\n"
                + "          \"type_name\": \"resourceAbTestInstanceWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \"resourcePendantBusinessDataWorker_4\",\n"
                + "            \"resourceAbTestInstanceWorker_3\"\n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourceAbTestInstanceWorker_5\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abBizName\",\n"
                + "              \"labelText\": \"abBizName\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"ab所属业务域\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abParamType\",\n"
                + "              \"labelText\": \"abParamType\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab参数类型(boolean/string/int/long/double)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abTestParamKey\",\n"
                + "              \"labelText\": \"abTestParamKey\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab的参数名\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abReturnValueToBranch\",\n"
                + "              \"labelText\": \"abReturnValueToBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"map结构:ab返回的值对应的分支\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        },\n"
                + "        \"resourceAbTestInstanceWorker_3\": {\n"
                + "          \"type_name\": \"resourceAbTestInstanceWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \"resourceVisitorPortraitCheckWorker_6\"\n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourceAbTestInstanceWorker_3\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abBizName\",\n"
                + "              \"labelText\": \"abBizName\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"ab所属业务域\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abParamType\",\n"
                + "              \"labelText\": \"abParamType\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab参数类型(boolean/string/int/long/double)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abTestParamKey\",\n"
                + "              \"labelText\": \"abTestParamKey\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab的参数名\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abReturnValueToBranch\",\n"
                + "              \"labelText\": \"abReturnValueToBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"map结构:ab返回的值对应的分支\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        },\n"
                + "        \"resourceVisitorPortraitCheckWorker_2\": {\n"
                + "          \"type_name\": \"resourceVisitorPortraitCheckWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \"resourceAbTestInstanceWorker_5\"\n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourceVisitorPortraitCheckWorker_2\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"blackUserList\",\n"
                + "              \"labelText\": \"blackUserList\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入屏蔽用户ID,并用半角逗号隔开\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"blackUserBranch\",\n"
                + "              \"labelText\": \"blackUserBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"黑名单的流转分支\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"whiteUserList\",\n"
                + "              \"labelText\": \"whiteUserList\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入用户白名单ID,并用半角逗号隔开\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"whiteUserBranch\",\n"
                + "              \"labelText\": \"whiteUserBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"白名单的流转分支\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"portraitToBranch\",\n"
                + "              \"labelText\": \"portraitToBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"用户人群/画像分支等(json结构)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"defaultBranch\",\n"
                + "              \"labelText\": \"defaultBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"默认的流转\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        },\n"
                + "        \"resourceAbTestInstanceWorker_1\": {\n"
                + "          \"type_name\": \"resourceAbTestInstanceWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \"resourceVisitorPortraitCheckWorker_2\",\n"
                + "            \"resourceAbTestInstanceWorker_3\"\n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourceAbTestInstanceWorker_1\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abBizName\",\n"
                + "              \"labelText\": \"abBizName\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"ab所属业务域\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abParamType\",\n"
                + "              \"labelText\": \"abParamType\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab参数类型(boolean/string/int/long/double)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abTestParamKey\",\n"
                + "              \"labelText\": \"abTestParamKey\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入ab的参数名\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"abReturnValueToBranch\",\n"
                + "              \"labelText\": \"abReturnValueToBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"map结构:ab返回的值对应的分支\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        },\n"
                + "        \"resourceVisitorPortraitCheckWorker_6\": {\n"
                + "          \"type_name\": \"resourceVisitorPortraitCheckWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \"resourcePendantBusinessDataWorker_4\"\n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourceVisitorPortraitCheckWorker_6\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"blackUserList\",\n"
                + "              \"labelText\": \"blackUserList\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入屏蔽用户ID,并用半角逗号隔开\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"blackUserBranch\",\n"
                + "              \"labelText\": \"blackUserBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"黑名单的流转分支\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"whiteUserList\",\n"
                + "              \"labelText\": \"whiteUserList\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"请输入用户白名单ID,并用半角逗号隔开\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"whiteUserBranch\",\n"
                + "              \"labelText\": \"whiteUserBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"白名单的流转分支\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"portraitToBranch\",\n"
                + "              \"labelText\": \"portraitToBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"用户人群/画像分支等(json结构)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"defaultBranch\",\n"
                + "              \"labelText\": \"defaultBranch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"默认的流转\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        },\n"
                + "        \"resourcePendantBusinessDataWorker_4\": {\n"
                + "          \"type_name\": \"resourcePendantBusinessDataWorker\",\n"
                + "          \"downstream_processor\": [\n"
                + "            \n"
                + "          ],\n"
                + "          \"config\": [\n"
                + "            {\n"
                + "              \"field\": \"name\",\n"
                + "              \"labelText\": \"节点名称\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"input\",\n"
                + "              \"value\": \"resourcePendantBusinessDataWorker_4\",\n"
                + "              \"required\": true\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"function\",\n"
                + "              \"labelText\": \"function\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"功能描述\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"switch\",\n"
                + "              \"labelText\": \"switch\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"true/false\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"relationBranchName\",\n"
                + "              \"labelText\": \"relationBranchName\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"关联的分支名(可以不填)\",\n"
                + "              \"required\": false\n"
                + "            },\n"
                + "            {\n"
                + "              \"field\": \"pendantBusinessData\",\n"
                + "              \"labelText\": \"pendantBusinessData\",\n"
                + "              \"errorMessage\": \"请输入\",\n"
                + "              \"type\": \"\",\n"
                + "              \"value\": \"挂件业务数据(json格式)\",\n"
                + "              \"required\": false\n"
                + "            }\n"
                + "          ]\n"
                + "        }\n"
                + "      }\n"
                + "    }\n"
                + "  }\n"
                + "}";
        DagWeave dagWeave = toDirectedAcyclicGraph(source);
        // System.out.println(dagWeave.getDirectedAcyclicGraph());
        Map context = Maps.newHashMap();
        context.put("path", 0);
        VertexDataset vertexDataset = DagTemplate.dataset(dagWeave, context);
        System.out.println("[场景1]执行结果:" + JSONUtils.toJSON(vertexDataset));

        System.out.println("------");

        Map context2 = Maps.newHashMap();
        context2.put("path", 1);
        VertexDataset vertexDataset2 = DagTemplate.dataset(dagWeave, context2);
        System.out.println("[场景2]执行结果:" + JSONUtils.toJSON(vertexDataset2));

        System.out.println("------");

        Map context3 = Maps.newHashMap();
        context2.put("path", 3);
        VertexDataset vertexDataset3 = DagTemplate.dataset(dagWeave, context3);
        System.out.println("[场景3]执行结果:" + JSONUtils.toJSON(vertexDataset3));
        // vertexExecutor.setApplicationContext();
        // executeDirectedAcyclicGraph(dagWeave, Maps.newHashMap());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy