在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. web.xml的作用及基本配置

    web工程中的web.xml文件有什么作用呢?它是每个web.xml工程都必须的吗? 一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的.那什么时候需要,什 ...

  2. python——如何import包目录

    文件位置 文件所在位置包括 , 源根目录的位置 该文件位置(也可以叫相对位置). 导入包的时候会从文件位置进行查找,并导入. 导入包 1. 什么是包? pycharm中包的图片 其中文件夹上有个圆点的 ...

  3. Django-初见

    目录 安装&启动 HTTP请求URL路由 项目APP 返回 页面内容 给浏览器 路由 路由子表 创建数据库 定义数据库表 创建数据库表 Django Admin 读取数据库数据 过滤条件 对资 ...

  4. k8s,coredns内部测试node节点上的pod的calico是否正常的一个小技巧

    最近由于master整个挂掉,导致相关一些基础服务瘫掉,修复中测试有些节点网络又出现不通的情况正常的启动相关一些服务后,测试一些节点,比较费劲,还有进入pod,以及还有可能涉及命名空间操作这里可以这样 ...

  5. IETF 官网

    IETF 官网 https://www.ietf.org/ IETF数据追踪网站: https://datatracker.ietf.org/

  6. java_类的访问控制符

    1.分类: public protected default private是java中的访问控制修饰符. public String name; protected String name; Str ...

  7. 1s 创建100G文件,最快的方法是?

    在我们日常工作中,为了验证开发的功能,比如:文件上传功能或者算法的处理效率等,经常需要一些大文件进行测试,有时在四处找了一顿之后,发现竟然没有一个合适的,虽然 Linux 中也有一些命令比如:vim. ...

  8. Java学习day26

    进程.多任务 1.例如吃饭的时候玩手机,边上厕所边玩手机,看似是同时做多个事情,本质上我们的大脑在同一时间只做了一件事情,这就是多任务 2.道路窄的时候容易造成拥堵,可以拓宽道路,加多车道,同一个方向 ...

  9. 使用 HTML5 input 类型提升移动端输入体验(转翻译)

    在过去的几年里,在移动设备上浏览网页已变得难以置信的受欢迎. 但是这些设备上的浏览体验,有时遗留很多的有待改进.当涉及到填写表单时,这一点尤为明显.幸运的是,HTML5规范引入了许多新input类型, ...

  10. 2021.07.02 P1383 高级打字机题解(可持久化平衡树)

    2021.07.02 P1383 高级打字机题解(可持久化平衡树) 分析: 从可以不断撤销并且查询不算撤销这一骚操作可以肯定这是要咱建一棵可持久化的树(我也只会建可持久化的树,当然,还有可持久化并查集 ...