我正在使用Java连接到Cassandra。我想做一些事情,比如检查列的数据类型,即;是长还是UTF-8因为,如果它很长,那么我可以得到 column.value.getLong()的值,但如果它是UTF-8或其他,我必须转换ByteBuffer到String。有人可以帮助我如何找到柱的类型?
答案 0 :(得分:5)
要获取列特定信息,首先必须遍历Keyspace定义中的Column Family定义并按名称匹配Column Family - 可以使用thrift API,但我建议使用Hector。
使用“列族”定义,遍历列元数据,并找到所需列的匹配项。然后参考匹配的Column Definition,获取验证类。如果没有元数据或没有匹配列,验证类将成为列族定义中的默认验证类。
使用Hector API,以下内容将列出键空间中的所有列族,并详细说明作为参数传递的CF名称。
public static void main(String[] args) {
String hostPort = "localhost:9160";
String cfname = null;
if (args.length < 1)
{
System.out.println("Expecting <CF> as arguments");
System.exit(1);
}
cfname = args[0];
Cluster cluster = HFactory.getOrCreateCluster( "myCluster", hostPort );
KeyspaceDefinition ksdef = cluster.describeKeyspace("myKeyspace");
for (ColumnFamilyDefinition cfdef: ksdef.getCfDefs()) {
System.out.println(cfdef.getName());
if (cfdef.getName().equals(cfname)) {
System.out.println("Comment: " + cfdef.getComment());
System.out.println("Key: " + cfdef.getKeyValidationClass());
System.out.println("Comparator: " + cfdef.getComparatorType().getTypeName());
System.out.println("Default Validation:" + cfdef.getDefaultValidationClass());
System.out.println("Column MetaData:");
for (ColumnDefinition cdef: cfdef.getColumnMetadata()) {
System.out.println(" Column Name: " + Charset.defaultCharset().decode(cdef.getName()).toString());
System.out.println(" Validation Class: " + cdef.getValidationClass());
System.out.println(" Index Name: " + cdef.getIndexName());
System.out.println(" Index Type: " + cdef.getIndexType().toString());
}
}
}
}
如果你运行它,你会注意到任何验证类都属于org.apache.cassandra.db.marshal包,每个类型都是从AbstractType派生的。
获得类型后,您可以对数据做出决策。例如,如果编写数据转储器工具,您可能只想获取每列的字符串表示形式,并且可以使用AbstractType来获取值的字符串表示形式,使用TypeParser创建类型。
E.g。我以前用非Hector 方法看起来像
private String getAsString(java.nio.ByteBuffer bytes, String marshalType) {
String val = null;
try {
AbstractType abstractType = TypeParser.parse(marshalType);
val = abstractType.getString(bytes);
} catch (ConfigurationException e) {
e.printStackTrace();
}
return val;
}
您可以使用此方法转储键和列名称;这些类型名称也在列族定义中。
一个快捷方式,如果你知道列值是一个字符串,因为字节缓冲区上没有getString方法,你必须使用java.nio.charset.Charset:
Charset.defaultCharset().decode(col.getValue()).toString()
答案 1 :(得分:2)
https://issues.apache.org/jira/browse/CASSANDRA-2302是用于实现ResultSet.getMetaData的Cassandra功能请求。评论提供了有关如何访问它的信息:
ResultSet rs = stmt.executeQuery("select ...");
ResultSetMetaData md = rs.getMetaData();
CassandraResultSetMetaData cmd = md.unwrap(CassandraResultSetMetaData.class);
但是,恐怕直到Cassandra 0.8才实现。您的问题已标记为cassandra-0.7
。
答案 2 :(得分:0)
通常我知道在我的应用程序中期望哪些数据类型,特别是如果我使用static column families;但是如果我使用的是动态列族,或者我只想保持代码的通用性,我倾向于将列设置为BytesType
并将它们序列化/反序列化为Object
类型。
e.g。考虑以下列族:
create column family album
with key_validation_class = 'UTF8Type'
and comparator = 'UTF8Type'
and default_validation_class = 'BytesType';
使用Hector的ObjectSerializer
,您可以将列值读取和写为Object
类型。这些值实际上是列族中的序列化对象,并且在Java代码中反序列化时,值将成为可用的Java对象。以下是我的客户端代码:
/* some code left out for brevity */
String columnFamily = "album";
ThriftColumnFamilyTemplate<String, String> template;
public void write(String key, Map<String, ?> album)
Mutator<String> mutator = template.createMutator();
for (Entry<String, ?> entry : album.entrySet()) {
mutator.addInsertion(key, columnFamily, HFactory.createColumn(entry.getKey(),
entry.getValue(), StringSerializer.get(), ObjectSerializer.get()));
}
mutator.execute();
}
public Map<String, ?> read(String key) {
ColumnFamilyResult<String, String> result = template.queryColumns(key);
Map<String, Object> album = new HashMap<String, Object>();
for (String name : result.getColumnNames()) {
HColumn<String, ByteBuffer> column = result.getColumn(name);
album.put(name, ObjectSerializer.get().fromByteBuffer(column.getValue()));
}
}
这是一个简单的测试,向您展示在列系列反序列化后列值保留其Object
类型:
public static void main(String[] args) {
Map<String, Object> album = new HashMap<String, Object>();
album.put("name", "Up The Bracket");
album.put("release", 2002);
album.put("in_stock", true);
/* write into column family and read it back out */
client.write("up_the_bracket", album);
Map<String, ?> result = client.read("up_the_bracket");
/* the column values are deserialized back into their original types */
assert result.get("name") instanceof String;
assert result.get("release") instanceof Integer;
assert result.get("in_stock") instanceof Boolean;
}