我正在使用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()
接受实例GetFunction
和RsultFunction
类。 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
似乎是因为values
在ArrayList
内属于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
那么这里可能出现什么问题?我应该如何做到这一点?
答案 0 :(得分:0)
最后一种方法(返回String[] values
)是正确的。问题在于形成错误的架构。似乎我在某种程度上最终在模式中有一个列而不是数据中存在的列。 (感谢架构字符串中包含由单个空格分隔的列的额外空格字符。额外的空间正在创建额外的列。)