web-dev-qa-db-ja.com

Spark

2番目の表で参照されている部門IDを持っている従業員のみを保持したいと思います。

Employee table
LastName    DepartmentID
Rafferty    31
Jones   33
Heisenberg  33
Robinson    34
Smith   34

Department table
DepartmentID
31  
33  

私は動作しない次のコードを試しました:

employee = [['Raffery',31], ['Jones',33], ['Heisenberg',33], ['Robinson',34], ['Smith',34]]
department = [31,33]
employee = sc.parallelize(employee)
department = sc.parallelize(department)
employee.filter(lambda e: e[1] in department).collect()

Py4JError: An error occurred while calling o344.__getnewargs__. Trace:
py4j.Py4JException: Method __getnewargs__([]) does not exist

何か案は?私はPythonでSpark 1.1.0を使用しています。ただし、ScalaまたはPythonの回答を受け入れます。

13
poiuytrez

この場合、達成したいのは、各パーティションで部門テーブルに含まれているデータでフィルタリングすることです。これが基本的な解決策になります。

val dept = deptRdd.collect.toSet
val employeesWithValidDeptRdd = employeesRdd.filter{case (employee, d) => dept.contains(d)}

部門データが大きい場合、ブロードキャスト変数は、タスクごとにデータをシリアル化する代わりに、データをすべてのノードに1回配信することで、パフォーマンスを向上させます。

val deptBC = sc.broadcast(deptRdd.collect.toSet)
val employeesWithValidDeptRdd = employeesRdd.filter{case (employee, d) => deptBC.value.contains(d)}

結合を使用することは機能しますが、結合を実現するにはデータの分散シャッフル(byKey)が必要になるため、非常にコストのかかるソリューションです。要件が単純なフィルターであることを考えると、(上記のように)各パーティションにデータを送信すると、パフォーマンスが大幅に向上します。

23
maasg

私はついに結合を使用してソリューションを実装しました。 Sparkからの例外を回避するために、部門に0の値を追加する必要がありました。

employee = [['Raffery',31], ['Jones',33], ['Heisenberg',33], ['Robinson',34], ['Smith',34]]
department = [31,33]
# invert id and name to get id as the key
employee = sc.parallelize(employee).map(lambda e: (e[1],e[0]))
# add a 0 value to avoid an exception
department = sc.parallelize(department).map(lambda d: (d,0))

employee.join(department).map(lambda e: (e[1][0], e[0])).collect()

output: [('Jones', 33), ('Heisenberg', 33), ('Raffery', 31)]
10
poiuytrez

複数の列の複数の値のフィルタリング:

データベース(この例ではHiveまたはSQLタイプdb)からデータをプルしていて、複数の列でフィルター処理する必要がある場合は、最初のフィルターを使用してテーブルをロードしてから、フィルターを反復処理する方が簡単な場合があります。 RDD(複数の小さな反復がSparkプログラミング)の推奨される方法です:

{
    import org.Apache.spark.sql.Hive.HiveContext
    val hc = new HiveContext(sc)

    val first_data_filter = hc.sql("SELECT col1,col2,col2 FROM tableName WHERE col3 IN ('value_1', 'value_2', 'value_3)")
    val second_data_filter = first_data_filter.filter(rdd => rdd(1) == "50" || rdd(1) == "20")
    val final_filtered_data = second_data_filter.filter(rdd => rdd(0) == "1500")

}

もちろん、正しい値でフィルタリングするには、データを少し知っておく必要がありますが、それは分析プロセスの一部です。

0
WaveRider

上記の同じexmについて、2番目の表で参照されている部門IDを含むまたは部門IDに含まれる従業員のみを保持したいと思います。ただし、結合操作である必要はありません。「contained」または「in」で表示されます。つまり、33は「in」334および335です。

employee = [['Raffery',311], ['Jones',334], ['Heisenberg',335], ['Robinson',34], ['Smith',34]]
department = [31,33]
employee = sc.parallelize(employee)
department = sc.parallelize(department)
0
yechiel