Получение `Mispartitioned tuple in single-partition insert statement` при попытке вставить данные в многораздельную таблицу с помощью` TABLE_NAME.insert`

Я создаю таблицу 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;

Я написал одно искровое задание для вставки данных в 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;

А ТАКЖЕ

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 для вставки данных в секционированную таблицу.


person Naresh Joshi    schedule 24.01.2019    source источник


Ответы (1)


Процедура «EMPLOYEE.insert» - это то, что называется процедурой «по умолчанию», которая автоматически генерируется VoltDB при создании таблицы EMPLOYEE. Он уже автоматически разбит на разделы на основе разбиения таблицы, поэтому вы не можете вызвать «PARTITION PROCEDURE EMPLOYEE.insert ...», чтобы переопределить это.

Я думаю, что происходит то, что процедура разбивается на столбец ID, который в таблице EMPLOYEE является VARCHAR. Следовательно, входным параметром должна быть строка. Однако я думаю, что ваш код каким-то образом читает файл CSV и передает первый столбец как значение int.

Метод java-клиента callProcedure (String procedureName, Object ... params) принимает в качестве параметров varargs. Это может быть любой Object []. Где-то на сервере выполняется проверка, где # аргументов должно соответствовать #, ожидаемому процедурой, в противном случае вызов процедуры возвращается как отклоненный и никогда не был бы выполнен. Однако я думаю, что в вашем случае количество аргументов в порядке, поэтому он пытается выполнить процедуру. Он хеширует значение 1-го параметра, соответствующее идентификатору, а затем определяет, в какой раздел он должен перейти. Вызов направляется в этот раздел для выполнения. Когда он выполняется, он пытается вставить значения, но есть еще одна проверка правильности значения ключа раздела для этого раздела, и это не удается.

Я думаю, что если значение передается как int, оно хешируется не в тот раздел. Затем в этом разделе он пытается вставить значение в столбец, который является VARCHAR, поэтому он, вероятно, неявно преобразует int в String, но не в правильном разделе, поэтому вставка не выполняется с этой ошибкой «Неправильно разбитый кортеж в одно- оператор вставки раздела ". Это та же ошибка, которую вы получили бы, если бы написали хранимую процедуру Java и настроили неправильный столбец в качестве ключа раздела.

Раскрытие информации: я работаю в VoltDB.

person BenjaminBallard    schedule 24.01.2019
comment
Спасибо, @BenjaminBallard! Я отключил параметр inferSchema в spark.read, поэтому все во фрейме данных превратилось в строку, и это сработало. - person Naresh Joshi; 25.01.2019
comment
Но мне интересно, почему я не получаю никаких ошибок, если попробую @AdHoc хранимую процедуру? - person Naresh Joshi; 25.01.2019
comment
@AdHoc отправляет все в виде строки в синтаксический анализатор и получает хеширование оттуда, поэтому я думаю, что он преобразовал идентификатор в строку по пути и перешел в правильный раздел. - person BenjaminBallard; 25.01.2019
comment
Понял! Спасибо, @Benjamain - person Naresh Joshi; 25.01.2019