如何在Scala

时间:2018-03-17 13:52:35

标签: scala sorting apache-spark rdd

所以这是data。 结构解释:

  

CREATE TABLE productsproduct_id int(11)NOT NULL   AUTO_INCREMENT,product_category_id int(11)NOT NULL,
  product_name varchar(45)NOT NULL,product_description   varchar(255)NOT NULL,product_price float NOT NULL,
  product_image varchar(255)NOT NULL,PRIMARY KEY(product_id))   ENGINE = InnoDB AUTO_INCREMENT = 1346 DEFAULT CHARSET = utf8 |

更新:我的环境是Spark 1.6.2和Scala 2.10.5

我希望得到一个按product_name asc,product_price desc排序的RDD。

我知道如何将RDD分类为asc:

val p = sc.textFile("products")
val fp = p.filter(r=>r.split(",")(4) !="")
val mfp = fp.map(r=>(r.split(",")(4).toFloat, r)).sortByKey(false).map(r=> (r._2.split(",")(4), r._2.split(",")(2))

现在我只有两个字段:product_priceproduct_name

我可以进行排序:

mfp.sortBy(r=>(r._1, r._2))

这给了我按名称排序的结果,然后按价格排序,在asc中;

(10,159.99)
(10,159.99)
(10,169.99)
(10,1799.99)
(10,189.0)
(10,199.98)
(10,199.99)
(10,199.99)
(10,1999.99)
(10,269.99)

我需要的是(product_category_id, product_name, product_price),在 asc 中按product_category_id排序,然后product_price desc

我只想要每product_category_id个前3个产品。

2 个答案:

答案 0 :(得分:0)

你几乎得到了它。 RDD sortBy始终按升序排序。即使你的字段是一个数字,所以你可以通过将它乘以-1得到反向排序。我使用了一个case类来使你的代码更具可读性。

case class Info(product_category_id: Int, product_name: String, product_price: Double)

val rdd = sc.textFile("products").map(line => line.split(",")).filter(!_.isEmpty)

val infos = rdd.map { split =>
    Info(
        product_category_id = split(1),
        product_name = split(2),
        product_price = split(4)
    )
}

val sorted = infos.sortBy(info => (info.product_category_id, -info.product_price))

坏消息是,这样您就不会按product_category_id进行分组,因此您无法获得每个类别的前3个产品。幸运的是,Spark mlib提供了一种方法来完成你想要的,使用有界优先级队列实现。

import org.apache.spark.mllib.rdd.MLPairRDDFunctions._
val keyByCategory = infos.keyBy(_.product_category_id)
val topByKey: RDD[(Int, Array[Info])] = keyByCategory.topByKey(3)(Ordering.by(-_.product_price))
val topWithKeysSorted = topByKey.sortBy(_._1)

答案 1 :(得分:0)

我找到了一个更容易(对我而言)的SparkSQL解决方案,这里是完整的脚本:

val productsRDD = sc.textFile("products").filter(x=>x.split(",")(4)!="")
val productsRDDmap = productsRDD.map(a => (a.split(",")(0).toInt, a.split(",")(1).toInt, a.split(",")(2), a.split(",")(4).toFloat))
val productsRDDmapDF = productsRDDmap.toDF("product_id","product_category_id", "product_name", "product_price")
productsRDDmapDF.registerTempTable("products")
val query = """
select  product_id , product_category_id, product_price,  row_number() over(partition by product_category_id  order by product_price  desc) as p_order from products  """
val result = sqlContext.sql(query)
result.where("p_order<=3").show(200)