簡體   English   中英

從 Hive Metastore(鑲木地板格式)在 Spark 中本地處理 10 億條記錄需要永遠 6 小時。 如何加快速度?

[英]Processing 1 billion records locally in Spark from Hive metastore(parquet format) takes forever 6 hours. How to speed it up?

我在 IntelliJ 中運行所有東西。 該應用程序在 Scala 中。

scalaVersion := "2.12.10" sparkVersion = "2.4.4"

所以我正在處理紐約市出租車數據。 近 11 億條記錄,120GB 數據。 我閱讀它,刪除不必要的數據,清理它,並以默認壓縮的鑲木地板格式寫入分區(日、月、年)中的 hive 元存儲。 到目前為止一切順利,它在幾分鍾 (2-3) 內就可以很快地工作。 現在我再次從 Metastore 讀取數據並執行一些操作,基本上,我想計算從 manhattanToJFK 的所有乘車次數,最終計算一些 UDF 和計數。 這需要永遠。

然后我有一個小於 1MB 的天氣數據的小數據集。 將近 50 列,我用它制作了一個只有 7 列的新 DF。 必須找到游樂設施和天氣等之間的一些相關性。所以加入日期然后 spark.ml 相關函數以獲得相關矩陣。 這也需要很長時間。

總共需要 6 個小時才能運行(我在 4-5 個小時,我搞砸了一些東西,不得不重新啟動)。 我等不及要檢查它是否准確。

從我閱讀和理解的內容來看,鑲木地板應該比閱讀和使用 CSV 快得多,但我發現它正好相反。 所以我覺得我做錯了什么。 也許一些配置或設置等? 我是一個有火花的初學者,自己學習。 因此,如果我犯了一個菜鳥錯誤,請耐心等待。 任何幫助都會有很大幫助。

如果我應該發布任何更新或信息,請告訴我。 我可以編輯它並發布它。

謝謝

def analysis() = {
    var parquetDF = SparkObject.spark.read.parquet("spark-warehouse/location")
//      .cache()
    val manhattanTojfkDF = countManhattanToJKF(parquetDF)
    findCorrelation(manhattanTojfkDF)
  }

  def countManhattanToJKF(df:DataFrame):DataFrame = {
    var parquetDF = df
    //  val geojson = scala.io.Source.fromURL(this.getClass.getResource("/nyc-borough-boundaries-polygon.geojson")).mkString
    val geojson = scala.io.Source.fromURL(this.getClass.getResource("/NYC Taxi Zones.geojson")).mkString
    val features = geojson.parseJson.convertTo[FeatureCollection]
    val broadcastFeatures = SparkObject.spark.sparkContext.broadcast(features)
    val lonlatToZoneID = (longitude: Double, latitude: Double) => {
      val feature: Option[Feature] = broadcastFeatures.value.find(f => {
        f.geometry.contains(new Point(longitude, latitude))
      })
      feature.map(f => {
        f("location_id").convertTo[String]
      }).getOrElse("NA")
    }
    val latlonToZoneIDUDF = udf(lonlatToZoneID)

    parquetDF = parquetDF.withColumn("pickupZoneID", when(parquetDF("pickupZoneID") === "NA",
      latlonToZoneIDUDF(parquetDF("pickup_longitude"), parquetDF("pickup_latitude")))
      .otherwise(parquetDF("pickup_longitude")))

    parquetDF = parquetDF.withColumn("dropoffZoneID", when(parquetDF("dropoffZoneID") === "NA",
      latlonToZoneIDUDF(parquetDF("dropoff_longitude"), parquetDF("dropoff_latitude")))
      .otherwise(parquetDF("dropoff_longitude")))


    val boroughLookupID = (pickupID:String) => {
      val feature: Option[Feature] = broadcastFeatures.value.find(f => {
        f.properties("location_id").convertTo[String] == pickupID
      })
      feature.map(f => {
        f("borough").convertTo[String]
      }).getOrElse("NA")
    }

    val boroughUDF = udf(boroughLookupID)
    parquetDF = parquetDF.withColumn("pickupBorough", boroughUDF(parquetDF("pickupZoneID")))
    parquetDF = parquetDF.withColumn("dropoffBorough", boroughUDF(parquetDF("dropoffZoneID")))

    val manhattanToJFK = (borough:String, dropOffID:String) => {
      (borough == "Manhattan" && dropOffID == "132")
    }

    val manhattanToJFKUDF = udf(manhattanToJFK)
    parquetDF = parquetDF.withColumn("manhattanToJFK",
      manhattanToJFKUDF(parquetDF("pickupBorough"), parquetDF("dropoffZoneID")))

    val filteredDF =  parquetDF.filter(parquetDF("ManhattanToJFK") === true)
    val totalRidesFromManhattanTOJFK = filteredDF.count()
    println(totalRidesFromManhattanTOJFK)
    print(parquetDF.show())
    filteredDF
  }

  def findCorrelation(filteredDF:DataFrame) = {
    var weatherDF = SparkObject.spark.read.format("csv")
      .option("header", true)
      .load(URLs.weatherData:_*)

    weatherDF = weatherDF.select(weatherDF("DATE").cast("date"), weatherDF("AWND").cast("float"),
      weatherDF("SNOW").cast("float"), weatherDF("SNWD").cast("float"), weatherDF("TMIN").cast("float"),
      weatherDF("TMAX").cast("float"), weatherDF("PRCP").cast("float"))

     val joinedDF = weatherDF.join(filteredDF, weatherDF("DATE") === filteredDF("pickupDate"))
      .select(weatherDF("DATE"), weatherDF("AWND"), weatherDF("SNOW"), weatherDF("SNWD"), weatherDF("TMIN"),
        weatherDF("TMAX"), weatherDF("PRCP"))
    //    .cache()

    val ridesPerDay = joinedDF.groupBy("DATE").agg(count("DATE").alias("rides_per_day"))
    val cleanedDF =  ridesPerDay.join(joinedDF, "DATE").dropDuplicates().drop("DATE")
    cleanedDF.printSchema()

    val assembler = new VectorAssembler()
      .setInputCols(cleanedDF.columns)
      .setOutputCol("features")

    val corrFeatures = assembler.transform(cleanedDF)

    val Row(coeff1: Matrix) = Correlation.corr(corrFeatures, "features").head
    println(s"Pearson correlation matrix:\n $coeff1")

    val Row(coeff2: Matrix) = Correlation.corr(corrFeatures, "features", "spearman").head
    println(s"Spearman correlation matrix:\n $coeff2")
  }

SparkSession 看起來像

lazy val spark = {
    SparkSession
      .builder()
      .master("local[*]")
      .appName("NYCTaxiDataKlarna")
      .getOrCreate()
  }

我將-Xms4g -Xmx4g作為 VM 選項傳遞,因此每個內存為 4.1 4.1 GB。

編輯:所以我現在只是運行 manhatantojfk 函數,最后做了一些改動,基本上是將數據持久化到 hive 中。 下次我可以從那里開始。 它已經運行了將近 5 個小時,但還沒有完成。

val dw = new DataWriter()
      dw.writeToHive(parquetDF, "parquet", "location_with_borough", "pickupDate")
      print(parquetDF.count())

      val filteredDF =  parquetDF.filter(parquetDF("ManhattanToJFK") === true)
      dw.writeToHive(parquetDF, "parquet", "manhattan_to_jfk", "pickupDate")
//      val totalRidesFromManhattanTOJFK = filteredDF.count()
//      println(totalRidesFromManhattanTOJFK)
//      print(parquetDF.show())
//      filteredDF

您可能不受 IO 限制,因此您閱讀的格式無關緊要。 您真正需要做的是找到查詢計划(也就是 spark 正在做的實際工作)並破譯它。 沒有查詢計划,您無法判斷問題是初始讀取還是連接或組或關聯本身。 最好首先查看 spark-history-server 的 sql 選項卡。 此外,通常最好在執行 ML(又名cleanedDF)之前將預處理過的數據轉儲到存儲中,這樣您就不會不斷地重新運行預處理。

“我在 IntelliJ 中運行所有東西。”

spark是如何配置的? 您是否使用 master = local[*] 運行?

編輯:所以我建議啟動 spark-shell 並進行一些 REPL 風格的代碼探索。 如果您在本地計算機上安裝了 spark,則從命令行使用“spark-shell”啟動它。當它啟動時,您將看到它打印出 spark-history-server url。 從這里運行您的代碼,然后打開 spark-history 服務器以找出 spark 花費的時間。

IMO 你的代碼看起來比它需要的更復雜。 您可能會無意中用腳射擊自己,直到您潛得更深,您才會知道這一點。

➜  ~ spark-shell 
20/02/23 04:06:53 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Spark context Web UI available at http://192.168.43.210:4040
Spark context available as 'sc' (master = local[*], app id = local-1582459622890).
Spark session available as 'spark'.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 2.4.2
      /_/

Using Scala version 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_231)
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

//enter code

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM