我有一个数据列表,该值基本上是一个bson文档(想想json),每个json的大小范围从5k到20k。它既可以是bson对象格式,也可以直接转换为json:
Key, Value
--------
K1, JSON1
K1, JSON2
K2, JSON3
K2, JSON4
我希望groupByKey会产生:
K1, (JSON1, JSON2)
K2, (JSON3, JSON4)
所以当我这样做时:
val data = [...].map(x => (x.Key, x.Value))
val groupedData = data.groupByKey()
groupedData.foreachRDD { rdd =>
//the elements in the rdd here are not really grouped by the Key
}
我对RDD的行为感到困惑。我在互联网上阅读了很多文章,包括Spark的官方网站:https://spark.apache.org/docs/0.9.1/scala-programming-guide.html
仍然无法实现我想要的目标。
--------更新---------------------
基本上我真的需要按密钥分组,关键是要在Elasticsearch中使用的索引,以便我可以通过Elasticsearch for Hadoop基于密钥执行批处理:
EsSpark.saveToEs(rdd);
我无法对每个分区执行操作,因为Elasticsearch只接受RDD。我试图使用sc.MakeRDD或sc.parallize,两者都告诉我它不可序列化。
我试图使用:
EsSpark.saveToEs(rdd, Map(
"es.resource.write" -> "{TheKeyFromTheObjectAbove}",
"es.batch.size.bytes" -> "5000000")
配置文档位于:https://www.elastic.co/guide/en/elasticsearch/hadoop/current/configuration.html
但是,与不使用配置根据单个文档的值定义动态索引相比,它非常慢,我怀疑它正在解析每个json以动态获取值。
答案 0 :(得分:3)
以下是示例。
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
object Test extends App {
val session: SparkSession = SparkSession
.builder.appName("Example")
.config(new SparkConf().setMaster("local[*]"))
.getOrCreate()
val sc = session.sparkContext
import session.implicits._
case class Message(key: String, value: String)
val input: Seq[Message] =
Seq(Message("K1", "foo1"),
Message("K1", "foo2"),
Message("K2", "foo3"),
Message("K2", "foo4"))
val inputRdd: RDD[Message] = sc.parallelize(input)
val intermediate: RDD[(String, String)] =
inputRdd.map(x => (x.key, x.value))
intermediate.toDF().show()
// +---+----+
// | _1| _2|
// +---+----+
// | K1|foo1|
// | K1|foo2|
// | K2|foo3|
// | K2|foo4|
// +---+----+
val output: RDD[(String, List[String])] =
intermediate.groupByKey().map(x => (x._1, x._2.toList))
output.toDF().show()
// +---+------------+
// | _1| _2|
// +---+------------+
// | K1|[foo1, foo2]|
// | K2|[foo3, foo4]|
// +---+------------+
output.foreachPartition(rdd => if (rdd.nonEmpty) {
println(rdd.toList)
})
// List((K1,List(foo1, foo2)))
// List((K2,List(foo3, foo4)))
}