00:00
好,我们接下来呢,继续来讲一下,就是说如何对呃,CQ语句对吧,或者说它的一些呃查询或者插入语句呢,呃来计算这样的一个have的表级血缘关系对吧?当然就是首先呃你要理解什么是血缘关系对吧?呃,什么是血缘关系,因为这个听着好像有点挺唬人的,呃,其实血缘关系非常简单对吧?我们在这里面的话呢,我们就来看一下表级血缘关系对吧?那么表级血缘关系的话呢,比如说我这里面我写一个非常简单的一个CQ对吧,那就是insert into table,比如说T1。对吧?啊,那这个是插入T1表的操作,然后呢,Select芯from t2,然后呢,joiningt3ont2.id等于T3.id对吧。那这样的一张表,呃,这样的一个呃CQ语句的话呢,你呃能分析出什么样的血缘关系来呢?或者说什么叫做血缘关系呢?我们来看一下,也就是说。
01:09
这个CQ语句,它实际上是从T2表和T3表查出数据来,然后写入到T1表里边,所以说它的血缘关系应该是这样子的。对吧,那么就是呃,P2表。和T3表。对吧,那么他俩的数据呢,写入到了T1表里边。对吧,如果你把这个血缘关系可视化出来呢,它就是这个样子。呃,也就是说我们所谓的表级血缘关系呢,其实就是给你一个CQ语句,你要分析出来这个数据是从哪查出来的,然后呢,又去了哪张表里面对吧?或者说插入到哪张表里边啊,当然就是说,呃,除了表级血缘关系以外呢,我们还可以分析,比如说字段级的血缘关系,对吧?呃,当然字段级的血缘关系呢,它就比表级的血缘关系更加难以复,呃,难以分析了,对不对?呃,那么为什么说它更加难以分析呢?因为。
02:15
我们一个CQ呢,它可能非常的复杂,对吧,那么这个字段它有可能是我一张临时表的字段,对吧,它并不是一个真实表的字段,那你这个临时表的字段,你就不应该出现在血缘关系图里面,对吧?包括说像表级血缘关系,那你分析CQ的时候,比方说他会有一些临时表,对吧,有一些。子查询,然后呢,呃,命名的别名为一个临时表,对吧,那这样的临时表呢,它因为它不是真实表,所以你不能把它反映在血缘关系图里边。也就是说我们这个血缘关系图呢,对吧?数据的来处它必须是真实的表,然后去向呢,也是真实的表,那么字段的血缘关系呢,它数据的来数必须是真实的表里面的字段,对吧?那么他去的那张表呢,对吧?它也必须是真实的表,那这个就是我们的呃,表级血缘关系和字段级血缘关系的一个概念啊,当然我们知道这个血缘关系它是干什么的话呢?啊,那这里面就有一个问题了,对吧?那也就是说给你一个CQ语句,你如何知道?
03:28
对不对,插入的表真实表是哪一张表,然后呢,数据的来源的真实表是哪些表对吧,说白了就是我们需要对表。对吧,我们需要对CQ语句进行什么呢?语法分析。对吧?需要对CQ语句呢进行一个语法分析,你才能得出结论说是呃,OK,说这个呃数据对吧,它是来源于哪张表,然后他去了哪张表,因为你不对这个语句呃进行语法分析,你不可能说是OK,我拿了这个语句,然后我做一个正则匹配对吧?呃,然后比方说我写一个正则表达式,然后匹配到in色into,然后我就把后面这张表当成真实表,然后直接放到这儿,对吧?那这样的话呢,是非常非常不严谨的,所以说我们实际上是必须要对CQ语句进行一个语法分析,对吧?进行一个语法分析好啊,那么在这儿的话呢,我们就首先来引入一个语法分析的工具呢,叫做ant lr4对吧,Ant l,那么这个工具呢,实际上就是Java里边,呃,其实它是最有名的语法分析工具之一,对吧,语法分析工具之一,当然这个工具非常强。
04:47
打实际上你可以用它来实现编程语言,呃,或者说类似于编译器的,呃这样的一些东西,对吧?呃,当然就是我们在引入这个RS之前呢,我们首先要清楚,呃就是说这个CQ它的一个执行流程,呃那么一般来讲的话呢,我们的一个CQ语句输入过来以后,对不对?你先要第一步要对它做什么呢?那么你当然第一步要对它做词法分析。
05:16
呃,当然这个词法分析呢,呃,它听起来有一点对吧,抽象,呃,但实际上的话呢,它的作用是什么呢?词法分析作用就是比如说我这里边我有一个赋值语句YA等于一分号,对吧,那么它在经过了此法分析以后。会变成一个什么样的东西呢?它在经过此法分析以后呀,会变成一个标记流对吧。呃,当然这个标记流的话呢,它其实很简单,呃,好,我们这个是一个标记流对吧,也就是一个token stream对吧?那么它会产生一个什么样的标记流呢?那这个标记流就是我们是va等于一,首先你要把这里面的空格忽略掉,对吧?在词法分析的时候,然后呢,在这的话呢,第一个是标记对吧?那么这个标记呢,是什么呢?是字符串Y。
06:22
对吧,那么第二个标记是什么呢?对吧,或者我们这里面,然后第二个标记的话呢,就是字符串A对吧?那么第三个标记是什么呢?那么第三个标记就是一个等号了。第三个标记是一个等号对吧?等号字符,那么最后一个标记是什么呢?整形的一,整形的一。对吧。标记整形一,也就是说实际上它就是把这个源代码的字符串呢,做一个切割对吧,那么切割出来以后呢,然后把它。
07:02
每切割出来的一个元素呢,把它转换成这样的一个标记,对吧,当然这个,呃,标记其实还缺了一个对吧,我们还缺一个分号。这个标记对吧,因为它最后一个是分号嘛。OK,也就是这里边的话呢,它是一个分号,好,那这个就是词法分析,你可以看到这个词法分析呢,就是把源代码呢,先给它转换成标记流,对吧?先给它转换成这个token stream啊,那么转换成标记流以后呢,那么接下来的第二步呢,就叫做语法分析,对吧?叫做语法分析,也就是你要把它分析出一个语法来,分析出它的语法来,所以说在这儿的话,我们要做一个语法分析,OK,那么语法分析一般来说它的结果是什么呢?呃,一般来说它的结果会把分析的结果呢,以一个抽象语法数的方式来表示对吧?抽象语法数啊,那么我们这个抽象语法数对吧?就va等于一分号,然后它转换成标记流以后呢?那么这个标记流经过语法分析对吧?比方说它是一个呃,Java语法,那么经过语法分析以后,它转化成的一个树形结构是什么呢?对不对?它转化成了一个树形结构,应该是这样子,首先它根节点呢,表示这是一个什么呀?这是一个赋值语句对吧?那比方说这个赋值语句它的等号的左边。
08:31
对不对,那这个应该是一个变量对吧?比方说这个呢,是一个变量A啊,当然一般这个等号的左边呢,可能在编译原理里边,它叫的呃学名对吧,或者说名称呢,它叫做什么呢?它叫做呃,就是说左值对吧?那么等号的右边的话呢,它就是一个右值,所以说在这的话呢,我们诶赋值语句的这样的另一边是多少呢?呃是整数一对吧,常量一或者说。
09:03
常量一,也就是说我们这个词法分析把它转成标记流以后呢,然后接下来我们语法分析把它转化成抽象语法数。对吧,把它转换成抽象语法数,然后呢,紧接着最后一步,对吧,那你就可以,呃,把它翻译成汇编。或者直接解释执行对吧,都是可以的啊,当然在这中间的话呢,呃,可能还会有一些语义分析的一些功能,比方说你去检查一下。变量A的类型能不能给它负一?对吧,整形一就是说做一些类型方面的检查,对吧,那这个是为了程序的安全性或者说健壮性啊,会有一些语义分析,但是大致流程基本上就是一个这样子的,对吧?那么对于一行CQ来讲的话呢,它其实因为CQ本身也是一门语言,所以说它其实遵循的流程是一样的,首先切割成标记流。
10:03
对吧,首先词法分析,呃,然后呢,再进行语法分析,转化成抽象语法数。好,也就是分析出它的语法来转,呃,语法分析这个是个标准流程,但是语法分析后面的话呢,呃,可能会做一些语义分析,就是类型检查对吧。语义分析,呃,比如说这里面会做一些类型检查之类的,那么语义分析完以后呢,对于一个CQ来讲,它一般来说会把它转化成一个什么呢?会把它翻译成一个执行计划,对吧?也就是在这儿的话呢,会翻译成一将我们的这个。将抽象语法数翻译成执行计划。那么我们这个执行计划呢,它翻译成执行计划以后呢,那接下来我就可以把它对吧?呃。
11:05
编译成汇编了对吧,那你就可以把它翻译成汇编或者对吧,Map reduce任务对不对,或者说是flink底层API程序对吧?这个取决于你的这个CQL到底是flink CQ还是have cql,呃,还是说像买CQL对吧?那么买CQ的话呢,基本上它会直接翻译成汇编去,呃,执行对吧,就是这一步的话呢,我们是将执行计划翻译成。对不对,目标代码,这个目标代码可能是flink的程序,也可能是map reduce任务,也可能是汇编,对吧,也可能是汇编,这个就是完整的一个CQ的执行流程。呃,那么在CQ它进行词法分析,并翻译成语法分析的这一步呢,对吧?在Java里边呢,有两种工具是最有名的,那么一个是安奥。
12:07
对吧?那么案台RR呢?哪些工具使用了案台RR来把CQ翻译成抽象语法数呢?或者说对它进行词法分析和语法分析呢?呃,那么常见的就是比如说。对吧,Have CQ Spark CQ对吧,那这两个实际上它用的都是安R,呃,那么还有一个呢,就是我们的Java CC。对吧,Java c这个工具主要用在哪里呢?实际上主要用在呃,它使用Java c实现了一个叫做呃阿帕奇Co set这样的一个工具。对吧?然后用这个工具呢,来进行对CQ进行词法分析,语法分析,对吧,可能功能还更强大一点,呃,直接可以翻译成执行计划,对吧?那么哪些工具使用了阿帕奇开set呢?对吧,那很著名的就是弗link CQ,它使用了这个阿帕奇开赛,而阿帕奇开赛呢,是基于Java CC来开发的,对吧?基于Java CC来开发的,呃,当然就是说这两个工具的使用,呃本身是比较复杂的,并不是说这两工具它很难掌握,而是它背后的知识对吧?它背后的知识呢,主要依来依赖一门这个计算机的课程,叫做编译原理,对吧?所以说你这个东西,呃,如果想要使用的非常六,对吧,你想要对这个Java CC或者说安泰RR使用的特别六的话呢?呃,那么你是需要学习一下这个编原理的,对吧?啊,那么对于案台RR的话呢,我会推荐一本书对吧,那这个案台RR的书呢,就叫做案台RR4权威指南对吧,大家可以。
13:46
可以去呃下来,呃就是说搜一下这本书买一下,然后呢,细致的看一下对吧,把上面的代码呢都敲一下,呃,那你就会,呃就是说大致明白他怎么用的,当然他背后要学习的知识还是非常多的,对吧?呃不夸张的说,你如果把这个东西掌握了的话呢,实际上你自己实现一个have是呃没有任何问题的对吧?没有任何问题的,因为你对这个CQ的语法很熟悉,然后对它做词法分析,语法分析,呃转换成抽象语法数,你就可以直接把它翻译成执行计划对吧,然后再翻译成map produce对吧,所以说实际上。
14:24
呃,它的挑战性呢,就在于这里,他挑这个实现一个have的挑战性,其实就在这儿对吧?呃,当然我们这门课程呢,我们并没有时间去详细的把安R4去讲解一下,呃,我们只能说是简单的入一下门,然后使用这个工具呢,来对CQ进行语法分析啊,那么然后呢,分析它的血缘关系,对吧?所以说首先的话呢,我们先来举一个非常小的例子来研究一下这个安泰RR4。
15:00
呃,它是怎么使用的对吧?那么在这里边的话呢,我们将会实现一个呃带负值的这样的一个计算器,对吧?什么叫做待负值呢?比如说我现在一加二,如果我回车的话呢,那么它应该计算出一个三来,对吧?那么我如果A等于一的话呢,那么A这个变量呢就负了,为了一,B等于二的话呢,那么B这个变量就负为了二,那么我这个A加上B,我在一个回车的话呢,那么它应该输出一个三对吧?那这个就是一个呃带负值的计算器对吧?当然它呃还需要执行一些比较复杂的,比方说我一加上呃这个二。乘以三对吧。二乘以三或者说这个我们把这个括,我们需要支持括号对吧,一加上二呃乘以三我们需要支持这个加减乘除对吧?四则运算以及括号来表示它的优先级,然后呢,我们还要简单的来支持一下赋值,我们就实现这样的一个呃,小型的带负值的这样的一个计算器,呃,来。
16:03
熟悉一下安塔R4的呃,它的这样的一个使用,对吧,实际上你呃从那你就可以看得出来,这个其实就是一个小型的有点类似于像编程语言的东西,对吧?好,那我们现在的话呢,我们就来研究一下这个S呢,它具体是如何使用的对不对?OK,我在这里边的话呢,我还是新建一个软件包,叫做呃,An。Lr tutorial。啊,我们直接使用最新版的安泰L对吧?呃,当然我们的依赖呢,也已经导到了POM文件里边,在这么样安泰l run态我们直接使用最新版,呃。你你之后如果想要去看一些类似于have源码的话呢,你要注意,呃,Have可能使用的是呃anti r它的旧版本的对吧,可能它使用的是安泰R3好,然后呢,我们在这个。软件包里边呢,创建一个文件叫做什么呢?叫做calculator.J4。
17:08
对吧,那么这个calculator这是什么呢?代负值。对吧,也就是我们在这里面代赋值的计算器的语法定义文件,对吧,这个东西,哎,这个是一个带赋值的语法定义文件,安特R4呢,它是以点G4为后缀的,对吧?点G4为后缀的,然后呢,我们在这的话呢,我们首先声明它是一个语法定义文件,注意这儿的话呢,要和呃它的文件名呢是一样的,对吧,就是呃calculator,所以说这个呢是哎语法。呃,这个。的名字,也就是我们这个带赋值的计算器的语法名字,然后接下来的话呢。我们带负值的计算器呢,它显然是由语句来组成的,对吧?显然是由语句来组成,第一个是一加二这样的一个表达式语句,第二个是赋值语句,第三个也是赋值语句,第四个是表达式语句,对吧?因为你回车以后,我是要计算出一个结果来的,当然这个也是一个表达式语句。所以说呢,我们的。
18:24
呃,这个带赋值计算器,它应该是由一系列的语句来组成的,对吧,一系列的语句来组成的,呃,所以在这里边的话呢。Program。也就是说。呃,我们的这个。程序它是statement的家,对吧?它是由一系列的语句来构成的,对吧。程序program是由。一系列语句构成的,对吧?那么这的加号表示什么呢?表示就是对吧,正则语法一个或者多个,实际上这种表示语法的方式呢,它有一个专门的名字叫做ebnf,对吧,E bnf。
19:13
语法表示法,对吧?扩展的八次诺尔范式的表示法,呃,这些东西其实都在边原理里边对吧?然后呢,左边哎,Program是定义,右边呢是它这个定义呢,呃,就是说右边呢,是它是由什么构成的,对吧?我们这面是由一个或者多个表达式构成对吧?加号表示一个或者多个,好,我现在定义了program,但是我还没有定义statement对吧,我还没有定义语句。那么语句又是由什么构成的呢?对不对?我们在这边statement它由什么构成对吧?它是由表达式加上换行符构成的。
20:02
对吧,它是由表达式加换行符构成的。那么这个是,呃,我们看一下啊,就是说我们的这个语句呢,有三种情况。语句有三种情况,那么第一种的话呢,是表达式换行符对吧?这是第一种语句啊,那么第二种语句是什么呢?那么第二种语句是赋值语句对吧?那么赋值语句的语法是什么呢?是标识符。对吧,等于一个。对不对表达式。然后换行符,那么第三种语句是什么呢?第三种语句就是换行符也可以直接作为一个语句,对吧?换行符也可以直接作为一个语句好。然后呢,我们现在是一个expression,然后new line,然后回车竖杠对吧,或者的意思ID等于expression对吧。
21:14
ID是标识符。Expression表达式等号赋值操作。呃,当然不要忘记一个换行符,好,那么第三个换行符直接作为一个表达式,对吧,然后不要忘记分号,OK,我们现在呢。呃,就是说语句呢,已经给它定义好了,但是你会发现哎,表达式个标红啊,因为我们这个expression表达式的语法,我们并没有对它进行呃定义,对吧,那我们这里边表达式分为哪几种呢。乘除对吧。加减。对吧,包括int整形,它自己就是一个表达式。对吧,那么赋值,呃,那么我们的这个标识符或者说变量名,它本身也是个表达式对吧,然后呢,就是由括号括起来的。
22:06
表达式对吧,它也是一个表达式,所以我们这边我们继续分类来定义expression冒号expression对不对,Op等于我们的运算符一个是。程浩。那么除了乘号以外呢,那么还有一个就是除号对吧,当然这个。呃,就是说运算符的左边和右边呢,它都必须是表达式对吧。我这个乘号除号的左右两边。你肯定也得是表达式啊,对不对,那么接下来我们除了乘除以外呢,然后我们在这里边还有什么呢?还有加减对吧。
23:00
还有加减,当然加减法的左右两边呢,也是表达式,当然为什么我要把乘除。放在上面呢,加减放在下面呢,因为乘除比加减的优先级要更高对吧?好OK,那么第三种表达是什么呢?Int,你作为一个整形来讲,它也可以是个表达式,然后第四种的话呢,是ID对吧?变量名它也可以是个表达式,然后呢,我圆括号对吧?圆括号中间给它再放一个expression呢。也就是说我用括号把表达式括起来,那它还是一个表达式对吧,那这样的话,我们所有的表达式呢,就分类完毕了,好,当然更复杂的编程语言的话,它表达式可能会更复杂对吧?比方说呃,还有微运算呀,逻辑逻辑左移啊,逻辑右移对不对。等等之类的一些语法OK啊,那在这的话呢,我们还有一些没有定义的,比方说这个ID。
24:00
变量名儿对吧。它并没有被定义,比方说ink是什么也没有定义,New life是什么也没有被定义,所以说你需要把它没有定义的语法呢,都给它定义出来,比如说在这里边ID对不对,我们这个是变量名,对吧。那么变量名它必须符合什么样的规则呢?我们这边简单一点,A到在A到Z,然后呢,来一个加号,也就是说它是一个大小写字母对吧,一个或者多个大小写字母,这个就变量名,当然就是说你Java里面的变量名的话呢,呃,可能还支持类似于像什么下划线呀,呃,什么数字呀等等等等,对吧?当然我们在这儿的话,我们就简化了我们的这个变量名呢,呃,就是说只支持大小写字母对吧,变量名。对不对,一个或者多个。
25:02
大小写字母好,那么还有呢,就是整形对不对,那么整形的话就是int,我们整形的话呢,是一个零到九,然后加号好,那这个是整形。那第三个的话呢,那就是说对吧,换行符,那这个换行符的话,那就是一个new line冒号。啊,当然这个换行符呢,我们在这儿的话,为了兼容一下,呃,就是我们把杠R和杠N都给它加上对吧,比方说这个问号的话呢,就是说我杠R可以出现零次或者一次对吧?然后呢,杠N的话呢,呃,必须出现,那这个就是换行符啊。OK,那么换行符我们也定义好了,然后呢,我们还需要跳过所有空白字符对吧,那在这的话就是WS。空格跳过斜杠T跳过对吧,然后加。
26:04
也就是说你不管有几个空白符对吧,制表符和空格,我都直接给他跳过箭头skip,哎,这样就跳过了,好OK,呃,实际上我们这样的一个语法文件呢,就已经定义好了,对吧?就已经定义好了,呃,但是它在转换成程序的时候呢,呃,可能就是说它自动生成的一些这个方法名和变量名呢,可能并不是那么容易去,呃,就是说可读性并不是那么强,对吧?所以说我们需要起名字对不对,比如说在这里边。我这个op等于乘号和除号,这表示什么呢?我们在里边我们就写一个注释对吧,那这个就是op是我们给运算符取的名字对吧?Op是我们给运算符取的名字。
27:00
然后呢,我们还可以给这些语法命名规则呢,给它起一些名字对吧,比如说在这儿的话呢,它怎么起呢,它使用一个井号这样的一个语法,对吧,井号print。Expression,对吧?也就是说我给这一行语法呢,起了一个名字叫做print expression对吧?Print expression好。然后呢,我第二行的话呢,我给它起一个名字叫做啊赛。对吧,然后第三行呢,我给它起一个名字叫做blank,也就是呃,空白的对吧,也就是我们在这的话呢。在ANTL4中。对吧,井号可以为语法规则取名字,这样它生成的呃方法名呢,就比较可读了,生成方法名比较可读了,好啊,那接下来呢,我们继续取名字对吧,比如说在这的话呢,我给它取一个名字叫做呃骂。
28:13
Dive对吧,也就是乘除,那这个的话呢,我给它取一个名字叫做ADD sub。对吧,然后这个int呢,我给它取一个名字就叫做int吧,然后这个ID呢,我给它取一个名字就叫做ID。然后呢,最后一个呢,我给他取一个名字叫做parents对吧,这个parents的意思呢,是括号的意思,也就是它是括号表达式,这个是int表达式,这是ID表达式,这个是加减表达式,这个是乘除表达式,好。然后呢,我们把这个加减乘除号呢,都给它取一个别名对吧?呃,也也是方便我们后面写代码嘛,然后。
29:00
它是乘号的意思对吧,然后呢,Div冒号,它是除号的意思对吧,然后呢,还有ADD冒号啊,那么这个I的冒号呢,它是加号的别名对吧?我们都要以分号为结尾对吧?Subb呢,它是减号的,呃,这样的一个别名,好,那这样的话呢,我们的。语法分语法文件,也就是我们这个计算器的语法文件呢,就已经定义完了,就已经定义完了。
我来说两句