[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。

 

 

你可能感兴趣的:(Apache,Calcite)