在Flink SQL中, 元数据的管理分为三层: catalog-> database-> table,

我们知道Flink SQL是依托calcite框架来进行SQL执行树生产,校验,优化等等, 所以本文讲介绍FlinkSQL是如何来结合Calcite来进行元数据管理的.

calcite开放的接口

public interface Schema {
Table getTable(String name); Schema getSubSchema(String name); ....
}

如接口所示, Schema接口,可以通过table名来获得一张表, 可以通过schema名来获得一个子schema.

public interface Table {
RelDataType getRowType(RelDataTypeFactory typeFactory);
....
}

看Table的接口, 主要就是返回table的RelDataType.

Flink的相关实现

接下来,我们来看下Flink是如何实现这些接口的:

public class CatalogManagerCalciteSchema extends FlinkSchema {
@Override
public Schema getSubSchema(String schemaName) {
if (catalogManager.schemaExists(name)) {
return new CatalogCalciteSchema(name, catalogManager, isStreamingMode);
} else {
return null;
}
}
}
public class CatalogCalciteSchema extends FlinkSchema {
@Override
public Schema getSubSchema(String schemaName) {
if (catalogManager.schemaExists(catalogName, schemaName)) {
return new DatabasecalciteSchema(schemaName, catalogNmae, catalogManager, isStreamingMode);
}
}
}
public class DatabaseCalciteSchema extends FlinkSchema {
private final String databaseName;
private final String catalogName;
private final CatalogManager catalogManager; @Override
public Table getTable(String tableName) {
ObjectIdentifier identifier = ObjectIdentifier.of(catalogName, databaseName, tableName);
return catalogManager.getTable(identifier)
.map(result -> {
CatalogBaseTable table = result.getTable();
FlinkStatistic statistic = getStatistic(result.isTemporary(), table, identifier);
return new CatalogSchemaTable(identifier,
table,
statistic,
catalogManager.getCatalog(catalogName)
.flatMap(Catalog::getTableFactory)
.orElse(null),
isStreamingMode,
result.isTemporary());
})
.orElse(null);
} @Override
public Schema getSubSchema(String name) {
return null;
}
}

很容易发现,CatalogSchema返回DatabaseSchema, DatabaseSchema返回Table,

这样就容易理解,Flink的三层结构是怎样的了. 同时, 具体的元数据实际上都是在catalogManager中。

DatabaseSchema中返回的Table类型为CatalogSchemaTable,我们来看下具体的结结构是怎样的,

上文中也提到了,Table接口主为getRowType函数, 用于返回某个table的type信息。

TableSchema是Flink内部用于保存各个字段的类型信息的类, 通过相关的转化函数,转换为calcite的type类型.

public class CatalogSchemaTable extends AbstractTable implements TemporalTable {

	private final ObjectIdentifier tableIdentifier;
private final CatalogBaseTable catalogBaseTable;
private final FlinkStatistic statistic;
private final boolean isStreamingMode;
private final boolean isTemporary;
...
private static RelDataType getRowType(RelDataTypeFactory typeFactory,
CatalogBaseTable catalogBaseTable,
boolean isStreamingMode) {
final FlinkTypeFactory flinkTypeFactory = (FlinkTypeFactory) typeFactory;
TableSchema tableSchema = catalogBaseTable.getSchema();
final DataType[] fieldDataTypes = tableSchema.getFieldDataTypes();
if (!isStreamingMode
&& catalogBaseTable instanceof ConnectorCatalogTable
&& ((ConnectorCatalogTable) catalogBaseTable).getTableSource().isPresent()) {
// If the table source is bounded, materialize the time attributes to normal TIMESTAMP type.
// Now for ConnectorCatalogTable, there is no way to
// deduce if it is bounded in the table environment, so the data types in TableSchema
// always patched with TimeAttribute.
// See ConnectorCatalogTable#calculateSourceSchema
// for details. // Remove the patched time attributes type to let the TableSourceTable handle it.
// We should remove this logic if the isBatch flag in ConnectorCatalogTable is fixed.
// TODO: Fix FLINK-14844.
for (int i = 0; i < fieldDataTypes.length; i++) {
LogicalType lt = fieldDataTypes[i].getLogicalType();
if (lt instanceof TimestampType
&& (((TimestampType) lt).getKind() == TimestampKind.PROCTIME
|| ((TimestampType) lt).getKind() == TimestampKind.ROWTIME)) {
int precision = ((TimestampType) lt).getPrecision();
fieldDataTypes[i] = DataTypes.TIMESTAMP(precision);
}
}
}
return TableSourceUtil.getSourceRowType(flinkTypeFactory,
tableSchema,
scala.Option.empty(),
isStreamingMode);
}
}

CatalogBaseTable接口定义如下, Flink的Table的参数(schema参数,connector参数)都可以最终表示为一个map.

public interface CatalogBaseTable {
/**
* Get the properties of the table.
*
* @return property map of the table/view
*/
Map<String, String> getProperties(); /**
* Get the schema of the table.
*
* @return schema of the table/view.
*/
TableSchema getSchema(); /**
* Get comment of the table or view.
*
* @return comment of the table/view.
*/
String getComment(); /**
* Get a deep copy of the CatalogBaseTable instance.
*
* @return a copy of the CatalogBaseTable instance
*/
CatalogBaseTable copy(); /**
* Get a brief description of the table or view.
*
* @return an optional short description of the table/view
*/
Optional<String> getDescription(); /**
* Get a detailed description of the table or view.
*
* @return an optional long description of the table/view
*/
Optional<String> getDetailedDescription();
}

FlinkSchema的使用

上面都是的相关接口都是Flink用于适配calcite框架元数据的相关实现。

那么这些类具体是在哪里调用的? 已经什么时候会被调用到?

calcite中的schema,主要是在validate过程中, 获得对应table的字段信息, 对应的function的返回值信息,

确保SQL的字段名, 字段类型是正确的.

类的依赖关系为:

validator ---> schemaReader ---> schema

FlinkPlannerImpl.scala中

  private def createSqlValidator(catalogReader: CatalogReader) = {
val validator = new FlinkCalciteSqlValidator(
operatorTable,
catalogReader,
typeFactory)
validator.setIdentifierExpansion(true)
// Disable implicit type coercion for now.
validator.setEnableTypeCoercion(false)
validator
}

PlanningConfigurationBuilder.java

	private CatalogReader createCatalogReader(
boolean lenientCaseSensitivity,
String currentCatalog,
String currentDatabase) {
SqlParser.Config sqlParserConfig = getSqlParserConfig();
final boolean caseSensitive;
if (lenientCaseSensitivity) {
caseSensitive = false;
} else {
caseSensitive = sqlParserConfig.caseSensitive();
} SqlParser.Config parserConfig = SqlParser.configBuilder(sqlParserConfig)
.setCaseSensitive(caseSensitive)
.build(); return new CatalogReader(
rootSchema,
asList(
asList(currentCatalog, currentDatabase),
singletonList(currentCatalog)
),
typeFactory,
CalciteConfig.connectionConfig(parserConfig));
}

综上所诉, 我们就知道了Flink是如何来利用calcite的schema来管理Flink的table信息的.

FlinkSQL源码阅读-schema管理的更多相关文章

  1. Linux 源码阅读 进程管理

    Linux 源码阅读 进程管理 版本:2.6.24 1.准备知识 1.1 Linux系统中,进程是最小的调度单位: 1.2 PCB数据结构:task_struct (Location:linux-2. ...

  2. 【面试】足够“忽悠”面试官的『Spring事务管理器』源码阅读梳理(建议珍藏)

    PS:文章内容涉及源码,请耐心阅读. 理论实践,相辅相成 伟大领袖毛主席告诉我们实践出真知.这是无比正确的.但是也会很辛苦. 就像淘金一样,从大量沙子中淘出金子一定是一个无比艰辛的过程.但如果真能淘出 ...

  3. LevelDB(v1.3) 源码阅读之 Arena(内存管理器)

    LevelDB(v1.3) 源码阅读系列使用 LevelDB v1.3 版本的代码,可以通过如下方式下载并切换到 v1.3 版本的代码: $ git clone https://github.com/ ...

  4. Spring源码阅读笔记

    前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...

  5. 淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划

    body, td { font-family: tahoma; font-size: 10pt; } 淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划 SQL编译解析三部曲分为 ...

  6. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

  7. 【原】AFNetworking源码阅读(三)

    [原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...

  8. 【原】SDWebImage源码阅读(三)

    [原]SDWebImage源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1.SDWebImageDownloader中的downloadImageWithURL 我们 ...

  9. [Erlang 0119] Erlang OTP 源码阅读指引

      上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的?   "代码去哪里找?",关于Erla ...

随机推荐

  1. JavaScript面向对象的方式开发轮播图插件

    轮播图是很多页面必不可少的组件.这里来使用面向对象方式开发一个插件.减去开发的痛楚 首先需要寻找对象:只有一个对象,轮播图!关键点在于找到这个对象所拥有的属性以及方法,通过代码实现出来,这是面向对象最 ...

  2. 记一次使用git报错,解决Unable to negotiate with **** port 22: no matching host key type found. Their offer: ssh-rsa

    windows电脑重装系统,去官网下载了最新的git安装,一路next下来,打开bash按老路子设置,生成公钥 git config --global user.name "yourname ...

  3. 2021年iOS 开发者账号申请-最新

    前言 现在已经是2021年了,中国国内的互联网生态国家管控越来越严禁,国家反垄断法,未成年人游戏限制,整治娱乐圈不良文化,出台公民网络个人信息保护法,全网进行app 应用进行安全审查,等等等,无不意味 ...

  4. 帝国CMS如何互相转移分表之间的数据

    最近发现帝国CMS文章数据添加太多到某一张分表中了,如图 这是极其不合理的,需要优化下,所以这篇文章要告诉大家的也就是如何互相转移分表之间的数据. 我现在要将:phome_ecms_news_data ...

  5. HTML/CSS+JS制作一个高考倒计时页面

    2020-07-09更新 修复倒计时归零后出现负数的bug 自动切换至下一年日期 ##效果展示 前言 在B站上找视频学习的,勉强搞出来了,写下此篇文章作为笔记,也希望有更多感兴趣的人能够有所收获. ( ...

  6. 【LeetCode】24.两两交换链表中的节点

    24.两两交换链表中的节点 知识点:链表 题目描述 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点.你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换). 示例 示例 1 ...

  7. Visual Studio2019 F5调试程序时选择文件后调试控制台进程关闭问题

    问题:Visual Studio2019 F5调试程序时选择文件后调试控制台进程关闭问题 解决方案: 修改Visual Studio 配置项 [工具]-[选项]-[项目和解决方案]-[Web项目]-[ ...

  8. CoAP调试工具Mozi.IoT.CoAP应用详解

    前言 CoAP是一种类HTTP协议的物联网专用协议,其数据包为人类不可阅读的字节流形式,在开发相关应用的时候往往不能准确的了解数据包的内容.故需要专用的调试工具对数据和通讯进行调试.这篇文章是为了让开 ...

  9. 简单几步解决ie打不开闪退的问题 亲测有效

    起因: 银行U盾插入 IE自动打开银行门户网站 打不开 闪退 不插入之后 IE还是闪退, 修复之法 清除IE扩展 一些自己安装的扩展或是被恶意安装的扩展插件会导致IE无法启动 1. 按住windows ...

  10. 《Streaming Systems》第三章: Watermarks

    定义 对于一个处理无界数据流的 pipeline 而言,非常需要一个衡量数据完整度的指标,用于标识什么时候属于某个窗口的数据都已到齐,窗口可以执行聚合运算并放心清理,我们暂且就给它起名叫 waterm ...