在Apache Spark中,将JavaRDD <row>转换为Dataset <row>会产生异常:ArrayList不是字符串

时间:2018-05-31 11:42:10

标签: java apache-spark apache-spark-sql hbase

我正在使用hbase-spark connector将hbase数据提取到spark JavaRDD<Row>(我觉得我能够成功完成,因为我能够打印获取的hbase数据)。然后,我正在尝试将JavaRDD<Row>转换为Dataset<Row>。但它给了我错误,这是在帖子中进一步给出的。首先让我开始我的代码的样子。

private static JavaRDD<Row> loadHBaseRDD() throws ParseException
{
    //form list of row keys
    List<byte[]> rowKeys = new ArrayList<byte[]>(5);
    //consider ids is class level variable
    ids.forEach(id -> {
        rowKeys.add(Bytes.toBytes(id));     
    });
    JavaRDD<byte[]> rdd = jsc.parallelize(rowKeys);

    //make hbase-spark connector call 
    JavaRDD resultJRDD = jhbc.bulkGet(TableName.valueOf("table1"),2,rdd,new GetFunction(),new ResultFunction());

    return resultJRDD;
}

请注意bulkGet()接受实例GetFunctionRsultFunction类。 GetFunction类有一个返回Get类实例的单一方法(来自hbase client):

public static class GetFunction implements Function<byte[], Get> {
    private static final long serialVersionUID = 1L;
    public Get call(byte[] v) throws Exception {
        return new Get(v);
    }
}

ResultFunction有一个将Result(hbase客户端类)的实例转换为Row的函数:

public static class ResultFunction implements Function<Result, Row> 
{
    private static final long serialVersionUID = 1L;
    public Row call(Result result) throws Exception 
    {
        List<String> values = new ArrayList<String>(); //notice this is arraylist, we talk about this latter

        for (Cell cell : result.rawCells()) {
            values.add(Bytes.toString(CellUtil.cloneValue(cell)));
        }
        return RowFactory.create(values);
    }
}

当我调用loadHBaseRDD()并打印返回的值时,它会正确打印值:

JavaRDD<Row> hbaseJavaRDD = loadHBaseRDD();
hbaseJavaRDD.foreach(row -> { 
    System.out.println(row);   //this prints rows correctly
}); 

这意味着行已从hbase正确获取到spark。 现在我想按照here的说明将JavaRDD<Row>转换为Dataset<Row>。因此,我首先创建StructType

StructType schema = //create schema

然后我尝试将JavaRDD转换为dataframe:

Dataset<Row> hbaseDataFrame = sparksession1.createDataFrame(hbaseJavaRDD, schema);
hbaseDataFrame.show(false);

这会抛出一个非常大的堆栈跟踪(下面只显示其中一部分)的异常,它出现在第hbaseDataFrame.show(false)行,第一行如下:

java.lang.RuntimeException: Error while encoding: java.lang.RuntimeException: java.util.ArrayList is not a valid external type for schema of string

似乎是因为valuesArrayList内属于ResultFunction.call()类型,因此它会提供异常java.lang.RuntimeException: Error while encoding: java.lang.RuntimeException: java.util.ArrayList is not a valid external type for schema of string

stackoveflow上有[类似的问题],其中answer表示应该返回String[][]而不是列表。虽然我没有得到返回String[][]背后的推理,但我将ResultFunction修改为values类型String[][]

public static class ResultFunction implements Function<Result, Row> 
{
    private static final long serialVersionUID = 1L;
    public Row call(Result result) throws Exception 
    {
        String[] values = new String[result.rawCells().length];
        String[][] valuesWrapped = new String[1][]; 

        for(int i=0;i<result.rawCells().length;i++)
        {
            values[i] = Bytes.toString(CellUtil.cloneValue(result.rawCells()[i]));
        }
        valuesWrapped[0] = values;
        return RowFactory.create(valuesWrapped);
    }
}

它在同一行hbaseDataFrame.show(false)提供以下异常:

java.lang.RuntimeException: Error while encoding: java.lang.RuntimeException: [[Ljava.lang.String; is not a valid external type for schema of string

最后,我再次修改了ResultFunction课程,以获得values类型的String[]变量:

public static class ResultFunction implements Function<Result, Row>
{
    private static final long serialVersionUID = 1L;
    public Row call(Result result) throws Exception 
    {
        String[] values = new String[result.rawCells().length];     
        for(int i=0;i<result.rawCells().length;i++)
        {
            values[i] = Bytes.toString(CellUtil.cloneValue(result.rawCells()[i]));
        }
        return values;
    }
}

这给了我带有起始线的大堆栈跟踪的例外:

java.lang.RuntimeException: Error while encoding: java.lang.ArrayIndexOutOfBoundsException: 14

那么这里可能出现什么问题?我应该如何做到这一点?

1 个答案:

答案 0 :(得分:0)

最后一种方法(返回String[] values)是正确的。问题在于形成错误的架构。似乎我在某种程度上最终在模式中有一个列而不是数据中存在的列。 (感谢架构字符串中包含由单个空格分隔的列的额外空格字符。额外的空间正在创建额外的列。)