[Apache Calcite]如何在Apache Calcite里使用RelBuilder引用字段?

方法

org.apache.calcite.tools.RelBuilder#field

核心方法

org.apache.calcite.tools.RelBuilder#field(int inputCount, int inputOrdinal, int fieldOrdinal,boolean alias)

inputCount:当前数据源(输入的表)的数量

inputOrdinal:在当前上下文中数据源的下标

fieldOrdinal:在当前上下文中字段的下标

alias:是否别名

讲解

元数据

testdb.travelrecord(id,user_id,traveldate,fee,days,blob,d) 7个字段

testdb.address(id,address) 2个字段

 

        RelBuilder relBuilder = RelBuilder.create(config);
        RelNode table = relBuilder
                .scan("testdb","travelrecord")
                .scan("testdb","address")
                .join(JoinRelType.INNER, relBuilder.equals(relBuilder.field(2,0,0),relBuilder.field(2,1,1)))
                .filter(relBuilder.and(relBuilder.equals(relBuilder.field(1,0,"id"),relBuilder.literal(1))))
                .project(relBuilder.field(1,0,0), relBuilder.field(1,0,1))
                .build();

               

join(JoinRelType.INNER, relBuilder.equals(relBuilder.field(2,0,0),relBuilder.field(2,1,8)))

2是当前的数据源数量,即testdb.travelrecord和testdb.address两个

relBuilder.field(2,0,0)中的第一个0是testdb.travelrecord所在的下标

relBuilder.field(2,1,1)中的1是testdb.address所在的下标

 

在join之后,字段按照数据源的顺序在栈顶依次排开

 

alias:是否别名,此参数一般为false

如果为true,同时指向的字段名与数据源字段不符,则建立别名字段

否则,直接指向数据源的输入值

 

以此封装得到下面的方法

public RexInputRef field(int inputCount, int inputOrdinal, int fieldOrdinal) //alias = false
public RexInputRef field(int fieldOrdinal)//inputCount = 1,inputOrdinal = 0
public RexInputRef field(int inputCount, int inputOrdinal, String fieldName)//根据上下文查找字段的下标
public RexInputRef field(String fieldName)//inputCount = 1,inputOrdinal = 0
public RexNode field(int inputCount, String alias, String fieldName) //引用别名和目标数据源字段名都相同的字段
public RexNode field(String alias, String fieldName)//inputCount = 1

错误例子

RelBuilder relBuilder = RelBuilder.create(config);
RelNode table = relBuilder
 .scan("testdb","travelrecord")
 .as("t")
 .scan("testdb","address")
 .as("a")
 .join(JoinRelType.INNER, relBuilder.equals(relBuilder.field("t","id"),
 relBuilder.field("a","id")))
 .filter(relBuilder.and(relBuilder.equals(relBuilder.field(1,0,"id"),relBuilder.literal(1))))
 .project(relBuilder.field(1,0,"id"), relBuilder.field(1,0,"user_id"))
 .build();
java.lang.IllegalArgumentException: no aliased field found; fields are: [\{aliases=[address, a],fieldName=id}, \{aliases=[address, a],fieldName=addressname}]java.lang.IllegalArgumentException: no aliased field found; fields are: [\{aliases=[address, a],fieldName=id}, \{aliases=[address, a],fieldName=addressname}] at org.apache.calcite.tools.RelBuilder.field(RelBuilder.java:511) at org.apache.calcite.tools.RelBuilder.field(RelBuilder.java:487)

无法根据上下文找到t.id,因为t不在栈顶,在栈顶的是a,此时把relBuilder.field("t","id")改为relBuilder.field(2,"t","id")即可

RelBuilder是使用栈来构建树,字段查找需要数据源在栈的位置和范围的信息,而relBuilder.field("t","id")假定了数据源只有一个的情况,也就是栈顶部第一个位置——栈顶。而

 .scan("testdb","travelrecord")
 .as("t")
 .scan("testdb","address")
 .as("a")

使t位于栈顶部第二个位置,所以relBuilder无法找到t。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值