【软件工程实践】Hive研究-Blog12
2021SC@SDUSC
研究内容介绍
本人负责的是负责的是将查询块QB转换成逻辑查询计划(OP Tree)
如下的代码出自apaceh-hive-3.1.2-src/ql/src/java/org/apache/hadoop/hive/ql/plan中,也就是我的分析目标代码。我们在Blog9-11中,完成了对如下文件代码的解析:
- BoundaryDef.java
- PTFExpressionDef.java
- OrderDef.java
- OrderExpressionDef.java
- PartitionDef.java
- WindowTableFunctionDef.java
- PartitionedTableFunctionDef.java
那么从本周开始,我们接着往下研究剩余的代码:
- PTFInputDef.java
- PTFQueryInputDef.java
- ShapeDetails.java
- WindowExpressionDef.java
- WindowFrameDef.java
PTFInputDef.java文件代码解析
我们首先附上整个java文件代码。
/*
* 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.plan.ptf;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.RowSchema;
import org.apache.hadoop.hive.ql.plan.Explain;
public abstract class PTFInputDef {
private String expressionTreeString;
private ShapeDetails outputShape;
private String alias;
public String getExpressionTreeString() {
return expressionTreeString;
}
public void setExpressionTreeString(String expressionTreeString) {
this.expressionTreeString = expressionTreeString;
}
public ShapeDetails getOutputShape() {
return outputShape;
}
@Explain(displayName = "output shape")
public String getOutputShapeExplain() {
RowSchema schema = outputShape.getRr().getRowSchema();
return StringUtils.join(schema.getSignature(), ", ");
}
public void setOutputShape(ShapeDetails outputShape) {
this.outputShape = outputShape;
}
@Explain(displayName = "input alias")
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public abstract PTFInputDef getInput();
}
开始解析。
全局变量解析(1)
和往常一样,我们首先对导入的包进行解析,做足准备工作。我们首先来看一下导入的包:
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.RowSchema;
import org.apache.hadoop.hive.ql.plan.Explain;
org.apache.commons.lang.StringUtils导入包解析
和以前一样,我们在官网上查看API的官方解释:
但由于这个类中的方法以及变量过多,我们无法也无需全部截取页面放至本Blog中展示。我们给出官方连接,等待至我们需要使用到这个类中的内部变量以及内部方法时再去寻找对应内容即可。
org.apache.hadoop.hive.ql.exec.RowSchema导入包解析
和以前一样,我们在官网上查看API的官方解释:
我们不难发现,这个包是一个定义的类,其中并没有什么特别的方法,所有的方法都是getter与setter方法,因此我们才推测这个类是一个定义类,或者说是一个实体类,用于规定使用的对象的格式以及包含的内容,方便操作。我们等待至使用到其中的内部变量或者方法时再返回此处进行详细的代码分析工作。
org.apache.hadoop.hive.ql.plan.Explain导入包解析
这个包在上一个Blog中已经解析过了,我们这里直接引用。
至此,我们3个导入包全部介绍完毕。
全局变量解析(2)
我们来看一下有哪些全局变量:
private String expressionTreeString;
private ShapeDetails outputShape;
private String alias;
首先对于第一个以及第三个变量,它们都是String类型的变量,这是很正常的类型,我们不做解析。对于第二个变量,它的类型为ShapeDetails类型。这是一个什么类型?我们从ptf文件夹中寻找,果然找到了这个类。
至此,我们PTFInputDef.java文件下的所有全局变量都解析完毕,下面我们开始正式的代码解析。
变量expressionTreeString的getter与setter方法
public String getExpressionTreeString() {
return expressionTreeString;
}
public void setExpressionTreeString(String expressionTreeString) {
this.expressionTreeString = expressionTreeString;
}
对于参数expressionTreeString的getter与setter方法,用于得到和设置expressionTreeString参数。
Explain设置(1)
@Explain(displayName = "output shape")
这是一个什么样的语句?我们先来观看@Expain这个关键字。@Explain其实是在调用我们的导入包org.apache.hadoop.hive.ql.plan.Explain
。而在这个包里,有着其string类型的displayName变量。前面的displayName = "output shape"
语句是在将变量displayName的值设置为"output shape"。
方法getOutputShapeExplain(1)
@Explain(displayName = "output shape")
public String getOutputShapeExplain() {
RowSchema schema = outputShape.getRr().getRowSchema();
return StringUtils.join(schema.getSignature(), ", ");
}
在方法的开头,先创建了一个RowSchema类型的变量schema 。然后将outputShape.getRr().getRowScheama()的返回值赋予给它。这个outputShape是什么变量?我们给出它的定义语句:private ShapeDetails outputShape;
,也就是说后面的两个方法都是在ptf文件夹下的另一个类ShapeDetails.java中定义的。我们转到这个类中对方法getRr()以及getRowSchema()的详细代码中。
方法gerRr
public RowResolver getRr() {
return rr;
}
可以看得出来,这是一个getter类型方法。那么这个rr是什么变量?我们找到其定义语句:transient RowResolver rr;
.对于这个java关键字transient,我们已经在Blog9中已经解析解释过了,故不再冗余的进行分析,这里我们给出Blog9的地址。那么后面的RowResolver是一个什么样子的类?我们首先在ptf文件夹下寻找这个类的踪影,发现无法找到。我们再看一下导包的语句import org.apache.hadoop.hive.ql.parse.RowResolver;
发现这是一个导入类型。
方法getRowSchema
显然,这是RowResolver的内部方法,我们直接来解org.apache.hadoop.hive.ql.parse.RowResolver导入包中的方法。
org.apache.hadoop.hive.ql.parse.RowResolver导入包解析
和以前一样,我们在官网上查看API的官方解释:
这里我们重点关注getRowSchema()方法。
显而易见,这是该类的内部变量的getter方法,用于返回一个类型为RowSchema的内部变量。
方法getOutputShapeExplain(2)
至此,我们的第一个语句RowSchema schema = outputShape.getRr().getRowSchema();
已经解析完毕了。我们来看一下第二个语句:return StringUtils.join(schema.getSignature(), ", ")
这里返回的是方法StringUtils.join(schema.getSignature(), ", ")的返回值。我们来看一下StringUtils.jon()这是一个什么样的方法。当然,我们得先了解参数的方法,也就是schema.getSignature()是一个什么类型的方法。
方法getSignature
显然,这是RowSchema类型的内部方法。我们来看一下这个方法的返回值是什么。
返回的是列表类型的变量,且列表中的元素类型为ColumnInfo类型。这个类型的变量由名字就可以看出其作用:返回列的信息。官方API对其的描述为:
Implementation for ColumnInfo which contains the internal name for the column (the one that is used by the operator to access the column) and the type (identified by a java class).
翻译成中文即为:
ColumnInfo 的实现,其中包含列的内部名称(运算符用于访问列的名称)和类型(由 java 类标识)。
方法getOutputShapeExplain(3)
回到源码中来,我们现在知道了schema.getSignature()是一个什么类型的方法了,接下来我们解析StringUtils.join()方法。
方法StringUtils.join
我们直接来看官方API对于该方法的描述以及返回值介绍。
对该方法的描述:将提供的数组的元素连接到一个包含提供的元素列表的字符串中。
方法的返回类型:String类型。
方法getOutputShapeExplain(4)
回到源码中来,我们现在知道了StringUtils.join()是一个什么类型的方法了。返回的是字符串的特定条件下的连接结果。
方法setOutputShape
public void setOutputShape(ShapeDetails outputShape) {
this.outputShape = outputShape;
}
Explain设置(2)
@Explain(displayName = "input alias")
这次的Expain设置则是将变量displayName的值设置为"input alias"。
参数alias的getter与setter方法
@Explain(displayName = "input alias")
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
抽象函数getInput
public abstract PTFInputDef getInput();
带有了java的关键字abstract。我们来看一下这个关键字的作用:
- abstract 关键字可以修饰类或方法。
- abstract 类可以扩展(增加子类),但不能直接实例化。
- abstract 方法不在声明它的类中实现,但必须在某个子类中重写。
其中我们需要注意的点:
- 采用 abstract 方法的类本来就是抽象类,并且必须声明为 abstract。
- abstract 类不能实例化。
- 仅当 abstract 类的子类实现其超类的所有 abstract 方法时,才能实例化 abstract类的子类。这种类称为具体类,以区别于 abstract 类。
- 如果 abstract 类的子类没有实现其超类的所有 abstract 方法,该子类也是 abstract 类。
- abstract 关键字不能应用于 static、private 或 final 方法,因为这些方法不能被重写,因此,不能在子类中实现。
- final 类的方法都不能是 abstract,因为 final 类不能有子类。
故这个方法会在别处被实现。
至此,PTFInputDef.java文件代码我们已全部解析完毕,我们接着往下继续解析。
PTFQueryInputDef.java文件代码解析
我们首先附上整个java文件的源码。
/*
* 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.plan.ptf;
import org.apache.hadoop.hive.ql.parse.PTFInvocationSpec.PTFQueryInputType;
import org.apache.hadoop.hive.ql.plan.Explain;
import org.apache.hadoop.hive.ql.plan.Explain.Level;
@Explain(displayName = "Input definition")
public class PTFQueryInputDef extends PTFInputDef {
private String destination;
private PTFQueryInputType type;
@Explain(displayName = "destination")
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public PTFQueryInputType getType() {
return type;
}
public void setType(PTFQueryInputType type) {
this.type = type;
}
@Explain(displayName = "type")
public String getTypeExplain() {
return type.name();
}
@Override
public PTFInputDef getInput() {
return null;
}
}
开始解析。
全局变量解析(1)
我们先来看一下导入的包:
import org.apache.hadoop.hive.ql.parse.PTFInvocationSpec.PTFQueryInputType;
import org.apache.hadoop.hive.ql.plan.Explain;
import org.apache.hadoop.hive.ql.plan.Explain.Level;
org.apache.hadoop.hive.ql.parse.PTFInvocationSpec.PTFQueryInputType导入包解析
和以前一样,我们在官网上查看API的官方解释:
这个类中包含了一个枚举型数组,其中这个枚举型数组包含了PTFCOMPONENT、SUBQUERY、TABLE、WINDOWING这些实例化对象。我们推测,这个类的对象引用时会用到这个枚举型数组内的实例化对象。其余的内部变量和方法等待至调用时我们再返回此处进行详细的代码解析。
org.apache.hadoop.hive.ql.plan.Explain导入包解析
我们在上面已经解析过这个包了,我们这里不再赘述。
org.apache.hadoop.hive.ql.plan.Explain.Level导入包解析
和以前一样,我们在官网上查看API的官方解释:
这个类中包含了一个枚举型数组,其中这个枚举型数组包含了DEFAULT、EXTENDED、USER这些实例化对象。我们推测,这个类的对象引用时会用到这个枚举型数组内的实例化对象。其余的内部变量和方法等待至调用时我们再返回此处进行详细的代码解析。
至此,导入的包全部解析完毕。
全局变量解析(2)
我们来看一下有哪些全局变量:
private String destination;
private PTFQueryInputType type;
对于第一个String类型的变量,我们不用做解释。对于第二个PTFQueryInputType类型的变量,这是导入包的变量类型,在下文中会使用到该变量作为接口去引用导入包内的一些内部的变量或者方法。
Explain设置(1)
@Explain(displayName = "destination")
这是一个什么样的语句?我们先来观看@Expain这个关键字。@Explain其实是在调用我们的导入包org.apache.hadoop.hive.ql.plan.Explain。而在这个包里,有着其string类型的displayName变量。前面的displayName = “name"语句是在将变量displayName的值设置为"destination”。
参数destination的getter与setter方法
@Explain(displayName = "destination")
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
对于参数destination的getter与setter方法,用于得到和设置destination参数。
参数type的getter与setter方法
public PTFQueryInputType getType() {
return type;
}
public void setType(PTFQueryInputType type) {
this.type = type;
}
对于参数type的getter与setter方法,用于得到和设置type参数。
Explain设置(2)
@Explain(displayName = "type")
这次的Expain设置则是将变量displayName的值设置为"type"。
方法getTypeExplain
@Explain(displayName = "type")
public String getTypeExplain() {
return type.name();
}
我们来看一下PTFQueryInputType类中的name()方法。其实在PTFQueryInputType类中没有name()这个方法。name()方法是枚举型变量Enum的方法,该方法用于获取到当前的枚举值的名字。也就是说,该方法的返回值是得到当前枚举型变量的名字。
方法getInput
@Override
public PTFInputDef getInput() {
return null;
}
这个方法其实是实现了PTFInputDef.java文件中的abstract类型方法getInput,在类的开头定义语句也指出了是继承了PTFInputDef类:public class PTFQueryInputDef extends PTFInputDef
。
至此,PTFQueryInputDef.java文件代码全部解析完毕,我们接着往下解析。
ShapeDetails.java文件代码解析
我们首先附上整个java文件代码。
/*
* 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.plan.ptf;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.hive.ql.exec.PTFUtils;
import org.apache.hadoop.hive.ql.parse.RowResolver;
import org.apache.hadoop.hive.ql.parse.TypeCheckCtx;
import org.apache.hadoop.hive.serde2.AbstractSerDe;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
public class ShapeDetails {
String serdeClassName;
Map<String, String> serdeProps;
List<String> columnNames;
transient StructObjectInspector OI;
transient AbstractSerDe serde;
transient RowResolver rr;
transient TypeCheckCtx typeCheckCtx;
public String getSerdeClassName() {
return serdeClassName;
}
public void setSerdeClassName(String serdeClassName) {
this.serdeClassName = serdeClassName;
}
public Map<String, String> getSerdeProps() {
return serdeProps;
}
public void setSerdeProps(Map<String, String> serdeProps) {
this.serdeProps = serdeProps;
}
public List<String> getColumnNames() {
return columnNames;
}
public void setColumnNames(List<String> columnNames) {
this.columnNames = columnNames;
}
public StructObjectInspector getOI() {
return OI;
}
public void setOI(StructObjectInspector oI) {
OI = oI;
}
public AbstractSerDe getSerde() {
return serde;
}
public void setSerde(AbstractSerDe serde) {
this.serde = serde;
}
public RowResolver getRr() {
return rr;
}
public void setRr(RowResolver rr) {
this.rr = rr;
}
public TypeCheckCtx getTypeCheckCtx() {
return typeCheckCtx;
}
public void setTypeCheckCtx(TypeCheckCtx typeCheckCtx) {
this.typeCheckCtx = typeCheckCtx;
}
}
开始解析。
参数serdeClassName
getter方法:
public String getSerdeClassName() {
return serdeClassName;
}
setter方法:
public void setSerdeClassName(String serdeClassName) {
this.serdeClassName = serdeClassName;
}
对于参数serdeClassName的getter与setter方法,用于得到和设置serdeClassName参数。
我们来看一下关于这个变量的定义语句:String serdeClassName
,是一个String类型的变量,我们不做解析。
参数serdeProps
getter方法:
public Map<String, String> getSerdeProps() {
return serdeProps;
}
setter方法:
public void setSerdeProps(Map<String, String> serdeProps) {
this.serdeProps = serdeProps;
}
对于参数serdeProps的getter与setter方法,用于得到和设置serdeProps参数。
我们来看一下关于这个变量的定义语句:Map<String, String> serdeProps
,这是一个Map<>类型的变量,相当于一个字典,我们不做解析。
参数columnNames
getter方法:
public List<String> getColumnNames() {
return columnNames;
}
setter方法:
public void setColumnNames(List<String> columnNames) {
this.columnNames = columnNames;
}
对于参数columnNames的getter与setter方法,用于得到和设置columnNames参数。
我们来看一下关于这个变量的定义语句:List<String> columnNames
,这是一个List<>类型的链表变量,我们不做解析。
参数OI
getter方法:
public StructObjectInspector getOI() {
return OI;
}
setter方法:
public void setOI(StructObjectInspector oI) {
OI = oI;
}
对于参数OI的getter与setter方法,用于得到和设置OI参数。
我们来看一下关于这个变量的定义语句:transient StructObjectInspector OI
,这是一个StructObjectInspector类型的变量。JAVA关键字transient我们已经解析过,这里不再赘述。我们查看导入包语句:
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
和以前一样,我们到官方API接口上查找:
我们待至使用到其中的内部变量或者方法时再返回此处进行详细的代码解析。
参数serde
getter方法:
public AbstractSerDe getSerde() {
return serde;
}
setter方法:
public void setSerde(AbstractSerDe serde) {
this.serde = serde;
}
对于参数serde的getter与setter方法,用于得到和设置serde参数。
我们来看一下关于这个变量的定义语句:transient AbstractSerDe serde;
,这是一个AbstractSerDe类型的变量。JAVA关键字transient我们已经解析过,这里不再赘述。我们查看导入包语句:
import org.apache.hadoop.hive.serde2.AbstractSerDe;
和以前一样,我们到官方API接口上查找:
我们待至使用到其中的内部变量或者方法时再返回此处进行详细的代码解析。
参数rr
getter方法:
public RowResolver getRr() {
return rr;
}
setter方法:
public void setRr(RowResolver rr) {
this.rr = rr;
}
对于参数rr的getter与setter方法,用于得到和设置rr参数。
我们来看一下关于这个变量的定义语句:transient RowResolver rr;
,这是一个RowResolver类型的变量。JAVA关键字transient我们已经解析过,这里不再赘述。我们查看导入包语句:
import org.apache.hadoop.hive.ql.parse.RowResolver;;
。我们已经在上文解析过这个导入包,这里不再赘述。
参数typeCheckCtx
getter方法:
public TypeCheckCtx getTypeCheckCtx() {
return typeCheckCtx;
}
setter方法:
public void setTypeCheckCtx(TypeCheckCtx typeCheckCtx) {
this.typeCheckCtx = typeCheckCtx;
}
对于参数typeCheckCtx的getter与setter方法,用于得到和设置typeCheckCtx参数。
我们来看一下关于这个变量的定义语句:transient TypeCheckCtx typeCheckCtx;
,这是一个TypeCheckCtx类型的变量。JAVA关键字transient我们已经解析过,这里不再赘述。我们查看导入包语句:
import org.apache.hadoop.hive.ql.parse.TypeCheckCtx;
和以前一样,我们到官方API接口上查找:
我们待至使用到其中的内部变量或者方法时再返回此处进行详细的代码解析。
至此,ShapeDetails.java文件代码全部解析完毕。
小结
通过本周的学习,我对HIVE有了更加深刻的认识,了解到了更加底层的逻辑,也学习到了许多官方的导入包的作用以及思想。希望能够在下周的学习中学习收获到新的关于HIVE的知识并学以致用。