You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确序列化含BETWEEN过滤条件的Calcite RelNode?

Calcite RelBuilder构建Filter节点序列化AssertError问题解决

问题描述

我希望通过RelBuilder构建Calcite RelNode并序列化后发送至其他系统。但发现构建Filter节点时,条件会被简化为SEARCH类型的RexCall,其值为Sarg。使用RelJsonWriter序列化该RelNode时触发了AssertError,经排查是Sarg导致的。使用Calcite版本为calcite-core-1.32.0,请问我的使用方式是否有误?

测试代码如下:

@Test
public void buildFilterTest() {
    try {
        SchemaPlus rootSchema = Frameworks.createRootSchema(true);
        rootSchema.add("USERS", new AbstractTable() { // note: add a table
            @Override
            public RelDataType getRowType(final RelDataTypeFactory typeFactory) {
                RelDataTypeFactory.Builder builder = typeFactory.builder();
                builder.add("ID", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.INTEGER));
                builder.add("NAME", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.CHAR));
                builder.add("AGE", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.INTEGER));
                return builder.build();
            }
        });
        final FrameworkConfig config = Frameworks.newConfigBuilder().parserConfig(SqlParser.Config.DEFAULT)
                .defaultSchema(rootSchema).build();
        RelBuilder builder = RelBuilder.create(config);

        builder.scan("USERS");
        builder.project(builder.field("ID"));
        RexNode greater = builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field("ID"), builder.literal(0));
        RexNode lesser = builder.call(SqlStdOperatorTable.LESS_THAN, builder.field("ID"), builder.literal(100));
        builder.filter(builder.call(SqlStdOperatorTable.AND, greater, lesser));
        RelNode relNode = builder.build();

        RelJsonWriter writer = new RelJsonWriter();
        relNode.explain(writer);
        String res = writer.asString();
        log.info("success");
    } catch (AssertionError e) {
        e.printStackTrace();
    }
}

问题原因

Calcite的RelBuilder默认启用了Sarg优化,会将连续的范围条件(如ID>0 AND ID<100)合并为SEARCH类型的RexCall,内部用Sarg对象表示范围。但在1.32.0版本中,RelJsonWriter并未适配Sarg类型的RexNode,序列化时触发断言错误。

解决方案

通过禁用RelBuilder的Sarg优化来规避该问题,具体是在创建FrameworkConfig时,添加RelBuilder.Config并关闭Sarg转换:

修改后的代码如下:

@Test
public void buildFilterTest() {
    try {
        SchemaPlus rootSchema = Frameworks.createRootSchema(true);
        rootSchema.add("USERS", new AbstractTable() { // note: add a table
            @Override
            public RelDataType getRowType(final RelDataTypeFactory typeFactory) {
                RelDataTypeFactory.Builder builder = typeFactory.builder();
                builder.add("ID", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.INTEGER));
                builder.add("NAME", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.CHAR));
                builder.add("AGE", new BasicSqlType(new RelDataTypeSystemImpl() {}, SqlTypeName.INTEGER));
                return builder.build();
            }
        });
        // 新增RelBuilder配置,关闭Sarg转换
        RelBuilder.Config relBuilderConfig = RelBuilder.Config.DEFAULT.withConvertToSarg(false);
        final FrameworkConfig config = Frameworks.newConfigBuilder()
                .parserConfig(SqlParser.Config.DEFAULT)
                .defaultSchema(rootSchema)
                .relBuilderConfig(relBuilderConfig) // 将RelBuilder配置传入
                .build();
        RelBuilder builder = RelBuilder.create(config);

        builder.scan("USERS");
        builder.project(builder.field("ID"));
        RexNode greater = builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field("ID"), builder.literal(0));
        RexNode lesser = builder.call(SqlStdOperatorTable.LESS_THAN, builder.field("ID"), builder.literal(100));
        builder.filter(builder.call(SqlStdOperatorTable.AND, greater, lesser));
        RelNode relNode = builder.build();

        RelJsonWriter writer = new RelJsonWriter();
        relNode.explain(writer);
        String res = writer.asString();
        log.info("success");
    } catch (AssertionError e) {
        e.printStackTrace();
    }
}

关键修改点

  • 创建RelBuilder.Config实例,调用withConvertToSarg(false)关闭自动将范围条件转换为Sarg的优化
  • 将该RelBuilder配置通过relBuilderConfig()方法传入FrameworkConfig的构建流程中

这样修改后,Filter节点的条件会保持原本的AND连接的GREATER_THAN和LESS_THAN表达式,RelJsonWriter可以正常序列化,不会触发断言错误。

内容的提问来源于stack exchange,提问作者lulijun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:52:11