blob: a78a0b2031067ccbc898a3da61c0725bdd2d9c71 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.flink.table.explain;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.DeserializationFeature;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.PropertyNamingStrategy;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Utility for converting an execution plan from JSON to a human-readable string.
*/
public class PlanJsonParser {
public static String getSqlExecutionPlan(String t, Boolean extended) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
// not every node is same, ignore the unknown field
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
PlanTree tree = objectMapper.readValue(t, PlanTree.class);
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
int tabCount = 0;
for (int index = 0; index < tree.getNodes().size(); index++) {
Node tempNode = tree.getNodes().get(index);
// input with operation such as join or union is coordinate, keep the same indent
if ((tempNode.getPact().equals("Data Source")) && (map.containsKey(tempNode.getPact()))) {
tabCount = map.get(tempNode.getPact());
}
else {
map.put(tempNode.getPact(), tabCount);
}
printTab(tabCount, pw);
pw.print("Stage " + tempNode.getId() + " : " + tempNode.getPact() + "\n");
printTab(tabCount + 1, pw);
String content = tempNode.getContents();
// drop the hashcode of object instance
int dele = tempNode.getContents().indexOf("@");
if (dele > -1) {
content = tempNode.getContents().substring(0, dele);
}
// replace with certain content if node is dataSource to pass
// unit tests, because java and scala use different api to
// get input element
if (tempNode.getPact().equals("Data Source")) {
content = "collect elements with CollectionInputFormat";
}
pw.print("content : " + content + "\n");
List<Predecessors> predecessors = tempNode.getPredecessors();
if (predecessors != null) {
printTab(tabCount + 1, pw);
pw.print("ship_strategy : " + predecessors.get(0).getShipStrategy() + "\n");
String mode = predecessors.get(0).getExchangeMode();
if (mode != null) {
printTab(tabCount + 1, pw);
pw.print("exchange_mode : " + mode + "\n");
}
}
if (tempNode.getDriverStrategy() != null) {
printTab(tabCount + 1, pw);
pw.print("driver_strategy : " + tempNode.getDriverStrategy() + "\n");
}
if (tempNode.getGlobalProperties() != null) {
printTab(tabCount + 1, pw);
pw.print(tempNode.getGlobalProperties().get(0).getName() + " : "
+ tempNode.getGlobalProperties().get(0).getValue() + "\n");
}
if (extended) {
List<GlobalProperties> globalProperties = tempNode.getGlobalProperties();
for (int i = 1; i < globalProperties.size(); i++) {
printTab(tabCount + 1, pw);
pw.print(globalProperties.get(i).getName() + " : "
+ globalProperties.get(i).getValue() + "\n");
}
List<LocalProperty> localProperties = tempNode.getLocalProperties();
for (int i = 0; i < localProperties.size(); i++) {
printTab(tabCount + 1, pw);
pw.print(localProperties.get(i).getName() + " : "
+ localProperties.get(i).getValue() + "\n");
}
List<Estimates> estimates = tempNode.getEstimates();
for (int i = 0; i < estimates.size(); i++) {
printTab(tabCount + 1, pw);
pw.print(estimates.get(i).getName() + " : "
+ estimates.get(i).getValue() + "\n");
}
List<Costs> costs = tempNode.getCosts();
for (int i = 0; i < costs.size(); i++) {
printTab(tabCount + 1, pw);
pw.print(costs.get(i).getName() + " : "
+ costs.get(i).getValue() + "\n");
}
List<CompilerHints> compilerHints = tempNode.getCompilerHints();
for (int i = 0; i < compilerHints.size(); i++) {
printTab(tabCount + 1, pw);
pw.print(compilerHints.get(i).getName() + " : "
+ compilerHints.get(i).getValue() + "\n");
}
}
tabCount++;
pw.print("\n");
}
pw.close();
return sw.toString();
}
private static void printTab(int tabCount, PrintWriter pw) {
for (int i = 0; i < tabCount; i++) {
pw.print("\t");
}
}
}
class PlanTree {
private List<Node> nodes;
public List<Node> getNodes() {
return nodes;
}
}