web-dev-qa-db-ja.com

Spark RDD?に相当するSQL row_numberを取得するにはどうすればよいですか?

多くの列を持つデータテーブルのrow_numbersの完全なリストを生成する必要があります。

SQLでは、これは次のようになります。

select
   key_value,
   col1,
   col2,
   col3,
   row_number() over (partition by key_value order by col1, col2 desc, col3)
from
   temp
;

ここで、Sparkという形式のRDDがあり、V =(col1、col2、col3)の場合、私のエントリは次のようになります。

(key1, (1,2,3))
(key1, (1,4,7))
(key1, (2,2,3))
(key2, (5,5,5))
(key2, (5,5,9))
(key2, (7,5,5))
etc.

SortBy()、sortWith()、sortByKey()、zipWithIndexなどのコマンドを使用してこれらを並べ替え、正しいrow_numberを持つ新しいRDDを作成したい

(key1, (1,2,3), 2)
(key1, (1,4,7), 1)
(key1, (2,2,3), 3)
(key2, (5,5,5), 1)
(key2, (5,5,9), 2)
(key2, (7,5,5), 3)
etc.

(括弧は気にしないので、フォームは(K、(col1、col2、col3、rownum))の代わりになります)

どうすればいいですか?

これが私の最初の試みです。

val sample_data = Seq(((3,4),5,5,5),((3,4),5,5,9),((3,4),7,5,5),((1,2),1,2,3),((1,2),1,4,7),((1,2),2,2,3))

val temp1 = sc.parallelize(sample_data)

temp1.collect().foreach(println)

// ((3,4),5,5,5)
// ((3,4),5,5,9)
// ((3,4),7,5,5)
// ((1,2),1,2,3)
// ((1,2),1,4,7)
// ((1,2),2,2,3)

temp1.map(x => (x, 1)).sortByKey().zipWithIndex.collect().foreach(println)

// ((((1,2),1,2,3),1),0)
// ((((1,2),1,4,7),1),1)
// ((((1,2),2,2,3),1),2)
// ((((3,4),5,5,5),1),3)
// ((((3,4),5,5,9),1),4)
// ((((3,4),7,5,5),1),5)

// note that this isn't ordering with a partition on key value K!

val temp2 = temp1.???

また、関数sortByをRDDに直接適用することはできませんが、最初にcollect()を実行する必要があり、次に出力もRDDではなく、配列であることに注意してください。

temp1.collect().sortBy(a => a._2 -> -a._3 -> a._4).foreach(println)

// ((1,2),1,4,7)
// ((1,2),1,2,3)
// ((1,2),2,2,3)
// ((3,4),5,5,5)
// ((3,4),5,5,9)
// ((3,4),7,5,5)

ここにもう少し進歩がありますが、まだ分割されていません:

val temp2 = sc.parallelize(temp1.map(a => (a._1,(a._2, a._3, a._4))).collect().sortBy(a => a._2._1 -> -a._2._2 -> a._2._3)).zipWithIndex.map(a => (a._1._1, a._1._2._1, a._1._2._2, a._1._2._3, a._2 + 1))

temp2.collect().foreach(println)

// ((1,2),1,4,7,1)
// ((1,2),1,2,3,2)
// ((1,2),2,2,3,3)
// ((3,4),5,5,5,4)
// ((3,4),5,5,9,5)
// ((3,4),7,5,5,6)
25
Glenn Strycker

row_number() over (partition by ... order by ...)機能がSpark 1.4に追加されました。この回答はPySpark/DataFramesを使用しています。

テストDataFrameを作成します。

from pyspark.sql import Row, functions as F

testDF = sc.parallelize(
    (Row(k="key1", v=(1,2,3)),
     Row(k="key1", v=(1,4,7)),
     Row(k="key1", v=(2,2,3)),
     Row(k="key2", v=(5,5,5)),
     Row(k="key2", v=(5,5,9)),
     Row(k="key2", v=(7,5,5))
    )
).toDF()

パーティション化された行番号を追加します。

from pyspark.sql.window import Window

(testDF
 .select("k", "v",
         F.rowNumber()
         .over(Window
               .partitionBy("k")
               .orderBy("k")
              )
         .alias("rowNum")
        )
 .show()
)

+----+-------+------+
|   k|      v|rowNum|
+----+-------+------+
|key1|[1,2,3]|     1|
|key1|[1,4,7]|     2|
|key1|[2,2,3]|     3|
|key2|[5,5,5]|     1|
|key2|[5,5,9]|     2|
|key2|[7,5,5]|     3|
+----+-------+------+
26
dnlbrky

これはあなたが育てている興味深い問題です。 Pythonで答えますが、Scalaにシームレスに翻訳できると確信しています。

これに取り組む方法は次のとおりです。

1-データを簡素化する:

temp2 = temp1.map(lambda x: (x[0],(x[1],x[2],x[3])))

temp2は現在、「実際の」キーと値のペアです。次のようになります。

[
((3, 4), (5, 5, 5)),  
((3, 4), (5, 5, 9)),   
((3, 4), (7, 5, 5)),   
((1, 2), (1, 2, 3)),  
((1, 2), (1, 4, 7)),   
((1, 2), (2, 2, 3))

]

2-次に、group-by関数を使用してPARTITION BYの効果を再現します。

temp3 = temp2.groupByKey()

temp3は2行のRDDになりました。

[((1, 2), <pyspark.resultiterable.ResultIterable object at 0x15e08d0>),  
 ((3, 4), <pyspark.resultiterable.ResultIterable object at 0x15e0290>)]

3-次に、RDDの各値にランク関数を適用する必要があります。 Pythonでは、単純なソート関数を使用します(列挙によりrow_number列が作成されます):

 temp4 = temp3.flatMap(lambda x: Tuple([(x[0],(i[1],i[0])) for i in enumerate(sorted(x[1]))])).take(10)

特定の順序を実装するには、正しい「キー」引数を入力する必要があることに注意してください(Pythonでは、次のようなラムダ関数を作成します。

lambda Tuple : (Tuple[0],-Tuple[1],Tuple[2])

最後に(キー引数関数なしでは、そのように見えます):

[
((1, 2), ((1, 2, 3), 0)), 
((1, 2), ((1, 4, 7), 1)), 
((1, 2), ((2, 2, 3), 2)), 
((3, 4), ((5, 5, 5), 0)), 
((3, 4), ((5, 5, 9), 1)), 
((3, 4), ((7, 5, 5), 2))

]

お役に立てば幸いです!

がんばろう。

4
Guillaume G
val test = Seq(("key1", (1,2,3)),("key1",(4,5,6)), ("key2", (7,8,9)), ("key2", (0,1,2)))

テスト:Seq [(String、(Int、Int、Int))] = List((key1、(1,2,3))、(key1、(4,5,6))、(key2、(7,8 、9))、(key2、(0,1,2)))

test.foreach(println)

(key1、(1,2,3))

(key1、(4,5,6))

(key2、(7,8,9))

(key2、(0,1,2))

val rdd = sc.parallelize(test, 2)

rdd:org.Apache.spark.rdd.RDD [(String、(Int、Int、Int))] = ParallelCollectionRDD [41] at parallelize at:26

val rdd1 = rdd.groupByKey.map(x => (x._1,x._2.toArray)).map(x => (x._1, x._2.sortBy(x => x._1).zipWithIndex))

rdd1:org.Apache.spark.rdd.RDD [(String、Array [((Int、Int、Int)、Int)])] = MapPartitionsRDD [44]マップ:25

val rdd2 = rdd1.flatMap{ 
  elem =>
   val key = elem._1
   elem._2.map(row => (key, row._1, row._2))
 }

rdd2:org.Apache.spark.rdd.RDD [(String、(Int、Int、Int)、Int)] = mapPartitionsRDD [45] at flatMap at:25

rdd2.collect.foreach(println)

(key1、(1,2,3)、0)

(key1、(4,5,6)、1)

(key2、(0,1,2)、0)

(key2、(7,8,9)、1)

1
Wallace Huang

From spark sql
データファイルを読み取ります...
val df = spark.read.json( "s3:// s3bukcet/key/activity/year = 2018/month = 12/date = 15/*");

上記のファイルには、user_id、pageviews、clicksの各フィールドがあります

User_idでパーティション化されたアクティビティID(row_number)を生成し、クリックで並べ替えます
val output = df.withColumn( "activity_id"、functions.row_number()。over(Window.partitionBy( "user_id")。orderBy( "clicks"))。cast(DataTypes.IntegerType));

0
Dakshin