2014-07-16 28 views
3

Scala的新手和嘗試讀取輸入原始數據以在多個字段上使用groupBy生成地圖。Scala - 如何從原始數據創建地圖以計算不同的值

樣品原料數據:

date,uid,site,success 
2014-07-14,userA,google,1 
2014-07-14,userB,google,1 
2014-07-14,userC,yahoo,1 
2014-07-14,userD,facebook,1 

我要舉報每個站點的不同用戶對於每一日期,即數,

2014-07-14,google,2 
2014-07-14,yahoo,1 
2014-07-14,facebook,1 

爲此,我試圖使用GROUPBY上日期和網站字段值爲uid。一旦我有了這個數據結構,我可以迭代地圖並計算不同的地圖值。 任何人都可以指出我如何生成數據結構?

謝謝!

+0

1.你有多大的INP數據? 2.你以後需要在不同的日期統計不同的用戶嗎? –

+0

每天大約有一百萬行,是的將需要統計不同日期的不同用戶。謝謝! – user2727704

回答

2

我希望我理解正確你。這是一個完整的例子。

case class Data(date: String, uid: String, site: String, success: Int) 

val sampleData = List(
    Data("2014-07-14","userA","google",1), 
    Data("2014-07-14","userA","google",1), 
    Data("2014-07-14","userB","google",1), 
    Data("2014-07-14","userC","yahoo",1), 
    Data("2014-07-14","userD","facebook",1) 
) 

sampleData.groupBy(_.date).map 
    {case (date, datelist) => (date, datelist.groupBy(_.site).map 
    {case (site, sitelist) => (site, sitelist.groupBy(_.uid).size)})} 

輸出是:Map(2014-07-14 -> Map(google -> 2, yahoo -> 1, facebook -> 1))

基本上你得到每個日期,包含的訪問,從不同用戶的站點地圖。請注意,從2計數userA訪問爲1

sitelist.groupBy(_.uid).size 

計數不同訪問由uid

編輯是的,沒有額外的數據結構是可能的。你現在只需要處理數組的索引。

val fileText = """2014-07-14,userA,google,1 
    2014-07-14,userA,google,1 
    2014-07-14,userA,google,1 
    2014-07-14,userB,google,1 
    2014-07-14,userC,yahoo,1 
    2014-07-14,userD,facebook,1""".stripMargin 

fileText.lines.map(_.split(",")).toList.groupBy(_(0)).map 
    {case (date, datelist) => (date, datelist.groupBy(_(2)).map 
    {case (site, sitelist) => (site, sitelist.groupBy(_(1)).size)})} 
+0

謝謝Kigyo,絕對回答我的問題。由於我將解析原始數據外部文件,不構建數據對象會增加額外的開銷?還有其他的選擇嗎? – user2727704

+0

@ user2727704看我的編輯。 – Kigyo

+0

謝謝@kigyo .. – user2727704

1

棄爲清晰起見,標題行,一個可能的實現方式如下:

val text = """2014-07-14,userA,google,1 
      |2014-07-14,userA,google,1 
      |2014-07-14,userB,google,1 
      |2014-07-14,userC,yahoo,1 
      |2014-07-16,userC,yahoo,1 
      |2014-07-14,userD,facebook,1 
      |2014-07-14,userE,facebook,1 
      |""".stripMargin 

val uniqueUsersByDateSite: Map[(String, String), Int] = text.lines.map { 
    line => 
    val tokens = line.split(",") 
    (tokens(0), tokens(1), tokens(2)) 
}.toSet.groupBy { 
    tuple: (String, String, String) => 
    (tuple._1, tuple._3) 
}.mapValues { 
    _.size 
} 

通過創建一個元組(date, uid, site)的,我們收集針對特定日期站點爲每個用戶獨特的項目。

groupBy方法然後通過(date, site)收集,將相同日期和地點的N個項目轉換爲地圖項目,其中包含與相應日期和地點的唯一用戶數量相對應的多個項目。

最後mapValue方法達到預期的效果:

Map((2014-07-16,yahoo) -> 1, (2014-07-14,facebook) -> 2, (2014-07-14,google) -> 2, (2014-07-14,yahoo) -> 1) 
+0

非常感謝Luigi ..從你的回答中學到了一些關於Scala的新東西。 – user2727704

0

答案貼@Kigyo好像還不錯,但我能想到的,你可以擴展它一點: 因此,假設這個數據結構:由

case class Data(date: String, uid: String, site: String, success: Int) 
val sampleData = List(
    Data("2014-07-14","userA","google",1), 
    Data("2014-07-14","userA","google",1), 
    Data("2014-07-14","userB","google",1), 
    Data("2014-07-14","userC","yahoo",1), 
    Data("2014-07-14","userD","facebook",1) 
) 

,你可以達到你想要的東西:

list.groupBy((_.date , _.site)).collect{ case (a , b : List[Data]) =>(a._1 , a._2 , b.map(_.success).sum) } ; 

返回Tuple3的列表,就像你想

+0

是的,這取決於什麼樣的數據結構@ user2727704想要的結果。我還認爲'成功'的數量是無關緊要的,因爲不同用戶的數量與它無關。 – Kigyo

+0

而不是b.map(_。success).sum是否有任何其他方法來將統計獨立應用於uid本身,因爲我可能並不總是有成功的領域。謝謝! – user2727704

+0

如果您希望使用'成功'字段,如日期和網站(充當過濾器),最好的方法是將其包含在第一個元組中(分組方式)。 –

相關問題