我正在尝试使用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)
答案 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 version
和spark-avro
软件包,您的方法就应该很好。
在使用Spark Structure Streaming消耗Kafka消息期间,有一种我更喜欢的替代方法是将UDF与fastavro
python库一起使用。 fastavro
相对较快,因为它使用了C扩展名。我已经使用它几个月了,没有任何问题。
如下面的代码片段所示,主要的Kafka消息承载在values
的{{1}}列中。出于演示目的,我使用具有2列kafka_df
和col1
的简单avro模式。 col2
UDF函数的返回是一个元组,分别对应于avro模式中描述的字段数。然后将流写到控制台以进行调试。
deserialize_avro