我在从Cosmos DB中读取数据块中的项目时遇到了一些问题,似乎将JSON作为字符串值读取,并且将数据从其中读取到列中时遇到了一些问题。
我有一列名为ProductRanges的行,其中具有以下值:
[0, 6, 9] 6
[2, 6, 9] 2
6 diminished
2 major
在Cosmos DB中,JSON文档有效,当导入数据时,数据框中的数据类型是字符串,而不是我期望的JSON对象/结构。
我希望能够计算“名称”出现的次数,并通过它们迭代获得最小值,最大值和值项,因为我们可以拥有的范围数可以大于3。我虽然在stackoverflow和其他地方发表过一些文章,但仍然停留在格式上。我尝试使用爆炸并读取基于列值的模式,但是它确实说了“在有效文档中”,认为可能是由于Pyspark在开始和结束时都需要{},但甚至在来自cosmos db的SQL查询仍然以字符串的数据类型结束。
任何指针将不胜感激
答案 0 :(得分:1)
我看到您从Azure CosmosDB检索了JSON文档并将其转换为PySpark DataFrame,但是嵌套的JSON文档或数组无法按预期方式转换为DataFrame列中的JSON对象,因为没有定义JSON类型在pyspark.sql.types
模块中,如下所示。
我在尝试解决文档PySpark: Convert JSON String Column to Array of Object (StructType) in Data Frame
时找到了适合您当前情况的文档,甚至与您想要的一样。
上面的文档显示了如何使用ArrayType
,StructType
,StructField
和其他基本PySpark数据类型将列中的JSON字符串转换为组合数据类型,可以在通过定义列模式和UDF来实现PySpark。
这是示例代码的摘要。希望对您有所帮助。
source = [{"attr_1": 1, "attr_2": "[{\"a\":1,\"b\":1},{\"a\":2,\"b\":2}]"}, {"attr_1": 2, "attr_2": "[{\"a\":3,\"b\":3},{\"a\":4,\"b\":4}]"}]
JSON通过sqlContext读入数据帧。输出为:
+------+--------------------+
|attr_1| attr_2|
+------+--------------------+
| 1|[{"a":1,"b":1},{"...|
| 2|[{"a":3,"b":3},{"...|
+------+--------------------+
root
|-- attr_1: long (nullable = true)
|-- attr_2: string (nullable = true)
然后,通过定义列模式和UDF来转换attr_2
列。
# Function to convert JSON array string to a list
import json
def parse_json(array_str):
json_obj = json.loads(array_str)
for item in json_obj:
yield (item["a"], item["b"])
# Define the schema
from pyspark.sql.types import ArrayType, IntegerType, StructType, StructField
json_schema = ArrayType(StructType([StructField('a', IntegerType(
), nullable=False), StructField('b', IntegerType(), nullable=False)]))
# Define udf
from pyspark.sql.functions import udf
udf_parse_json = udf(lambda str: parse_json(str), json_schema)
# Generate a new data frame with the expected schema
df_new = df.select(df.attr_1, udf_parse_json(df.attr_2).alias("attr_2"))
df_new.show()
df_new.printSchema()
输出如下:
+------+--------------+
|attr_1| attr_2|
+------+--------------+
| 1|[[1,1], [2,2]]|
| 2|[[3,3], [4,4]]|
+------+--------------+
root
|-- attr_1: long (nullable = true)
|-- attr_2: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- a: integer (nullable = false)
| | |-- b: integer (nullable = false)
答案 1 :(得分:0)
从给定的json数据中,您可以使用printSchema查看数据框的架构并使用它 考虑以下示例:
{"Id":11,"data":[{"package":"com.browser1","activetime":60000},{"package":"com.browser6","activetime":1205000},{"package":"com.browser7","activetime":1205000}]}
{"Id":12,"data":[{"package":"com.browser1","activetime":60000},{"package":"com.browser6","activetime":1205000}]}
......
appActiveTime.printSchema()
root
|-- data: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- activetime: long (nullable = true)
| | |-- package: string (nullable = true)
由于具有数组,因此需要展开数据并选择如下的struct字段
import org.apache.spark.sql.functions._
appActiveTime.withColumn("data", explode($"data"))
.select("data.*")
.show(false)
输出如下:
+----------+------------+
|activetime| package|
+----------+------------+
| 60000|com.browser1|
| 1205000|com.browser6|
| 1205000|com.browser7|
| 60000|com.browser1|
| 1205000|com.browser6|
+----------+------------+
希望这会有所帮助。