通过Spark SQL查询Cassandra UDT

时间:2018-12-12 13:58:23

标签: apache-spark cassandra etl parquet presto

我们想通过 SparkSQL 从Cassandra DB查询数据。问题在于数据以 UDT 的形式存储在cassandra中。 UDT的结构是深层嵌套的,并且包含可变长度的数组,因此很难将数据分解为平面结构。 我找不到任何有效的示例,如何通过SparkSQL查询此类UDT,尤其是根据UDT值过滤结果。

或者,您是否可以建议其他ETL管道(查询引擎,存储引擎等),它更适合我们的用例?

我们的ETL管道:

Kafka(重复事件)-> Spark流-> Cassandra(重复数据删除以仅存储最新事件) <-Spark SQL <-分析平台(UI)

到目前为止我们尝试过的解决方案:

1)Kafka-> Spark-> 镶木地板 <-Apache Drill

一切正常,我们可以查询和过滤数组以及嵌套的数据结构。

问题:无法重复数据删除(使用最新事件重写镶木地板文件)

2)Kafka-> Spark-> Cassandra <-Presto

解决了重复数据删除问题1)。

问题:Presto不支持UDT类型(presto docpresto issue

我们的主要要求是:

  • 支持重复数据删除。我们可能会收到许多具有相同ID的事件,我们只需要存储最新的事件即可。
  • 使用数组存储深度嵌套的数据结构
  • 分布式存储,可扩展以供将来扩展
  • 具有类似SQL的查询支持的分布式查询引擎(用于与Zeppelin,Tableau,Qlik等连接)。该查询不必实时运行,可以接受几分钟的延迟。
  • 支持模式演变(AVRO风格)

感谢您的任何建议

1 个答案:

答案 0 :(得分:1)

您可以只使用点语法对嵌套元素执行查询。例如,如果我具有以下CQL定义:

cqlsh> use test;
cqlsh:test> create type t1 (id int, t text);
cqlsh:test> create type t2 (id int, t1 frozen<t1>);
cqlsh:test> create table nudt (id int primary key, t2 frozen<t2>);
cqlsh:test> insert into nudt (id, t2) values (1, {id: 1, t1: {id: 1, t: 't1'}});
cqlsh:test> insert into nudt (id, t2) values (2, {id: 2, t1: {id: 2, t: 't2'}});
cqlsh:test> SELECT * from nudt;

 id | t2
----+-------------------------------
  1 | {id: 1, t1: {id: 1, t: 't1'}}
  2 | {id: 2, t1: {id: 2, t: 't2'}}

(2 rows)

然后我可以按以下方式加载该数据:

scala> val data = spark.read.format("org.apache.spark.sql.cassandra").
     options(Map( "table" -> "nudt", "keyspace" -> "test")).load()
data: org.apache.spark.sql.DataFrame = [id: int, t2: struct<id: int, t1: struct<id: int, t: string>>]

scala> data.cache
res0: data.type = [id: int, t2: struct<id: int, t1: struct<id: int, t: string>>]

scala> data.show
+---+----------+
| id|        t2|
+---+----------+
|  1|[1,[1,t1]]|
|  2|[2,[2,t2]]|
+---+----------+

然后查询数据以仅选择UDT中字段的特定值:

scala> val res = spark.sql("select * from test.nudt where t2.t1.t = 't1'")
res: org.apache.spark.sql.DataFrame = [id: int, t2: struct<id: int, t1: struct<id: int, t: string>>]

scala> res.show
+---+----------+
| id|        t2|
+---+----------+
|  1|[1,[1,t1]]|
+---+----------+

您可以使用spark.sql或相应的.filter函数-取决于您的编程风格。该技术适用于来自不同来源(例如JSON等)的任何结构类型数据。

但是要考虑到,您不会像通过分区键/集群列进行查询时那样从Cassandra连接器获得优化