【问题标题】:how to write a spark scala schema for complex datatypes like map,struct,array如何为 map、struct、array 等复杂数据类型编写 spark scala 模式
【发布时间】:2020-09-19 18:31:20
【问题描述】:

请查找数据格式

c3f36c25-2546-48b2-bd72-1b5e5dcae2ab/1620247529/{6032:{"advertisers":{"Amoma":[{"eurocents":17256,"breakfast":false}]

尝试以下方法

valsschema=List(
                ("Userid", StringType, true),
                ("unix_time", IntegerType, true),
("hotelresults",MapType(IntegerType,true,StructType(("advertisers",MapType(StringType,true,ArrayType(StructType("eurocents",IntegerType,true,"breakfast",BooleanType,true))))))
              ) 

【问题讨论】:

  • 能否请您发布您的问题,并提供更清晰的信息以及您面临的异常/错误
  • 我需要通过 sparkscala 为上述数据创建一个配置单元表。需要创建一个架构。我收到错误,因为方法应用的参数不足:(名称:字符串,数据类型:org.apache.spark.sql.types.DataType,可为空:布尔,元数据:org.apache.spark.sql.types.Metadata)对象 StructField 中的 org.apache.spark.sql.types.StructField。未指定值参数dataType
  • 还有其他方法可以为我的数据创建架构
  • 你问题中的 JSON 无效。请先更正
  • c3f36c25-2546-48b2-bd72-1b5e5dcae2ab\u00011620247529\u00016032\u0003Amoma\u000617256\bfalse => 这是原始数据,这不是 JSON 。我已经转换了它

标签: scala apache-spark hive apache-spark-sql complex-data-types


【解决方案1】:

使用add 方法创建一个StructType 可能更容易。

您的整个文件似乎是带有“/”(斜杠)分隔符的 CSV 格式:

// create initial DataFrame with JSON data inside of 3rd column
val df:DataFrame = spark.read.format("csv").option("delimiter", "/").option("header", "false").option("inferSchema", "false").load("62132524.txt").toDF("UserId", "UnixTime", "HotelResults")

您的第 3 列 JSON 无效,因此在此处更改:

c3f36c25-2546-48b2-bd72-1b5e5dcae2ab/1620247529/{"advertisers":{"Amoma":[{"eurocents":17256,"breakfast":false}]}}

使用from_json 方法创建一个模式来解析JSON(使用通配符导入来确保所有内容都已导入):

import org.apache.spark.sql.types._
import org.apache.spark.sql.functions._

// prepare StructType with inner StructType
val detailType:StructType = new StructType().add("eurocents", IntegerType).add("breakfast", BooleanType)
val jsonSchema:StructType = new StructType().add("advertisers", MapType(StringType, ArrayType(detailType, false)))

// Now, the JSON Schema can be used:
df.select(from_json(col("HotelResults"), jsonSchema) as "HotelResults2").select(col("HotelResults2.*")).show

基于cmets编辑(直接解析平面文件)

内置的 CSV 解析器只能解析带有一个分隔符的文件。一种解决方法是使用split Scala String 方法。

// Read data into a flat RDD
val rawDF = spark.sparkContext.textFile("rawdata.dat")

// Create case class (I added 3 fields, but you will need to add the rest)
case class Record(id: Int, advertiser: String, euroCents: Int)

// Create function converting an array of values to the case class
def arrToRecord(a:Array[String]): Record = Record(a(0).toInt, a(1), a(2).toInt)

// Use one of the approaches below - they should be equivalent in your case
val mappedDF:DataFrame = rawDF.map((s:String) => arrToRecord(s.split("[\u0006\u0003\u0005\u0007\u0008\u0002]"))).toDF()
// OR
val mappedDF:DataFrame = rawDF.map((s:String) => arrToRecord(s.split(Array('\u0006','\u0003','\u0005','\u0007','\u0008','\u0002')))).toDF()

结果


mappedArr.show
+----+----------+---------+
|  id|advertiser|euroCents|
+----+----------+---------+
|6032|     Amoma|    17256|
+----+----------+---------+

【讨论】:

  • 我的数据格式是.dat文件。请找到原始数据,请告诉我如何将其读取为csv文件。我用 spark.read.format("csv").option("delimiter", "/u001").option("header", "false").option("inferSchema", "false").load(filepath /.dat) 并且我将前两个 cols 作为 col0/col1/col2.. 但是 col2 具有 unicode 字符并且不能使用分隔符进行过滤,因为有集合项。希望现在很清楚。 @ELinda .. 我们几乎接近解决方案。
  • {"_c0":"c3f36c25-2546-48b2-bd72-1b5e5dcae2ab","_c1":"1620247529","_c2":"6032\u0003Amoma\u000617256\bfalse\u0005Tui.com\ u000617149 \ bfalse \ u000739448 \ bfalse \ u00028001 \ u0003expedia \ u000634650 \ bfalse \ u0005Mercure \ u000621490 \ bfalse \ u0005Destinia \ u000613719 \ bfalse \ u000723011 \ bfalse \ u00079788 \ bfalse \ u0005Tui.com \ u000625723 \ bfalse \ u0005booking.com \ u000629272 \ bfalse\u000728400\bfalse\u00026033\u0003Amoma\u00065361\bfalse}
  • 参见上面的“编辑”部分
  • 我已经成功创建了一个数据框,现在我需要架构。我已经创建了一个,但是我收到了错误,我提到了数据以及在 val sschema = new StructType() .add("userid",StringType) .add("unix_time",StringType) .add( "广告商", MapType(StringType,ArrayType(new StructType().add("eurocents", IntegerType).add("breakfast", BooleanType)))) val rawDF = spark.sparkContext.textFile("C:/Users/ Rajaraman/Desktop/task/data/hive.dat")
  • 我将代码改写为 val df1 = rawDF.map((s:String) => (s.split("['\u0001','\u0002','\u0003',' \u0004',\u0005','\u0006','\u0007','\u0008',\u0009,\u0010]"))).toDF() 并得到以下输出 |[c3f36c25-2546-48b2- bd72-1b5e5dcae2ab, 1620247529, 6032, Amoma, 17256, false c0a0b114-d1f9-491b-b6c3-ec90d05881ac, 1620208508, 9089, Tui.com, 23418, false @Elinda-请查看
猜你喜欢
  • 2022-12-17
  • 1970-01-01
  • 1970-01-01
  • 2023-02-02
  • 2018-09-14
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
相关资源
最近更新 更多