web-dev-qa-db-ja.com

Spark値でソートされたコレクションを取得

このチュートリアルを試していました http://spark.Apache.org/docs/latest/quick-start.html 最初にファイルからコレクションを作成しました

textFile = sc.textFile("README.md")

それから私は言葉を鳴らすコマンドを試しました:

wordCounts = textFile.flatMap(lambda line: line.split()).map(lambda Word: (Word, 1)).reduceByKey(lambda a, b: a+b)

コレクションを印刷するには:

 wordCounts.collect()

コマンドsortByKeyを使用して、Wordで並べ替える方法を見つけました。値で並べ替えるのと同じこと、この場合はドキュメント内でWordが出現する数をどのように行うことができるのかと思っていました。

34
user3702916

ソートは通常、collect()が呼び出される前に実行する必要があります。これは、データセットをドライバープログラムに返すためです。また、これはhadoop map-reduceジョブがJavaでプログラムされるため、 wantは(通常)HDFSに書き込まれます。 spark APIを使用すると、この方法により、出力を「生の」形式で自由に書き込むことができます。たとえば、さらに処理するための入力として使用できるファイルに書き込むことができます。

Eliasahの提案に従って、collect()の前にsparkのscala APIソートを使用し、Tuple2.swap()を2回使用します。 2番目のフィールド(_2という名前)の最初のフィールド(_1という名前)の単語数のカウントが含まれています。以下は、spark-Shellでこれをスクリプト化する方法の例です。

// this whole block can be pasted in spark-Shell in :paste mode followed by <Ctrl>D
val file = sc.textFile("some_local_text_file_pathname")
val wordCounts = file.flatMap(line => line.split(" "))
  .map(Word => (Word, 1))
  .reduceByKey(_ + _, 1)  // 2nd arg configures one task (same as number of partitions)
  .map(item => item.swap) // interchanges position of entries in each Tuple
  .sortByKey(true, 1) // 1st arg configures ascending sort, 2nd arg configures one task
  .map(item => item.swap)

ソートの順序を逆にするには、最初の引数が昇順のブール値であるため、sortByKey(false、1)を使用します。 2番目の引数はタスクの数(パーティションの数に相当)で、1つの出力データファイルのみが必要な小さな入力ファイルでテストするために1に設定されます。 reduceByKeyもこのオプションの引数を取ります。

この後、wordCounts RDDをテキストファイルとしてsaveAsTextFile(directory_pathname)を使用してディレクトリに保存できます。このディレクトリには、ジョブに設定されたリデューサーの数に応じて、part-xxxxxファイル(part-00000で始まる)が格納されます(1レデューサーごとの出力データファイル)、ジョブが成功したかどうかに応じた_SUCCESSファイル、および.crcファイル。

Pysparkを使用すると、上記のpythonスクリプトと非常によく似たscalaスクリプトは、実質的に同じ出力を生成します。これは、値によるコレクションのソートを示すpysparkバージョンです。

file = sc.textFile("file:some_local_text_file_pathname")
wordCounts = file.flatMap(lambda line: line.strip().split(" ")) \
    .map(lambda Word: (Word, 1)) \
    .reduceByKey(lambda a, b: a + b, 1) \ # last arg configures one reducer task
    .map(lambda (a, b): (b, a)) \
    .sortByKey(1, 1) \ # 1st arg configures ascending sort, 2nd configures 1 task
    .map(lambda (a, b): (b, a))

pythonは先頭および末尾の空白をデータとしてキャプチャするため、stripby)はスペースで各行を分割する前に挿入されますが、spark-を使用する必要はありません。シェル/スカラ。

WordCountのsparkバージョンとpythonバージョンの出力の主な違いは、spark出力(Word、3)python出力(u'Word '、3)。

spark RDDメソッドの詳細については、 http://spark.Apache.org/docs/1.1.0/api/python/pyspark.rdd.RDD-class.html を参照してください。 pythonおよび https://spark.Apache.org/docs/latest/api/scala/#org.Apache.spark.rdd.RDD for scalaの場合。

Spark-Shellでは、wordCountsでcollect()を実行すると、RDDからArray [(String、Int)] = Array [Tuple2(String、Int)]に変換され、各Tuple2要素の2番目のフィールドでソートできます。を使用して:

Array.sortBy(_._2) 

sortBy もオプションの暗黙的な数学を取ります。ロメオ・キエンツラーがこの質問に対する以前の回答で示したような順序付け引数。 Array.sortBy(_._ 2)は、Intの既存の順序をオーバーライドするため、map-reduceスクリプトを実行する前に暗黙的な逆順序を定義するだけで、_2フィールドでArray Tuple2要素の逆ソートを行います。 Romeo Kienzlerによって既に定義されている逆整数順序は次のとおりです。

// for reverse order
implicit val sortIntegersByString = new Ordering[Int] {
  override def compare(a: Int, b: Int) = a.compare(b)*(-1)
}

この逆順序を定義するもう1つの一般的な方法は、aとbの順序を逆にして、比較定義の右側に(-1)をドロップすることです。

// for reverse order
implicit val sortIntegersByString = new Ordering[Int] {
  override def compare(a: Int, b: Int) = b.compare(a)
}   
32
user4322779

よりPython的な方法でそれを行う。

# In descending order
''' The first parameter tells number of elements
    to be present in output.
''' 
data.takeOrdered(10, key=lambda x: -x[1])
# In Ascending order
data.takeOrdered(10, key=lambda x: x[1])
20
kiran6

値で順序付けされた上位N個の要素を取得する場合:

theRDD.takeOrdered(N, lambda (key, value): -1 * len(value))

文字列の長さで注文する場合。

一方、値がすでに希望の順序に適した形式になっている場合は、次のようになります。

theRDD.takeOrdered(N, lambda (key, value): -1 * value)

十分でしょう。

6
okello

このようにすることができます

// for reverse order
implicit val sortIntegersByString = new Ordering[Int] {
    override def compare(a: Int, b: Int) = a.compare(b)*(-1)
}

counts.collect.toSeq.sortBy(_._2)

したがって、基本的にRDDをシーケンスに変換し、並べ替え方法を使用して並べ替えます。

上記のブロックは、降順のソート順を取得するためにソート動作をグローバルに変更します。

5
Romeo Kienzler

here で文書化された汎用のsortBy変換(アクションではなく、つまり配列ではなくRDDを返す)を使用できると思います。

だからあなたの場合、あなたはできる

wordCounts.sortBy(lambda (Word, count): count)
4
stackoverflower

出力を値でソートする最も簡単な方法。 reduceByKeyの後に、キーを値として、値をキーとして出力をスワップし、falseが降順でソートされるsortByKeyメソッドを適用できます。デフォルトでは、昇順でソートされます。

 val test=textFile.flatMap(line=> line.split(" ")).map(Word=> (Word, 1)).reduceByKey(_ + _).map(item => item.swap).sortByKey(false)

pythonの@kefによる解決策は...

以下を変更する必要があります-

.map(lambda (a, b): (b, a))

.map(lambda a: (a[1], a[0]))
2
Sud
 wordCounts.map(lambda (a,b) : (b,a)).sortByKey(ascending=False).map(lambda (a,b) : (b,a)).collect()

WordCount rddの各行は次のように見えるため、このソリューションは機能します。

(単語、COUNT)

最初のマップは、タプルの順序を逆にしたrddを生成します。つまり、これらは次のようになります。

(COUNT、Word)

SortByKeyを実行すると、COUNTがキーとして取得されます。次に、2番目のマップは、ソートされた2番目のrddを元の形式にマップします。

(単語、COUNT)

行ごとではなく、行はワードカウントでソートされます。

ここでの暗黙の前提は、マッピングによってRDD行の順序が変更されないということです。さもないと、2番目のマップがソートを混乱させる可能性があります。

1

SCALA=を使用してsortByValueを実行するより良い方法は

val count = oozie.flatMap(line => line.split(" ")).map(Word => (Word,1)).reduceByKey(_ + _).sortBy(x => x._2)

x._2は、リストxの2番目の要素を表します。

降順でソートを行うには「-x._2」

scala> val count = oozie.flatMap(line => line.split(" ")).map(Word => (Word,1)).reduceByKey(_ + _).sortBy(x => -x._2)

count: org.Apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[26] at sortBy at <console>:25

scala> count.take(10)
res6: Array[(String, Int)] = Array((the,4603), (to,1707), (and,1595), (of,1337), (a,1319), (Oozie,1302), (in,1131), (.,994), (is,956), (for,753))
1
Suren

Pythonを使用して解決できました。そこで、ペア値のリストを作成し、値でソートしました。

out = wordCounts.collect()
outSort = sorted(out, key=lambda Word:word[1])
0
user3702916