セットの分析をしようとしています。次のようなサンプルデータセットがあります。
orders.json
{"items":[1,2,3,4,5]}
{"items":[1,2,5]}
{"items":[1,3,5]}
{"items":[3,4,5]}
それは、IDを表す番号のリストである単一のフィールドだけです。
これが私が実行しようとしているSparkスクリプトです:
val sparkConf = new SparkConf()
.setMaster("local[*]")
.setAppName("Dataframe Test")
val sc = new SparkContext(sparkConf)
val sql = new SQLContext(sc)
val dataframe = sql.read.json("orders.json")
val expanded = dataframe
.explode[::[Long], Long]("items", "item1")(row => row)
.explode[::[Long], Long]("items", "item2")(row => row)
val grouped = expanded
.where(expanded("item1") !== expanded("item2"))
.groupBy("item1", "item2")
.count()
val recs = grouped
.groupBy("item1")
expanded
とgrouped
の作成は問題ありません。簡単に言うと、expanded
は、2つのIDが同じ元のセットにあった2つのIDのすべての可能なセットのリストです。 grouped
は、それ自体と一致したIDを除外し、IDの一意のペアをすべてグループ化して、それぞれのカウントを生成します。 grouped
のスキーマとデータサンプルは次のとおりです。
root
|-- item1: long (nullable = true)
|-- item2: long (nullable = true)
|-- count: long (nullable = false)
[1,2,2]
[1,3,2]
[1,4,1]
[1,5,3]
[2,1,2]
[2,3,1]
[2,4,1]
[2,5,2]
...
だから、私の質問は、タプルのリストを作成するために、各結果の最初の項目をグループ化するにはどうすればよいですか?上記のサンプルデータの場合、次のようなものが予想されます。
[1, [(2, 2), (3, 2), (4, 1), (5, 3)]]
[2, [(1, 2), (3, 1), (4, 1), (5, 2)]]
recs
を使用したスクリプトでわかるように、各行の最初の項目である「item1」に対してgroupByを実行することから始めると思いました。しかし、その後は、アクションが非常に制限されたこのGroupedDataオブジェクトが残ります。実際には、sum、avgなどの集計を行うだけで済みます。各結果からタプルをリストしたいだけです。
この時点でRDD関数を簡単に使用できますが、それはデータフレームの使用とは異なります。データフレーム関数でこれを行う方法はありますか?.
1.6以降で利用可能なorg.Apache.spark.sql.functions
(collect_list
およびstruct
)を使用してビルドできます。
val recs =grouped.groupBy('item1).agg(collect_list(struct('item2,'count)).as("set"))
+-----+----------------------------+
|item1|set |
+-----+----------------------------+
|1 |[[5,3], [4,1], [3,2], [2,2]]|
|2 |[[4,1], [1,2], [5,2], [3,1]]|
+-----+----------------------------+
collect_set
も使用できます
編集:詳細については、tuples
はデータフレームに存在しません。最も近い構造はstruct
です。これは、型なしデータセットAPIのケースクラスと同等であるためです。
編集2:collect_set
には、結果が実際にはセットではないという警告が含まれていることにも注意してください(SQLタイプにセットプロパティを持つデータタイプはありません)。つまり、(少なくともバージョン2.1.0では)順序が異なる別個の「セット」になってしまう可能性があります。次に、それらをsort_array
でソートする必要があります。