2

我正在使用 Java 连接到 Cassandra。我想做一些事情,比如检查列的数据类型,即;无论是长的还是 UTF-8 因为,如果它是长的,那么我可以将值作为column.value.getLong()但如果它是 UTF-8 或其他,我必须将 ByteBuffer 转换为字符串。有人可以帮助我如何找到 Column 的类型吗?

4

3 回答 3

5

要获取特定于列的信息,您首先必须遍历键空间定义中的列族定义并按名称匹配列族——可以使用 thrift API,但我建议使用 Hector。

使用列族定义,遍历列元数据,并找到所需列的匹配项。然后参考匹配的列定义,得到验证类。如果没有元数据或没有匹配的列,则验证类将是列族定义中的默认验证类。

使用 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 创建类型。

例如,我用来执行此操作的非 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;
}

您可以使用此方法转储键和列名;这些类型名称也在列族定义中。

一个快速的捷径,如果你知道列值是一个字符串,因为在字节缓冲区上没有获取字符串的方法,你必须使用 java.nio.charset.Charset:

Charset.defaultCharset().decode(col.getValue()).toString()
于 2012-01-18T22:02:04.110 回答
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

于 2012-01-17T23:08:26.617 回答
0

通常我知道在我的应用程序中期望什么数据类型,特别是如果我使用静态列族;但是如果我使用动态列族,或者我只想保持我的代码通用,我倾向于将我的列设置为BytesType并将它们序列化/反序列化为Object类型。

例如,考虑以下列族:

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;
}
于 2013-10-11T13:58:22.387 回答