Apache Calcite教程-Schema,Table.自定义Schema,自定义Table

Github

Apache Calcite - schema

schema其实就是表的结构(行列信息),
schema相关类主要存放在org.apache.calcite.schema包下,
此包中的接口定义SQL验证器使用的对象,以验证SQL抽象语法树并将标识符解析为对象。

schema - 常用类

本文只重点介绍Schema,Table,ScheamFactory,TableFactory的使用,其他类的使用会在日后文章中介绍

Schema

Schema为表和函数的命名空间,一个schema可以包括多个子schema

常用方法

  • Table getTable(String name); 根据表名称,获取表信息
  • Set getTableNames(); 获取全部表名称
  • Collection getFunctions(String name); 获取function信息
  • Set getFunctionNames(); 获取所有function名称
  • Schema getSubSchema(String name); 获取子schema
  • Set getSubSchemaNames(); 获取所有子schema的名称
AbstractSchema

Schema的默认实现类,实现了部分方法
用户自定义的schema一般基于这个类实现

SchemaPlus

Schema的包装类,用户使用的时候不需要实现这个类的接口

SchemaFactory

Schema的工厂类,模式工厂允许您在模型文件中包含自定义模式。
例如从一个json文件中共创建schema
用户一般基于这个类创建为自定义工厂

Table

表信息

  • RelDataType getRowType(RelDataTypeFactory typeFactory); 获取表的行类型
  • Statistic getStatistic(); 获取表的信息
  • Schema.TableType getJdbcTableType(); 获取jdbc的tableType
  • boolean isRolledUp(String column); 给定列是否可以累加
  • boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, SqlNode parent, CalciteConnectionConfig config);
    给定列是否可以使用聚合函数
AbstractTable

Table接口的默认抽象类
用户一般看情况,是否基于这个类来实现,或者基于这个类的子类实现

ScannableTable

可以在不创建中间关系表达式的情况下扫描的表。

QueryableTable

可以将Table转换为Queryable

TranslatableTable

Table翻译成RelNode

FilterableTable

将过滤器传递进入表中,从而可以减少部分计算逻辑

ProjectableFilterableTable

将过滤器和投影传递进入表中,从而可以减少部分计算路基

StreamableTable

将表转换成一个流

AbstractQueryableTable

AbstractTableQueryableTable的抽象类

TableFactory

Table工厂类,模式工厂允许您在模型文件中包含自定义模式。
例如从一个json文件中共创建table
用户一般基于这个类创建为自定义工厂

Statistic

表的统计系统

Function

函数

ScalarFunction

带返回值的函数

TableFunction

执行期间的函数信息

FunctionParameter

函数参数

Apache Calcite - model

org.apache.calcite.model
提供JSON格式的模型文件或者YAML格式的模型的解析
用户可以通过实现SchemaFactoryTableFactory定义自己的模式

JsonXXX

配置信息的解析对应的实体类

ModelHandler

主要解析json和yaml文件
calcite主要通过driver建立连接时解析对应的schema和table.

Driver类调用org.apache.calcite.jdbc.Driver.createHandler,创建ModelHandler解析schema和table,之后将schema和table设置回connect

具体实现代码

列信息

/**
 * 列信息
 * @author quxiucheng
 * @date 2019-04-26 11:18:00
 */
@Data
public class TutorialColumn implements Serializable {
    /**
     * 字段名称
     */
    private String name;

    /**
     * 字段类型名称
     */
    private String type;

}

自定义table


import lombok.Data;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.schema.impl.AbstractTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Pair;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义table
 * @author quxiucheng
 * @date 2019-04-26 11:17:00
 */
@Data
public class TutorialTable extends AbstractTable implements Serializable {
    /**
     * 表名称
     */
    private String name;

    /**
     * 列信息
     */
    private List<TutorialColumn> columnList;


    /**
     * 获取行类型
     * @param typeFactory
     * @return
     */
    @Override
    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        List<String> names = new ArrayList<>();
        List<RelDataType> types = new ArrayList<>();
        for (TutorialColumn sqlExecuteColumn : columnList) {
            names.add(sqlExecuteColumn.getName());
            RelDataType sqlType = typeFactory.createSqlType(SqlTypeName.get(sqlExecuteColumn.getType().toUpperCase()));
            types.add(sqlType);
        }
        return typeFactory.createStructType(Pair.zip(names, types));
    }
}

自定义schema


import com.google.common.collect.Maps;
import lombok.Data;
import lombok.NonNull;
import org.apache.calcite.schema.Table;
import org.apache.calcite.schema.impl.AbstractSchema;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 自定义schema
 * @author quxiucheng
 * @date 2019-04-26 11:16:00
 */
@Data
public class TutorialTableSchema extends AbstractSchema implements Serializable {

    /**
     * schema名称
     */
    private String name;

    /**
     * table信息
     */
    private List<TutorialTable> tableList;

    public TutorialTableSchema(@NonNull String name, @NonNull List<TutorialTable> tableList) {
        this.name = name;
        this.tableList = tableList;
    }


    /**
     * 获取该schema中所有的表信息
     *
     * @return
     */
    @Override
    protected Map<String, Table> getTableMap() {
        Map<String, Table> tableMap = Maps.newHashMap();
        for (TutorialTable table : this.tableList) {
            tableMap.put(table.getName(), table);
        }
        return tableMap;
    }

}

table工厂


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Table;
import org.apache.calcite.schema.TableFactory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * table工厂
 * @author quxiucheng
 * @date 2019-04-26 11:20:00
 */
public class TutorialTableFactory implements TableFactory {

    /**
     * yaml解析器
     */
    private static final ObjectMapper YAML_MAPPER = new YAMLMapper();

    /**
     * 创建table
     * @param schema
     * @param name
     * @param operand
     * @param rowType
     * @return
     */
    @Override
    public Table create(SchemaPlus schema, String name, Map operand, RelDataType rowType) {
        try {
            String ddl = (String) operand.get("ddl");
            return YAML_MAPPER.readValue(new File(ddl), TutorialTable.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

schema工厂


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaFactory;
import org.apache.calcite.schema.SchemaPlus;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * schema工厂类
 * @author quxiucheng
 * @date 2019-04-26 11:19:00
 */
public class TutorialSchemaFactory implements SchemaFactory {

    private static final ObjectMapper JSON_MAPPER = new ObjectMapper()
            .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
            .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
            .configure(JsonParser.Feature.ALLOW_COMMENTS, true);

    /**
     * 创建schema
     * @param parentSchema
     * @param name
     * @param operand
     * @return
     */
    @Override
    public Schema create(SchemaPlus parentSchema, String name, Map<String, Object> operand) {
        try {
            List<TutorialTable> tableList = new ArrayList<>();

            ArrayList tables = (ArrayList) operand.get("tables");
            for (Object table : tables) {
                String ddl = (String) ((HashMap) table).get("ddl");
                TutorialTable tutorialTable = JSON_MAPPER.readValue(new File(ddl), TutorialTable.class);
                tableList.add(tutorialTable);

            }
            return new TutorialTableSchema(name, tableList);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

model文件

{
  "version": "1.0",
  "defaultSchema": "tutorial",
  "schemas": [ {
    "name": "tutorial",
    "type": "custom",
    "factory": "com.github.quxiucheng.calcite.schema.tutorial.TutorialSchemaFactory",
    "operand": {
      "tables": [
        {
        "ddl": "calcite-tutorial-3-schema/src/main/resources/user/user.json",
        "data": "calcite-tutorial-3-schema/src/main/resources/user/user.txt"
      },{
        "ddl": "calcite-tutorial-3-schema/src/main/resources/role/role.json",
        "data": "calcite-tutorial-3-schema/src/main/resources/role/role.txt"
      }
      ]
    }
  } ]
}

后记

本文只介绍schema相关的信息,不介绍如何进行查询等,等信息

  1. type等类在日后type中介绍.
  2. relXXX等相关实体类在日后转换关系表达式介绍.
  3. Enumerable,Queryable等实体信息在日后查询时介绍

代码实例

https://github.com/quxiucheng/apache-calcite-tutorial/tree/master/calcite-tutorial-3-schema

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache Calcite是一个灵活的SQL解析器框架,可以用于解析和优化SQL查询语句,支持多种数据库,包括MySQL、Oracle、SQL Server、PostgreSQL等。下面是Apache Calcite的使用方法: 1. 引入依赖 在项目的pom.xml文件中添加Apache Calcite的依赖: ```xml <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-core</artifactId> <version>1.26.0</version> </dependency> ``` 2. 创建SQL解析器 使用Apache Calcite的SQL解析器,可以将SQL语句解析成AST(抽象语法树)。AST是一种用于表示SQL语句结构的数据结构,可以用于进一步分析和优化SQL查询语句。 ```java import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SqlParserConfig config = SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build(); SqlParser parser = SqlParser.create(sql, config); SqlNode node = parser.parseQuery(); System.out.println(node.getClass().getSimpleName()); } } ``` 以上代码演示了如何创建一个SQL解析器,解析一个SELECT语句,并输出AST的型。 3. 访问AST AST是一个树形结构,可以使用Visitor模式来访问AST的节点。Apache Calcite提供了许多访问AST节点的Visitor,可以方便地遍历AST的节点。 ```java import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SqlParserConfig config = SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build(); SqlParser parser = SqlParser.create(sql, config); SqlNode node = parser.parseQuery(); node.accept(new SqlBasicVisitor<Void>() { @Override public Void visit(SqlIdentifier id) { System.out.println(id.getName()); return null; } }); } } ``` 以上代码演示了如何访问AST的节点,使用SqlBasicVisitor来访问SqlIdentifier节点,并输出节点的名称。 4. 优化查询 AST可以用于进一步优化SQL查询语句。Apache Calcite提供了许多优化器,可以根据AST的结构进行优化,例如选择最优的执行计划、推导查询条件、消除冗余计算等。 ```java import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.plan.*; import org.apache.calcite.prepare.CalcitePrepareImpl; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; import org.apache.calcite.sql2rel.SqlToRelConverter; import org.apache.calcite.tools.*; import org.apache.calcite.util.Util; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SchemaPlus schema = Frameworks.createRootSchema(true); FrameworkConfig config = Frameworks.newConfigBuilder() .defaultSchema(schema) .parserConfig(SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build()) .build(); Planner planner = Frameworks.getPlanner(config); SqlNode node = planner.parse(sql); SqlValidator validator = planner.getValidator(); SqlNode validatedNode = validator.validate(node); RelDataTypeFactory typeFactory = planner.getTypeFactory(); JavaTypeFactory javaTypeFactory = new JavaTypeFactoryImpl(typeFactory); SqlToRelConverter.Config converterConfig = SqlToRelConverter.configBuilder() .withTrimUnusedFields(false) .build(); SqlToRelConverter converter = new SqlToRelConverter( new CalcitePrepareImpl.PlannerImpl(planner, converterConfig), validator, schema, javaTypeFactory, converterConfig); RelNode relNode = converter.convertQuery(validatedNode, false, true); RelOptPlanner optPlanner = relNode.getCluster().getPlanner(); optPlanner.setRoot(relNode); RelTraitSet traitSet = optPlanner.emptyTraitSet().plus(RelCollations.EMPTY); RelNode optimizedNode = optPlanner.findBestExp(traitSet, relNode); System.out.println(Util.toLinux(optimizedNode.toString())); } } ``` 以上代码演示了如何使用Apache Calcite进行SQL查询语句的优化。首先创建一个Planner对象,然后使用Planner解析和验证SQL语句。接着使用SqlToRelConverter将SQL语句转换为RelNode对象,最后使用RelOptPlanner进行优化,得到最优的执行计划。 以上就是Apache Calcite的使用方法,你可以根据需要使用它来解析和优化SQL查询语句。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值