Pyspark 2.4.3,从Kafka读取Avro格式消息-Pyspark结构化流

时间:2019-11-21 21:18:44

标签: apache-spark pyspark avro spark-avro

我正在尝试使用PySpark 2.4.3从Kafka读取Avro消息。基于下面的基于流的堆栈链接,能够转换为Avro格式(to_avro),并且代码按预期工作。但是from_avro无法正常工作并解决以下问题。是否还有其他模块支持读取从Kafka流式传输的avro消息?这是Cloudra发行环境。 请对此提出建议。

参考: Pyspark 2.4.0, read avro from kafka with read stream - Python

环境详细信息:

火花:

 / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 2.1.1.2.6.1.0-129
      /_/

Using Python version 3.6.1 (default, Jul 24 2019 04:52:09)

Pyspark:

pyspark 2.4.3

Spark_submit:

/usr/hdp/2.6.1.0-129/spark2/bin/pyspark --packages org.apache.spark:spark-avro_2.11:2.4.3 --conf spark.ui.port=4064

to_avro

from pyspark.sql.column import Column, _to_java_column 

def from_avro(col, jsonFormatSchema): 
    sc = SparkContext._active_spark_context 
    avro = sc._jvm.org.apache.spark.sql.avro
    f = getattr(getattr(avro, "package$"), "MODULE$").from_avro
    return Column(f(_to_java_column(col), jsonFormatSchema)) 


def to_avro(col): 
    sc = SparkContext._active_spark_context 
    avro = sc._jvm.org.apache.spark.sql.avro
    f = getattr(getattr(avro, "package$"), "MODULE$").to_avro
    return Column(f(_to_java_column(col))) 
from pyspark.sql.functions import col, struct


avro_type_struct = """
{
  "type": "record",
  "name": "struct",
  "fields": [
    {"name": "col1", "type": "long"},
    {"name": "col2", "type": "string"}
  ]
}"""


df = spark.range(10).select(struct(
    col("id"),
    col("id").cast("string").alias("id2")
).alias("struct"))
avro_struct_df = df.select(to_avro(col("struct")).alias("avro"))
avro_struct_df.show(3)
+----------+
|      avro|
+----------+
|[00 02 30]|
|[02 02 31]|
|[04 02 32]|
+----------+
only showing top 3 rows

from_avro:

avro_struct_df.select(from_avro("avro", avro_type_struct)).show(3)

错误消息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/hdp/2.6.1.0-129/spark2/python/pyspark/sql/dataframe.py", line 993, in select
    jdf = self._jdf.select(self._jcols(*cols))
  File "/usr/hdp/2.6.1.0-129/spark2/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py", line 1133, in __call__
  File "/usr/hdp/2.6.1.0-129/spark2/python/pyspark/sql/utils.py", line 63, in deco
    return f(*a, **kw)
  File "/usr/hdp/2.6.1.0-129/spark2/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py", line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o61.select.
: java.lang.NoSuchMethodError: org.apache.avro.Schema.getLogicalType()Lorg/apache/avro/LogicalType;
        at org.apache.spark.sql.avro.SchemaConverters$.toSqlTypeHelper(SchemaConverters.scala:66)
        at org.apache.spark.sql.avro.SchemaConverters$$anonfun$1.apply(SchemaConverters.scala:82)

2 个答案:

答案 0 :(得分:0)

您的Spark版本实际上是2.1.1,因此您不能使用Spark中包含的spark-avro软件包的2.4.3版本

您需要使用Databricks的一个

  

是否还有其他模块支持读取从Kafka流式传输的Avro消息?

您可以使用普通的kafka Python库,而不是Spark

答案 1 :(得分:0)

Spark 2.4.0支持 to_avro from_avro 函数,但仅适用于Scala and Java。然后,只要使用适当的spark versionspark-avro软件包,您的方法就应该很好。

在使用Spark Structure Streaming消耗Kafka消息期间,有一种我更喜欢的替代方法是将UDF与fastavro python库一起使用。 fastavro相对较快,因为它使用了C扩展名。我已经使用它几个月了,没有任何问题。

如下面的代码片段所示,主要的Kafka消息承载在values的{​​{1}}列中。出于演示目的,我使用具有2列kafka_dfcol1的简单avro模式。 col2 UDF函数的返回是一个元组,分别对应于avro模式中描述的字段数。然后将流写到控制台以进行调试。

deserialize_avro