簡體   English   中英

Spark StringIndexer.fit在大型記錄上非常慢

[英]Spark StringIndexer.fit is very slow on large records

我有大型數據記錄格式如下:

// +---+------+------+
// |cid|itemId|bought|
// +---+------+------+
// |abc|   123|  true|
// |abc|   345|  true|
// |abc|   567|  true|
// |def|   123|  true|
// |def|   345|  true|
// |def|   567|  true|
// |def|   789| false|
// +---+------+------+

ciditemId是字符串。

有965,964,223條記錄。

我試圖使用StringIndexercid轉換為整數,如下所示:

dataset.repartition(50)
val cidIndexer = new StringIndexer().setInputCol("cid").setOutputCol("cidIndex")
val cidIndexedMatrix = cidIndexer.fit(dataset).transform(dataset)

但是這些代碼行很慢(大約需要30分鍾)。 問題是它太大了,以至於我之后無法做任何事情。

我正在使用具有2個節點(61 GB內存)的R4 2XLarge集群的亞馬遜EMR集群。

我可以做進一步的性能提升嗎? 任何幫助都感激不盡。

如果列的基數很高,那么這是預期的行為。 作為培訓過程的一部分, StringIndexer收集所有標簽,並創建標簽 - 索引映射(使用Spark的oasutil.collection.OpenHashMap )。

在最壞的情況下,該過程需要O(N)存儲器,並且在計算和存儲器方面都是密集的。

如果列的基數很高,並且其內容將用作特征,則最好應用FeatureHasher (Spark 2.3或更高版本)。

import org.apache.spark.ml.feature.FeatureHasher

val hasher = new FeatureHasher()
  .setInputCols("cid")
  .setOutputCols("cid_hash_vec")
hasher.transform(dataset)

它不保證唯一性並且不可逆,但它對於許多應用來說已經足夠好了,並且不需要裝配過程。

對於不會用作功能的列,您還可以使用hash函數:

import org.apache.spark.sql.functions.hash

dataset.withColumn("cid_hash", hash($"cid"))

假如說:

  • 您打算將cid用作功能(在StringIndexer + OneHotEncoderEstimator之后)
  • 您的數據位於S3中

先問幾個問題:

在不知情的情況下,我的第一個猜測是你現在不應該擔心內存並首先檢查你的並行度。 您只有2個R4 2XLarge實例可以為您提供:

  • 8個CPU
  • 61GB內存

就個人而言,我會嘗試:

  • 獲得更多實例
  • R4 2XLarge實例與具有更多CPU的其他實例交換

不幸的是,對於目前的EMR產品,這只能通過在問題上投入資金來實現:

最后,需要repartition(50) 可能會引入進一步的延誤......

暫無
暫無

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

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