org.apache.hadoop.hive.ql.optimizer.FieldNode Maven / Gradle / Ivy
/**
* 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.hadoop.hive.ql.optimizer;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FieldNode {
private String fieldName;
private List nodes;
public FieldNode(String fieldName) {
this.fieldName = fieldName;
nodes = new ArrayList<>();
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public void addFieldNodes(FieldNode... nodes) {
if (nodes != null) {
addFieldNodes(Arrays.asList(nodes));
}
}
public void addFieldNodes(List nodes) {
for (FieldNode fn : nodes) {
if (fn != null) {
this.nodes.add(fn);
}
}
}
public List getNodes() {
return nodes;
}
public void setNodes(List nodes) {
this.nodes = nodes;
}
public List toPaths() {
List result = new ArrayList<>();
if (nodes.isEmpty()) {
result.add(fieldName);
} else {
for (FieldNode child : nodes) {
for (String rest : child.toPaths()) {
result.add(fieldName + "." + rest);
}
}
}
return result;
}
public static FieldNode fromPath(String path) {
String[] parts = path.split("\\.");
return fromPath(parts, 0);
}
private static FieldNode fromPath(String[] parts, int index) {
if (index == parts.length) {
return null;
}
FieldNode fn = new FieldNode(parts[index]);
fn.addFieldNodes(fromPath(parts, index + 1));
return fn;
}
/**
* Merge the field node 'fn' into list 'nodes', and return the result list.
*/
public static List mergeFieldNodes(List nodes, FieldNode fn) {
List result = new ArrayList<>(nodes);
for (int i = 0; i < nodes.size(); ++i) {
FieldNode mfn = mergeFieldNode(nodes.get(i), fn);
if (mfn != null) {
result.set(i, mfn);
return result;
}
}
result.add(fn);
return result;
}
public static List mergeFieldNodes(List left, List right) {
List result = new ArrayList<>(left);
for (FieldNode fn : right) {
result = mergeFieldNodes(result, fn);
}
return result;
}
/**
* Merge the field nodes 'left' and 'right' and return the merged node.
* Return null if the two nodes cannot be merged.
*
* There are basically 3 cases here:
* 1. 'left' and 'right' have the same depth, e.g., 'left' is s[b[c]] and
* 'right' is s[b[d]]. In this case, the merged node is s[b[c,d]]
* 2. 'left' has larger depth than 'right', e.g., 'left' is s[b] while
* 'right' is s[b[d]]. In this case, the merged node is s[b]
* 3. 'left' has smaller depth than 'right', e.g., 'left' is s[b[c]] while
* 'right' is s[b]. This is the opposite case of 2), and similarly,
* the merged node is s[b].
*
* A example where the two inputs cannot be merged is, 'left' is s[b] while
* 'right' is p[c].
*/
public static FieldNode mergeFieldNode(FieldNode left, FieldNode right) {
Preconditions.checkArgument(left.getFieldName() != null && right.getFieldName() != null);
if (!left.getFieldName().equals(right.getFieldName())) {
return null;
}
if (left.getNodes().isEmpty()) {
return left;
} else if (right.getNodes().isEmpty()) {
return right;
} else {
// Both are not empty. Merge two lists.
FieldNode result = new FieldNode(left.getFieldName());
result.setNodes(mergeFieldNodes(left.getNodes(), right.getNodes()));
return result;
}
}
@Override
public String toString() {
String res = fieldName;
if (nodes.size() > 0) {
res += "[";
for (int i = 0; i < nodes.size(); i++) {
if (i == nodes.size() - 1) {
res += nodes.get(i).toString();
} else {
res += nodes.get(i).toString() + ",";
}
}
res += "]";
}
return res;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FieldNode fieldNode = (FieldNode) o;
if (fieldName != null ? !fieldName.equals(fieldNode.fieldName) : fieldNode.fieldName != null) {
return false;
}
return nodes != null ? nodes.equals(fieldNode.nodes) : fieldNode.nodes == null;
}
@Override
public int hashCode() {
int result = fieldName != null ? fieldName.hashCode() : 0;
result = 31 * result + (nodes != null ? nodes.hashCode() : 0);
return result;
}
}