我是Spark的新手,也是Clojure的新手(尽管我非常喜欢Clojure到目前为止可以做的事情)。我目前正在尝试使用Sparkling在Clojure中解析JSON,并且在转换数据并以我可以理解和调试的形式获取数据的基础方面遇到了麻烦。在下面的示例中,我使用了虚拟数据,但是我的实际数据超过了400GB。
作为一个例子,我首先尝试用逗号分割JSON输入的每一行(每一行都是完整记录),这样我就可以获得键和值的列表(最终转换为关键字和值映射)。在具有伪数据的Scala(更容易找到Spark示例)中,此方法工作正常:
val data = sc.parallelize(Array ("a:1,b:2","a:3,b:4"))
val keyVals = data.map(line => line.split(","))
keyVals.collect()
这将返回Array [Array [String]] = Array(Array(a:1,b:2),Array(a:3,b:4)),这至少是键值的合理起点映射。
但是,当我在Clojure中运行以下命令时会产生闪闪发光:
(def jsony-strings (spark/parallelize sc ["a:1,b:2","a:3,b:4"]))
(def jsony-map (->> jsony-strings
(spark/map (fn [l] (string/split l #",")))
))
(spark/collect jsony-map)
我从JVM中获得了通常的并发意大利面,其症结似乎是:
2018-08-24 18:49:55,796 WARN序列化。实用工具:55-错误反序列化对象(clazz:gdelt.core $ fn__7437,命名空间:gdelt.core)
java.lang.ClassNotFoundException:gdelt.core $ fn__7437
这是一个错误,我似乎得到了几乎所有我想做的比计数还复杂的事情。
有人可以指出正确的方向吗?
我想我应该注意,我的大问题是在大于内存(400G)的数据集中处理大量的JSON行。我将使用JSON键进行过滤,排序,计算等,并且Spark管道对于快速并行处理和这些功能的便利性都看起来不错。但是我当然愿意考虑使用其他替代方法来处理此数据集。
答案 0 :(得分:1)
您应为此使用Cheshire:
;; parse some json
(parse-string "{\"foo\":\"bar\"}")
;; => {"foo" "bar"}
;; parse some json and get keywords back
(parse-string "{\"foo\":\"bar\"}" true)
;; => {:foo "bar"}
I like to use a shortcut对于第二种情况,因为我一直想将字符串键转换为clojure关键字:
(is= {:a 1 :b 2} (json->edn "{\"a\":1, \"b\":2}"))
这只是一个简单的包装,带有(我认为)一个易于记忆的名称:
(defn json->edn [arg]
"Shortcut to cheshire.core/parse-string"
(cc/parse-string arg true)) ; true => keywordize-keys
(defn edn->json [arg]
"Shortcut to cheshire.core/generate-string"
(cc/generate-string arg))
更新:请注意,Cheshire可以处理惰性流:
;; parse a stream lazily (keywords option also supported)
(parsed-seq (clojure.java.io/reader "/tmp/foo"))