Cuneiform 是用于大规模科学数据分析的开源 工作流程语言 [2] [3] 。
它是促进并行计算 的静态类型 的纯函数式 编程语言 。它的特征是有个全功能的外界函数接口 ,允许用户集成来自很多外部编程语言的软件。Cuneiform在组织层面上提供了一些设施,如条件分支 和通用递归 ,使其具有图灵完备性 。
概述
Cuneiform尝试拉近在科学工作流程系统如Apache Taverna 、KNIME 或Galaxy ,与大规模数据分析程序模型如MapReduce 或Pig Latin 之间的间隙,同时提供函数式编程语言的通用性。
Cuneiform是用分布式Erlang 实现的。如果运行在分布式模态下,它导出一个遵循POSIX 的分布式文件系统 ,如Gluster 或Ceph (用FUSE 集成某个其他文件系统例如HDFS )。作为替代选择,Cuneiform脚本可以执行在HTCondor 或Apache Hadoop 顶上[4] [5] [6] [7] 。
Cuneiform受到了Peter Kelly的工作的影响,他提议函数式编程作为科学工作流程执行的模型[8] 。
故而,Cuneiform不同于其他的基于数据流程编程 的工作流程语言,如并行 脚本语言 Swift [9] 。
扩展软件集成
外部工具和库(比如R 或Python 库)是通过外界函数接口 来集成的。通过它可以组合,比如允许通过snippet节点使用外部软件的KNIME ,或为集成Java 软件提供BeanShell 服务的Apache Taverna 。通过定义采用外界语言的任务,就可能使用一个外部工具或库的API。这种方式下,工具可以直接集成而不需要写包装器或重新实现工具[10] 。
目前支持的外界编程语言有:
计划增加外界语言AWK 和gnuplot 。
类型系统
Cuneiform提供简单的、静态检查的类型系统[11] 。虽然Cuneiform提供列表作为复合数据类型 ,它省略了传统的列表访问子(head
和tail
),以避免在访问空列表时,可能引起的运行时间错误的可能性。转而列表只能通过在其上map
或fold
,以全有或全无方式访问。此外,Cuneiform(在组织层面)省略了算术,这排除了除以零的可能性。省略任何的部份定义运算,允许保证运行时间错误只能在外界代码中引发。
基础数据类型
Cuneiform提供的基础数据类型有布尔值 、字符串 和文件 。这里的文件被用来以任意格式在外界函数之间交换数据。
记录和模式匹配
Cuneiform提供记录 (结构)作为复合数据类型。下面的例子展示定义一个变量r
,作为有两个字段a1
和a2
的记录,第一个是字符串,而第二个是布尔值:
let r : < a1 : Str , a2 : Bool > =
< a1 = "my string" , a2 = true >;
记录可以要么通过投影(projection)要么通过模式匹配 来访问。下面的例子从记录r
,提取两个字段a1
和a2
:
let a1 : Str = ( r | a1 );
let < a2 = a2 : Bool > = r ;
列表和列表处理
进一步的,Cuneiform提供列表 作为复合数据类型。下面的例子展示定义一个变量xs
,作为一个有三个元素的一个文件:
let xs : [ File ] =
[ 'a.txt' , 'b.txt' , 'c.txt' : File ];
列表可以通过for
和fold
算子来处理。这里的for
算子可以接受多个列表,来逐个元素的处置列表(类似于Racket 中的for/list
、Common Lisp 中的mapcar
或Erlang 中的zipwith
)。
下面的例子展示如何在一个单一的列表上map
,结果是一个文件列表:
for x <- xs do
process - one ( arg1 = x )
: File
end ;
下面的例子展示如何zip
两个列表,结果也是一个文件列表:
for x <- xs , y <- ys do
process - two ( arg1 = x , arg2 = y )
: File
end ;
最后,列表可以使用fold
算子来做聚集。下面的例子合计一个列表的元素:
fold acc = 0, x <- xs do
add( a = acc, b = x )
end;
并行执行
Cuneiform是纯函数式语言,就是说它不支持可变引用 。作为结论,它可以使用独立子项,将一个程序分解成可并行的各部份。Cuneiform调度器分布这些部份到做工节点。此外,Cuneiform采用传名调用求值策略 ,值只在它对计算结果有贡献时计算。最后,外界函数应用是记忆化 的,用来加速包含以前推导结果的计算。
例如,下列Cuneiform程序允许f
和g
的应用平行的运行,而h
是有依赖的,它只在f
和g
二者完成的时候可以开始:
let output-of-f : File = f();
let output-of-g : File = g();
h( f = output-of-f, g = output-of-g );
下列Cuneiform程序通过将函数f
映射到一个三元素列表,创建了三个并行应用:
let xs : [File] =
['a.txt', 'b.txt', 'c.txt' : File];
for x <- xs do
f( x = x )
: File
end;
类似的,在记录r
的构造中,f
和g
的应用是独立的,因此可以并行运行:
let r : < a : File , b : File > =
< a = f (), b = g () > ;
例子
下面是一个hello-world脚本:
def greet ( person : Str ) -> < out : Str >
in Bash * {
out = "Hello $person"
} *
( greet ( person = "world" ) | out );
这个脚本定义了采用Bash 的一个任务greet
,它对其字符串实际参数person
预加上"Hello "
。这个函数产生具有一个单一字符串字段的记录out
。应用greet
,绑定实际参数person
到字符串"world"
,产生记录<out = "Hello world">
。将这个记录投影为它的字段out
,求值出字符串"Hello world"
。
可以通过定义采用Bash 的一个任务来集成命令行工具:
def samtoolsSort ( bam : File ) -> < sorted : File >
in Bash * {
sorted = sorted . bam
samtools sort - m 2 G $bam - o $sorted
} *
在这个例子中定义了任务samtoolsSort
。它调用了工具SAMtools ,处置一个BAM格式的输入文件,并产生一个排序了也是BAM格式的输出文件。
发行历史
版本
出现日期
实现语言
发布平台
外界语言
1.0.0
2014年5月
Java
Apache Hadoop
Bash, Common Lisp, GNU Octave, Perl, Python, R, Scala
2.0.x
2015年3月
Java
HTCondor , Apache Hadoop
Bash, BeanShell , Common Lisp , MATLAB, GNU Octave, Perl, Python, R, Scala
2.2.x
2016年4月
Erlang
HTCondor , Apache Hadoop
Bash, Perl, Python, R
3.0.x
2018年2月
Erlang
分布式Erlang
Bash , Erlang , Java , MATLAB , GNU Octave , Perl , Python , R , Racket
在2016年4月,Cuneiform的实现语言从Java 切换成了Erlang ,并且在2018年2月,它的主要发布执行平台从Apache Hadoop 变更为分布式Erlang。此外,从2015年到2018年,HTCondor 曾被作为可替代执行平台来维护。
Cuneiform的外表语法修订过两次,这反映在主版本号上。
版本1
在2014年5月发布的最初草案中,Cuneiform密切关联于Make ,它构造解释器在执行期间要遍历的静态数据依赖图。与后来版本的主要区别,是缺乏条件、递归或静态类型检查。区分文件和字符串,是通过同波浪号~
形成一个单一引用的字符串。脚本的查询表达式,通过target
关键字来介入。Bash是缺省外界语言。函数应用必须使用apply
形式来完成,它接受task
作为第一个关键字实际参数。一年之后,这种外表语法被一种精简却类似的版本所替代。
下面的例子脚本从一个FTP服务器下载一个参考genome:
declare download-ref-genome;
deftask download-fa( fa : ~path ~id ) *{
wget $path/$id.fa.gz
gunzip $id.fa.gz
mv $id.fa $fa
}*
ref-genome-path = ~'ftp://hgdownload.cse.ucsc.edu/goldenPath/hg19/chromosomes';
ref-genome-id = ~'chr22';
ref-genome = apply(
task : download-fa
path : ref-genome-path
id : ref-genome-id
);
target ref-genome;
版本2
基于Swing的编辑器和Cuneiform 2.0.3的REPL
Cuneiform外表语法的第二个草案,首次发表于2015年3月,在Cuneiform的实现语言从Java 到Erlang 的迁移期间,持续使用了三年。求值不同于早期方式,解释器归约一个表达式,而非遍历一个静态图。在外表语法保持使用这段时期,解释器被形式化和简化,这导致了第一个Cuneiform的语义规定。语法特征是有了条件。但是,布尔值被编码为列表,再度利用空列表为布尔值false
,非空列表为布尔值true
。递归后来作为形式化的副产品而增加。但是,静态类型检查,只在后来的版本3中介入。
下列脚本解压一个压缩文件,并把它分解为大小均匀的划分:
deftask unzip( <out( File )> : zip( File ) ) in bash *{
unzip -d dir $zip
out=`ls dir | awk '{print "dir/" $0}'`
}*
deftask split( <out( File )> : file( File ) ) in bash *{
split -l 1024 $file txt
out=txt*
}*
sotu = "sotu/stateoftheunion1790-2014.txt.zip";
fileLst = split( file: unzip( zip: sotu ) );
fileLst;
版本3
Cuneiform外表语法的当前版本,比较于早期的草案,是尝试拉近与主流函数式编程语言的间隙。它的特征是简单的静态检查的类型系统,并在列表之外介入记录作为第二个复合数据结构类型。布尔值独立为基础数据类型。
下列脚本解包一个文件,结果为一个文件列表:
def untar( tar : File ) -> <fileLst : [File]>
in Bash *{
tar xf $tar
fileLst=`tar tf $tar`
}*
let hg38Tar : File =
'hg38/hg38.tar';
let <fileLst = faLst : [File]> =
untar( tar = hg38Tar );
faLst;
引用
^ Release 3.0.5 . 2022年5月27日 [2023年3月19日] .
^ 存档副本 . [2021-03-03 ] . (原始内容 存档于2021-03-18).
^ Brandt, Jörgen; Bux, Marc N.; Leser, Ulf. Cuneiform: A functional language for large scale scientific data analysis (PDF) . Proceedings of the Workshops of the EDBT/ICDT. 2015, 1330 : 17–26 [2021-03-03 ] . (原始内容 (PDF) 存档于2020-02-17).
^ Scalable Multi-Language Data Analysis on Beam: The Cuneiform Experience by Jörgen Brandt . Erlang Central. [28 October 2016] . (原始内容 存档于2 October 2016).
^ Bux, Marc; Brandt, Jörgen; Lipka, Carsten; Hakimzadeh, Kamal; Dowling, Jim; Leser, Ulf. SAASFEE: scalable scientific workflow execution engine (PDF) . Proceedings of the VLDB Endowment. 2015, 8 (12): 1892–1895 [2021-03-03 ] . doi:10.14778/2824032.2824094 . (原始内容 (PDF) 存档于2020-11-25).
^ Bessani, Alysson; Brandt, Jörgen; Bux, Marc; Cogo, Vinicius; Dimitrova, Lora; Dowling, Jim; Gholami, Ali; Hakimzadeh, Kamal; Hummel, Michael; Ismail, Mahmoud; Laure, Erwin; Leser, Ulf; Litton, Jan-Eric; Martinez, Roxanna; Niazi, Salman; Reichel, Jane; Zimmermann, Karin. Biobankcloud: a platform for the secure storage, sharing, and processing of large biomedical data sets (PDF) . The First International Workshop on Data Management and Analytics for Medicine and Healthcare (DMAH 2015). 2015 [2021-03-03 ] . (原始内容 (PDF) 存档于2018-10-01).
^ Scalable Multi-Language Data Analysis on Beam: The Cuneiform Experience . Erlang-factory.com. [28 October 2016] . (原始内容 存档于2020-07-12).
^ Kelly, Peter M.; Coddington, Paul D.; Wendelborn, Andrew L. Lambda calculus as a workflow model. Concurrency and Computation: Practice and Experience. 2009, 21 (16): 1999–2017. doi:10.1002/cpe.1448 .
Barseghian, Derik; Altintas, Ilkay; Jones, Matthew B.; Crawl, Daniel; Potter, Nathan; Gallagher, James; Cornillon, Peter; Schildhauer, Mark; Borer, Elizabeth T.; Seabloom, Eric W. Workflows and extensions to the Kepler scientific workflow system to support environmental sensor data access and analysis (PDF) . Ecological Informatics. 2010, 5 (1): 42–50 [2021-03-03 ] . doi:10.1016/j.ecoinf.2009.08.008 . (原始内容 (PDF) 存档于2022-02-25).
^
Di Tommaso, Paolo; Chatzou, Maria; Floden, Evan W; Barja, Pablo Prieto; Palumbo, Emilio; Notredame, Cedric. Nextflow enables reproducible computational workflows. Nature Biotechnology. 2017, 35 (4): 316–319. PMID 28398311 . doi:10.1038/nbt.3820 .
^ A Functional Workflow Language Implementation in Erlang (PDF) . [28 October 2016] . (原始内容 (PDF) 存档于2022-02-25).
^
Brandt, Jörgen; Reisig, Wolfgang; Leser, Ulf. Computation semantics of the functional scientific workflow language Cuneiform. Journal of Functional Programming . 2017, 27 . S2CID 6128299 . doi:10.1017/S0956796817000119 .