我正在使用给定的插入语句创建VoltDB表
CREATE TABLE EMPLOYEE (
ID VARCHAR(4) NOT NULL,
CODE VARCHAR(4) NOT NULL,
FIRST_NAME VARCHAR(30) NOT NULL,
LAST_NAME VARCHAR(30) NOT NULL,
PRIMARY KEY (ID, CODE)
);
然后使用
对表进行分区PARTITION TABLE EMPLOYEE ON COLUMN ID;
我写了一个spark作业将数据插入到VoltDB中,我正在使用下面的Scala代码将记录插入到VoltDB中,如果不对表进行分区,代码会很好地工作
import org.voltdb._;
import org.voltdb.client._;
import scala.collection.JavaConverters._
val voltClient:Client = ClientFactory.createClient();
voltClient.createConnection("IP:PORT");
val empDf = spark.read.format("csv")
.option("inferSchema", "true")
.option("header", "true")
.option("sep", ",")
.load("/FileStore/tables/employee.csv")
// Code to convert scala seq to java varargs
def callProcedure(procName: String, parameters: Any*): ClientResponse =
voltClient.callProcedure(procName, paramsToJavaObjects(parameters: _*): _*)
def paramsToJavaObjects(params: Any*) = params.map { param ⇒
val value = param match {
case None ⇒ null
case Some(v) ⇒ v
case _ ⇒ param
}
value.asInstanceOf[AnyRef]
}
empDf.collect().foreach { row =>
callProcedure("EMPLOYEE.insert", row.toSeq:_*);
}
但是如果我对表进行分区,我会遇到错误
Mispartitioned tuple in single-partition insert statement.
Constraint Type PARTITIONING, Table CatalogId EMPLOYEE
Relevant Tuples:
ID CODE FIRST_NAME LAST_NAME
--- ----- ----------- ----------
1 CD01 Naresh "Joshi"
at org.voltdb.client.ClientImpl.internalSyncCallProcedure(ClientImpl.java:485)
at org.voltdb.client.ClientImpl.callProcedureWithClientTimeout(ClientImpl.java:324)
at org.voltdb.client.ClientImpl.callProcedure(ClientImpl.java:260)
at line4c569b049a9d4e51a3e8fda7cbb043de32.$read$$iw$$iw$$iw$$iw$$iw$$iw.callProcedure(command-3986740264398828:9)
at line4c569b049a9d4e51a3e8fda7cbb043de40.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$1.apply(command-3986740264399793:8)
at line4c569b049a9d4e51a3e8fda7cbb043de40.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$1.apply(command-3986740264399793:7)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
我发现找到有关该问题的链接(https://forum.voltdb.com/forum/voltdb-discussions/building-voltdb-applications/1182-mispartitioned-tuple-in-single-partition-insert-statement),并尝试使用以下查询对过程进行分区
PARTITION PROCEDURE EMPLOYEE.insert ON TABLE EMPLOYEE COLUMN ID;
AND
PARTITION PROCEDURE EMPLOYEE.insert ON TABLE EMPLOYEE COLUMN ID [PARAMETER 0];
但是执行这些语句时出现[Ad Hoc DDL Input]: VoltDB DDL Error: "Partition references an undefined procedure "EMPLOYEE.insert""
错误。
但是,我可以通过使用@AdHoc
存储过程来插入数据,但是对于使用EMPLOYEE.insert
存储过程进行插入的上述情况,我无法解决问题或解决方案数据放入分区表中。
答案 0 :(得分:1)
过程“ EMPLOYEE.insert”是所谓的“默认”过程,该过程在创建表EMPLOYEE时由VoltDB自动生成。已经根据表的分区对其进行了自动分区,因此无法调用“ PARTITION PROCEDURE EMPLOYEE.insert ...”来覆盖它。
我认为正在发生的事情是该过程由ID列分区,该列在EMPLOYEE表中是VARCHAR。因此,输入参数应为字符串。但是,我认为您的代码以某种方式读取了CSV文件并将第一列作为int值传递。
java客户端的callProcedure(String procedureName,Object ... params)方法接受varargs作为参数。这可以是任何Object []。在服务器上的某处进行检查,其中参数的#必须与过程期望的#相匹配,否则过程调用将被拒绝,否则将永远不会执行。但是,我认为在您的情况下,#号参数是可以的,因此它将尝试执行该过程。它对与ID对应的第一个参数值进行哈希处理,然后确定该参数应转到哪个分区。调用被路由到该分区以执行。当它执行时,它尝试插入值,但是还要检查该分区的分区键值是否正确,并且这是失败的。
我认为如果该值作为int传递,则将其散列到错误的分区。然后,在该分区中,它尝试将值插入到VARCHAR列中,因此它可能会将int隐式转换为String,但它不在正确的分区中,因此插入失败,并出现以下错误:“分区插入语句。”如果您编写了一个Java存储过程并将错误的列配置为分区键,则会遇到相同的错误。
披露:我在VoltDB工作。