在clojure中实现flambo mapValues函数

时间:2015-07-29 09:27:49

标签: clojure apache-spark rdd flambo

我有一个clojure函数,它使用flambo v0.60函数api对样本数据集进行一些分析。我注意到当我使用(get rdd 2)而不是获取rdd集合中的第二个元素时,它获取rdd集合的第一个元素的第二个字符。我的假设是clojure将rdd集合的每一行视为一个完整的字符串而不是一个向量,以便我能够获得集合中的第二个元素。我正在考虑使用map-values函数将映射的值转换为我可以得到第二个元素的向量,我试过这个:

(defn split-on-tab-transformation [xctx input]
 (assoc xctx :rdd (-> (:rdd xctx)
                   (spark/map (spark/fn [row] (s/split row #"\t")))
                   (spark/map-values vec)))) 

不幸的是我收到了一个错误: java.lang.IllegalArgumentException: No matching method found: mapValues for class org.apache.spark.api.java.JavaRDD...

这是代码返回rdd中的第一个集合: (假设我删除了上述函数中的(spark/map-values vec)

(defn get-distinct-column-val
 "input = {:col val}"
  [ xctx input ]
  (let [rdds (-> (:rdd xctx)
           (f/map (f/fn [row] row))
           f/first)]
(clojure.pprint/pprint rdds)))

输出:

[2.00000 770127      200939.000000   \t6094\tBENTONVILLE, AR DPS\t22.500000\t5.000000\t2.500000\t5.000000\t0.000000\t0.000000\t0.000000\t0.000000\t0.000000\t1\tStore Tab\t0.000000\t4.50\t3.83\t5.00\t0.000000\t0.000000\t0.000000\t0.000000\t19.150000]

如果我尝试获取第二个元素770127

(defn get-distinct-column-val
 "input = {:col val}"
  [ xctx input ]
  (let [rdds (-> (:rdd xctx)
           (f/map (f/fn [row] row))
           f/first)]
   (clojure.pprint/pprint (get rdds 1)))

我明白了:

[\.]

Flambo documentation for map-values

我是clojure的新手,我很感激任何帮助。感谢

1 个答案:

答案 0 :(得分:1)

首先,map-values(或Spark API中的mapValues)仅在PairRDD上有效转换(例如此类[:foo [1 2 3]]。具有此类值的RDD可以被解释作为一些某种地图,其中第一个元素是一个键,第二个元素是一个值。

如果您有这样的RDD mapValues转换值而不更改密钥。在这种情况下,你应该使用第二个地图,虽然它似乎已经过时,因为clojure.string/split已经返回了一个向量。

使用map-values的简单示例:

(let [pairs [(ft/tuple :foo 1) (ft/tuple :bar 2)]
      rdd (f/parallelize-pairs sc pairs) ;; Note parallelize-pairs -> PairRDD
      result (-> rdd       
          (f/map-values inc) ;; Map values
          (f/collect))]
  (assert (= result [(ft/tuple :foo 2) (ft/tuple :bar 3)])))

根据您的描述,您似乎正在使用输入RDD而不是从split-on-tab-transformation返回的RDD。如果我不得不猜测您是否尝试使用原始xctx,而不是split-on-tab-transformation返回的原始maps。由于Clojure assoc是不可变的,get-distinct-column-val不会更改传递的参数,而RDD[String]会收到RDD[Array[String]]而不会(spit "data.txt" (str "Mazda RX4\t21\t6\t160\n" "Mazda RX4 Wag\t21\t6\t160\n" "Datsun 710\t22.8\t4\t108\n"))

根据命名约定,我假设您希望为数组中的单个位置获取不同的值。为清楚起见,我删除了代码中未使用的部分。首先让我们创建虚拟数据:

(defn split-on-tab-transformation [xctx]
   (assoc xctx :rdd (-> (:rdd xctx)
                        (f/map #(clojure.string/split % #"\t")))))

(defn get-distinct-column-val
  [xctx col]
    (-> (:rdd xctx)
      (f/map #(get % col))
        (f/distinct)))

添加功能的重写版本

(assert
 (= #{"Mazda RX4 Wag" "Datsun 710" "Mazda RX4"}
    (-> {:sc sc :rdd (f/text-file sc "data.txt")}
      (split-on-tab-transformation)
      (get-distinct-column-val 0)
      (f/collect)
      (set))))

和结果

   var foods:JSON?{
        didSet{
            self.setupFood()
        }
    }

    func setupFood(){

    return value = {
                  "total_count": 1, 
                  "foods": [{
                               "food_name": "fish",
                               "article_id": 122
                  }],
                  "table": {"table_id": 60,
                            "table_name": "far left"}
                  }
    }