让 PigPen 支持本地代码和命名空间

介绍 PigPen 的文章中,做者在 Future Work 一节中提到,咱们在 PigPen 中不能调用本地声明的代码。例如一下代码在最后生成的 Pig 脚本中是执行不了的,会报找不到符号 foo 的错误:html

(ns test.core
  (:require [pigpen.core :as pig]))
(defn foo [x] …)
(pig/map foo)

这样就只能把全部 foo 函数要作的事情所有写在 pig/map 后面。若是 foo 要作的事情不少,代码很长,那么写出来的代码将很是难看。git

PigPen 不光不支持本地代码的调用,还不支持 namespace 的引用(https://groups.google.com/forum/#!msg/pigpen-support/-Kd06UfzxEU/vYEAZvmZLFcJ)。github

这些在任何编程语言中都看似很天然的功能在初期的 PigPen 中都不支持。其实这里的每个本地代码的调用或者其余 namespace 中函数的调用在最后写成 Pig 脚本后都是一个 UDF,而 PigPen 的目的之一也就是要取代 Pig 脚本和 UDF混写的方式,因此应该会有解决的办法,但没时间(也懒)去扒源代码去想办法处理这种状况,因而到 GitHub 上找到主要的贡献者 Matt Bossenbroek,向他发邮件请教。编程

Matt 指出若是要用调用本地代码须要这样作:编程语言

(ns test.core
  (:require [pigpen.core :as pig]))
(defn foo [x] …)
(pig/map (do (require 'test.core) foo))

我尝试了一下,好像并不能达到预期的效果。函数

因而我试着改变一下生成的 Pig 脚本,看能不能运行起来。反正最后部署到集群上运行的时候也是用的生成的 Pig 脚本文件。在生成的 Pig 脚本中,全部的 Clojure 代码都被 pigpen.PigPenFn* 一组类(PigPenFnBooleanPigPenFnStringPigPenFnTuplePigPenFnDataBagPigPenFnDataByteArray)包装成 UDF 插入到最终生成的 Pig 脚本中,不一样的后缀返回不一样的 Pig 基本类型的值。ui

在生成的 Pig 脚本中,这些类的第一个参数都是 '(clojure.core/require (quote [pigpen.pig]))',看一下代码知道这个参数会被当作 Clojure 代码读入来作初始化用,因此应该在这里加上要包含的 namespace。试了一些果真能够运行了。再看一下代码发现要经过 PigPen 的方法来添加这个 require 也很差弄,就打算先用 PigPen 生成 Pig 脚本,而后在这里加上另外要包含的 namespace(写一个脚本往每一个这样的类里面加上 namespace 也不会太麻烦)。google

同时也顺带问一下 Matt 怎么利用 PigPen 来作,Matt 说正在考虑用什么样的方式来支持引用 namespace。结果在大年初二早上收到邮件说新版本的 PigPen([com.netflix.pigpen/pigpen "0.1.4"]) 能够支持了,并给出了一个例子:spa

(ns pigpen-demo.core
  (:require [pigpen.core :as pig]
            [clojure.string :as str]))

(defn square [x]
  (* x x))

(defn my-query []
  (->>
    (pig/return [1 2 3])
    (pig/map square)
    (pig/map (fn [x] (square x)))
    (pig/into [])
    (pig/map #(str/join "," %))
    (pig/dump)))

可是必定要把整个项目打包成一个 uberjar 分发到集群上去。这样基本上能够把 PigPen 用到个人实验性的工做中去了(production 环境不容许乱用新东西)。.net

相关文章
相关标签/搜索