嵌套的JSON字段如何在Spark中引发AMBIGUOUS_REFERENCE_TO_FIELDS?

编程语言 2026-07-08

我正在消费两个币安的数据流:一个交易流和一个K 线(蜡烛图)流。这是我在Spark作业中使用的模式/结构:

========================================================================
# TRADE STREAM SCHEMA (MICRO VIEW)
# ========================================================================
trade_schema = StructType([
    StructField("e", StringType(), True),
    StructField("s", StringType(), True),
    StructField("t", LongType(), True),
    StructField("p", StringType(), True),
    StructField("q", StringType(), True),
    StructField("T", LongType(), True),
    StructField("m", BooleanType(), True)
])

parsed_trade_df = (
    trade_raw_df
    .select(
        from_json(
            col("value").cast("string"),
            trade_schema
        ).alias("json")
    )
    .filter(col("json").isNotNull())
    .select(
        col("json.e").alias("event_type"),
        col("json.s").alias("symbol"),
        col("json.t").alias("trade_id"),
        col("json.p").cast(DecimalType(18, 2)).alias("price"),
        col("json.q").cast(DecimalType(18, 6)).alias("quantity"),
        col("json.T").alias("trade_time_ms"),
        col("json.m").alias("is_buyer_maker")
    )
    .filter(col("event_type") == "trade")
    .filter(col("trade_time_ms").isNotNull())
    .filter(col("price").isNotNull())
    .filter(col("quantity").isNotNull())
)
parsed_trade_df.printSchema()
# ========================================================================
# TRADE TRANSFORMATION
# ========================================================================
trade_df = (
    parsed_trade_df
    .withColumn(
        "event_time",
        (col("trade_time_ms") / 1000).cast("timestamp")
    )
    .withColumn(
        "total_value_usd",
        col("price") * col("quantity")
    )
)

当Spark容器启动时,我得到以下错误:

26/06/23 18:28:01 INFO StandaloneSchedulerBackend: SchedulerBackend is ready for scheduling beginning after reached minRegisteredResourcesRatio: 0.0

Traceback (most recent call last):

  File "/opt/spark/app/spark_streaming.py", line 95, in <module>

    trade_raw_df

  File "/opt/spark/python/lib/pyspark.zip/pyspark/sql/dataframe.py", line 3223, in select

  File "/opt/spark/python/lib/py4j-0.10.9.7-src.zip/py4j/java_gateway.py", line 1322, in __call__

  File "/opt/spark/python/lib/pyspark.zip/pyspark/errors/exceptions/captured.py", line 185, in deco

pyspark.errors.exceptions.captured.AnalysisException: [AMBIGUOUS_REFERENCE_TO_FIELDS] Ambiguous reference to the field `t`. It appears 2 times in the schema.

[Tue 23 Jun 2026 06:28:03 PM UTC] Spark exited with code 1

Retrying in 10 seconds...

回溯指向我JSON解析步骤中的一个 .select(...) 操作。

让我困惑的是,交易模式只有一个字段,名为 t,而K 线模式在 k 结构中嵌套了另一个 t。我以为Spark应该能够区分 json.tjson.k.t

在Spark中通常是什么原因会导致这个错误?

示例交易:

{
  "e": "trade",
  "E": 1782371994016,
  "s": "BTCUSDT",
  "t": 6442492017,
  "p": "61849.00000000",
  "q": "0.00016000",
  "T": 1782371994015,
  "m": false
}

kline数据流

{
  "e": "kline",
  "E": 1782371994016,
  "s": "BTCUSDT",
  "k": {
    "t": 1782371940000,
    "T": 1782371999999,
    "i": "1m",
    "o": "61802.00000000",
    "c": "61848.99000000",
    "h": "61849.00000000",
    "l": "61799.00000000",
    "v": "7.06707000",
    "n": 1618,
    "x": false,
    "q": "436860.47143120"
  }
}

解决方案

这是一个简单的大小写敏感问题。默认情况下 spark.sql.caseSensitive 被设置为 false

>>> 
>>> from pyspark.sql.types import StructType, StructField, StringType, LongType, BooleanType
>>> from pyspark.sql.functions import from_json, col
>>> from pyspark.sql import Row
>>> 
>>> json_str = '{"e":"trade","E":1782371994016,"s":"BTCUSDT","t":6442492017,"p":"61849.00","q":"0.00016","T":1782371994015,"m":false}'
>>> df = spark.createDataFrame([Row(value=json_str)])
>>> 
>>> schema = StructType([
...     StructField("e", StringType()),
...     StructField("s", StringType()),
...     StructField("t", LongType()),
...     StructField("p", StringType()),
...     StructField("q", StringType()),
...     StructField("T", LongType()),
...     StructField("m", BooleanType())
... ])
>>> 
>>> spark.conf.set('spark.sql.caseSensitive', 'false')
>>> #       this is the default value          ^^^^^
>>> 
>>> df.select(from_json(col("value"), schema).alias("json")).select("json.t", "json.T").show()
....
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "workspaces/dlh-databricks/fxc/.venv/lib64/python3.12/site-packages/pyspark/sql/classic/dataframe.py", line 991, in select
    jdf = self._jdf.select(self._jcols(*cols))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
....
    raise converted from None
pyspark.errors.exceptions.captured.AnalysisException: [AMBIGUOUS_REFERENCE_TO_FIELDS] Ambiguous reference to the field `t`. It appears 2 times in the schema. SQLSTATE: 42000
>>>

修改配置:

>>> 
>>> spark.conf.set('spark.sql.caseSensitive', 'true')
>>> df.select(from_json(col("value"), schema).alias("json")).select("json.t", "json.T").show()
+----------+-------------+                                                      
|         t|            T|
+----------+-------------+
|6442492017|1782371994015|
+----------+-------------+

>>>

就我而言,你应该只使用不同的列名来替代配置,而不是修改配置。不过,随你便。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章