如何使用Hadoop将CQL Collection对象保存到Cassandra?

时间:2014-05-24 00:09:38

标签: java hadoop cassandra cql apache-spark

我使用Spark Hadoop API从Cassandra获取数据并将结果保存到Cassandra。 对于行值,如果列类型很长,这是使用CadoOutputFormat适配器为Hadoop发送数据到Cassandra的方法:

val outVal = new java.util.ArrayList[ByteBuffer](1)
outVal.add(ByteBufferUtil.bytes(count.longValue()))

但是当列类型为set<text>时,我无法使其正常工作。我试图用ObjectOutputStream序列化java.util.Set对象但thrift客户端抛出InvalidRequestException(why:string didn't validate.)

val outVal = new java.util.ArrayList[ByteBuffer](1)
val byteOut = new ByteArrayOutputStream()
val out = new ObjectOutputStream(byteOut)
out.writeObject(data)
byteOut.close()
outVal.add(ByteBuffer.wrap(byteOut.toByteArray))
(outKey, outVal)

似乎期望outVal是一个字符串值。我查看了Cassandra中SetSerializer和CollectionSerializer类的源代码,看起来Cassandra对Collection对象使用自定义序列化。 Hadoop CQL3 API是否提供了一种序列化Collection对象的方法,还是我必须找到一种从外部使用Cassandra内部类的方法?

1 个答案:

答案 0 :(得分:0)

现在似乎唯一的解决方案是从Cassandra源代码复制序列化代码。以下是Cassandra内部处理集合对象的方法:

    List<ByteBuffer> bbs = new ArrayList(list.size());
    int size = 0;
    for (String elt : list)
    {
        ByteBuffer bb = ByteBufferUtil.bytes(elt);
        bbs.add(bb);
        size += 2 + bb.remaining();
    }

    ByteBuffer result = ByteBuffer.allocate(2 + size);
    result.putShort((short)list.size());
    for (ByteBuffer bb : bbs)
    {
        result.putShort((short)bb.remaining());
        result.put(bb.duplicate());
    }
    return (ByteBuffer)result.flip();