Oozie是一个基于工作流引擎的开源框架,依赖于MapReduce来实现,是一个管理 Apache Hadoop 作业的工作流调度系统。是由Cloudera公司贡献给Apache的,它能够提供对Hadoop MapReduce和Pig Jobs的任务调度与协调。Oozie需要部署到Java Servlet容器中运行。
官网:https://oozie.apache.org/
官方文档:https://oozie.apache.org/docs/5.2.1/index.html
安装包下载地址:https://dlcdn.apache.org/oozie/5.2.1/
github源码地址:https://github.com/apache/oozie.git
Oozie的特点:
hPDL定义(一种XML流程定义语言);

Oozie三层结构:
Workflow:工作流,由我们需要处理的每个工作组成,进行需求的流式处理,是对要进行的顺序化工作的抽象。
start,end,kill等。以及提供工作流的执行路径机制,如decision, fork, join等。hive、shell、sqoop、pig、mr等等。流程图如下:

Coordinator:协调器,可以理解为工作流的协调器,可以将多个工作流协调成一个工作流来进行处理,是对要进行的顺序化的workflow的抽象,定时触发一个workflow。流程图如下:
Bundle:捆,束。将一堆的coordinator进行汇总处理,是对一堆coordiantor的抽象,用来绑定多个coordinator或者多个workflow,流程图如下:
一般Oozie是集成到CDH上使用的,所以这里部署就通过CM去部署了,没有部署CDH的小伙伴,可以参考我之前的文章:大数据Hadoop之——Cloudera Hadoop(CM 6.3.1+CDH 6.3.2环境部署)




还在是在大数据Hadoop之——Cloudera Hadoop(CM 6.3.1+CDH 6.3.2环境部署)这篇文章初始化的配置。


默认就行,当然可以自行修改



到这里Oozie服务就安装完成了。
由于oozie的xml配置执行各种任务调度是在太过于繁琐,所有一般都使用hue整合oozie来使用。
修改配置

重启Hue服务

重新登录Hue web

发现多了计划程序,这就是Oozie的计划程序

1、创建workflow


2、查看workflow

3、配置调用任务
这里选择shell脚本,很多选择




保存

4、立即执行


发现报错了
WARN org.apache.oozie.command.wf.ActionStartXCommand: SERVER[hadoop-cdhslave02-168-182-163] USER[admin] GROUP[-] TOKEN[] APP[myworkflow001] JOB[0000003-220423133048789-oozie-oozi-W] ACTION[0000003-220423133048789-oozie-oozi-W@shell-52b4] Error starting action [shell-52b4]. ErrorType [TRANSIENT], ErrorCode [JA009], Message [JA009: Invalid resource request! Cannot allocate containers as requested resource is greater than maximum allowed allocation. Requested resource type=[memory-mb], Requested resource=<memory:2048, vCores:1>, maximum allowed allocation=<memory:1024, vCores:4>, please note that maximum allowed allocation is calculated by scheduler based on maximum resource of registered NodeManagers, which might be less than configured maximum allocation=<memory:1024, vCores:4>
原因是 yarn配置的最大容器申请资源是1024M,oozie配置的启动资源要2048M,在CM中修改oozie的相关配置。

重启服务后重新执行

再去看Yarn任务

其实这里只是加了一个任务,其实可以加很多任务,接下来就可自行扩展了
sql文件
create database test001;
CREATE TABLE IF NOT EXISTS test001.person_1 (
id INT COMMENT 'ID',
name STRING COMMENT '名字',
age INT COMMENT '年龄',
likes ARRAY<STRING> COMMENT '爱好',
address MAP<STRING,STRING> COMMENT '地址'
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':'
LINES TERMINATED BY '\n';

跟前面的步骤一样,只是调度的任务不同和脚本不同而已,这里就不再过多截图介绍了。

通过beeline连接hive检查
$ beeline -u jdbc:hive2://hadoop-cdhmaster-168-182-161:10000 -n root
show databases;
show tables from test001;

当然也对应有个yarn任务


选择workflow


【温馨提示】一定要注意时区的问题,否则调度就出错了。保存之后就可以提交定时任务。
提交Schedule



Oozie 提供了一个命令行实用程序oozie来执行作业和管理任务。所有操作都是通过oozie CLI 的子命令完成的。
一个Oozie 的 job 一般由以下文件组成:
job.properties :记录了job的属性workflow.xml :使用hPDL 定义任务的流程和分支脚本文件/lib目录:用来执行具体的任务的文件job.properties
| key | 含义 |
|---|---|
| nameNode | HDFS地址 |
| jobTracker | jobTracker(ResourceManager)地址 |
| queueName | Oozie队列(默认填写default) |
| examplesRoot | 全局目录(默认填写examples) |
| oozie.usr.system.libpath | 是否加载用户lib目录(true/false) |
| oozie.libpath | 用户lib库所在的位置 |
| oozie.wf.application.path | Oozie流程所在hdfs地址(workflow.xml所在的地址) |
| user.name | 当前用户 |
| oozie.coord.application.path | Coordinator.xml地址(没有可以不写) |
| oozie.bundle.application.path | Bundle.xml地址(没有可以不写) |
【温馨提示】这个文件如果是在本地通过命令行进行任务提交的话,这个文件在本地就可以了,当然也可以放在hdfs上,与workflow.xml和lib处于同一层级。
nameNode,jobTracker和oozie.wf.application.path在hdfs中的位置必须设置。
oozie官方提供的oozie-examples.tar.gz
这个包里也有:https://dlcdn.apache.org/oozie/5.2.1/oozie-5.2.1.tar.gz
$ tar -xf oozie-examples.tar.gz
$ cd examples/apps/
$ ll
很多示例,这里只演示几个,其余的小伙伴可以自行练习一下

进入到shell的示例目录,发现有两个配置文件job.properties,workflow.xml
$ cd shell
修改job.properties
# 配置hdfs,地址记得改成自己环境的
nameNode=hdfs://hadoop-cdhslave01-168-182-162:8020
# 配置yarn,8088是web端口,8032是yarn的服务端口号
resourceManager=hadoop-cdhslave01-168-182-162:8032
queueName=default
examplesRoot=examples
# HDFS脚本文件存放目录
oozie.wf.application.path=${nameNode}/user/${user.name}/workflow/shell
# 定义脚本变量,也可以直接写脚本名字
shellScript=helloworld.sh
修改workflow.xml
默认是echo输出,这里修改成执行脚本
<workflow-app xmlns="uri:oozie:workflow:1.0" name="shell-wf">
<start to="shell-node"/>
<action name="shell-node">
<shell xmlns="uri:oozie:shell-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${shellScript}</exec>
<file>/user/oozie/workflow/shell/${shellScript}#${shellScript}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<kill name="fail-output">
<message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
</kill>
<end name="end"/>
</workflow-app>
脚本:helloworld.sh
#!/bin/bash
echo `date` " hello world" >> /tmp/helloworld.log
可以在job.properties定义一个变量,在workflow.xml中使用变量
把三个文件都上传到/user/oozie/workflow/shell/目录下
$ sudo -u oozie hadoop fs -mkdir -p /user/oozie/workflow/shell/
$ sudo -u oozie hadoop fs -put * /user/oozie/workflow/shell/

立即执行任务
$ sudo -u oozie /usr/bin/oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/ -config job.properties -run

Oozie web UI查看,登录web时,发现有问题

Oozie web console is disabled.
To enable Oozie web console install the Ext JS library.
Refer to Oozie Quick Start documentation for details.
【Oozie web console is disabled 问题解决】
$ find /opt/ -name libext
$ cd /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/lib/oozie/libext
$ wget http://archive.cloudera.com/gplextras/misc/ext-2.2.zip
$ sudo unzip ext-2.2.zip
$ sudo chown oozie:oozie -R ext-2.2
执行成功了

再去看一下yarn任务

$ cd /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/share/doc/oozie-5.1.0+cdh6.3.2/examples/apps
# copy一份shell文件
$ cp -r shell shell02
$ cd shell02
新建一个shell脚本,test02.sh
#!/bin/bash
echo "test mutil workflow" >> /tmp/test02.log
修改job.properties
# 配置hdfs,地址记得改成自己环境的
nameNode=hdfs://hadoop-cdhslave01-168-182-162:8020
# 配置yarn,8088是web端口,8032是yarn的服务端口号
resourceManager=hadoop-cdhslave01-168-182-162:8032
queueName=default
examplesRoot=examples
# HDFS脚本文件存放目录
oozie.wf.application.path=${nameNode}/user/${user.name}/workflow/shell
# 定义脚本变量,也可以直接写脚本名字
shellScript=helloworld.sh
# 新增一个脚本变量
shellScript02=test02.sh
修改workflow.xml,新增一个action
<workflow-app xmlns="uri:oozie:workflow:1.0" name="shell-wf">
<start to="shell-node01"/>
<action name="shell-node01">
<shell xmlns="uri:oozie:shell-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${shellScript}</exec>
<file>/user/oozie/workflow/shell/${shellScript}#${shellScript}</file>
<capture-output/>
</shell>
<ok to="shell-node02"/>
<error to="fail"/>
</action>
<action name="shell-node02">
<shell xmlns="uri:oozie:shell-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${shellScript02}</exec>
<file>/user/oozie/workflow/shell/${shellScript02}#${shellScript02}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<kill name="fail-output">
<message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
</kill>
<end name="end"/>
</workflow-app>
强制覆盖
$ sudo -u oozie hadoop fs -put -f * /user/oozie/workflow/shell/
执行任务
$ sudo -u oozie /usr/bin/oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/ -config job.properties -run


直接使用官方模板修改(wordcount示例)
$ cd /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/share/doc/oozie-5.1.0+cdh6.3.2/examples/apps/map-reduce
$ ll
$ tree lib/

先用传统方式验证一把
$ cat>./wordcount.txt<< EOF
hello oozie
hello hadoop
hadoo oozie
hello world
hello bigdata
bigdata hadoop
hello flink
EOF
$ sudo -u hdfs hadoop fs -put wordcount.txt /
# 找到hadoop-mapreduce-examples*.jar包
$ find /opt/ -name hadoop-mapreduce-examples*.jar
$ sudo -u hdfs yarn jar /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/jars/hadoop-mapreduce-examples-3.0.0-cdh6.3.2.jar wordcount /wordcount.txt /out

配置workflow.xml
先在上面的跑的任务中查找map类和reduce


map类

reduce类

修改后的workflow.xml内容如下:
<workflow-app xmlns="uri:oozie:workflow:1.0" name="map-reduce-wf">
<start to="mr-node"/>
<action name="mr-node">
<map-reduce>
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<prepare>
<delete path="${nameNode}/user/oozie/workflow/map-reduce/output/"/>
</prepare>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
<!-- 配置MR调度任务时,设置使用新的API-->
<property>
<name>mapred.mapper.new-api</name>
<value>true</value>
</property>
<property>
<name>mapred.reducer.new-api</name>
<value>true</value>
</property>
<!-- 指定job key输出类型 -->
<property>
<name>mapreduce.job.output.key.class</name>
<value>org.apache.hadoop.io.Text</value>
</property>
<!-- 指定job value输出类型 -->
<property>
<name>mapreduce.job.output.value.class</name>
<value>org.apache.hadoop.io.IntWritable</value>
</property>
<!-- 指定输入路径 -->
<property>
<name>mapred.input.dir</name>
<value>/user/oozie/workflow/map-reduce/wordcount.txt</value>
</property>
<!-- 指定输出路径 -->
<property>
<name>mapred.output.dir</name>
<value>/user/oozie/workflow/map-reduce/output/</value>
</property>
<!-- 指定map类 -->
<property>
<name>mapreduce.job.map.class</name>
<value>org.apache.hadoop.examples.WordCount$TokenizerMapper</value>
</property>
<!-- 指定reduce类 -->
<property>
<name>mapreduce.job.reduce.class</name>
<value>org.apache.hadoop.examples.WordCount$IntSumReducer</value>
</property>
<property>
<name>mapred.map.tasks</name>
<value>1</value>
</property>
</configuration>
</map-reduce>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Map/Reduce failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>
修改job.properties,内容如下:
# 配置hdfs,地址记得改成自己环境的
nameNode=hdfs://hadoop-cdhslave01-168-182-162:8020
# 配置yarn,8088是web端口,8032是yarn的服务端口号
resourceManager=hadoop-cdhslave01-168-182-162:8032
queueName=default
examplesRoot=examples
oozie.wf.application.path=${nameNode}/user/${user.name}/workflow/map-reduce/workflow.xml
# 定义脚本变量,也可以直接写脚本名字
outputDir=map-reduce
换掉lib下面的jar包,使用新API
$ cd /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/share/doc/oozie-5.1.0+cdh6.3.2/examples/apps
$ cp /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/jars/hadoop-mapreduce-examples-3.0.0-cdh6.3.2.jar map-reduce/lib/
$ rm -f map-reduce/lib/oozie-examples-5.1.0-cdh6.3.2.jar
把map-reduce目录推到HDFS上
$ sudo -u oozie hadoop fs -put -f map-reduce /user/oozie/workflow/

执行任务
$ sudo -u oozie /usr/bin/oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/ -config map-reduce/job.properties -run
登录Oozie web UI:http://hadoop-cdhslave02-168-182-163:11000/oozie/

登录yarn web查看任务

$ cd /opt/cloudera/parcels/CDH-6.3.2-1.cdh6.3.2.p0.1605554/share/doc/oozie-5.1.0+cdh6.3.2/examples/apps
$ cd cron
修改job.properties,内容如下:
nameNode=hdfs://hadoop-cdhslave01-168-182-162:8020
resourceManager=hadoop-cdhslave01-168-182-162:8032
queueName=default
examplesRoot=examples
oozie.coord.application.path=${nameNode}/user/${user.name}/workflow/cron
# start必须设置未来时间,否则任务会失败
start=2022-04-27T23:30Z
end=2022-04-29T01:00Z
workflowAppUri=${nameNode}/user/${user.name}/workflow/cron
shellScript=test001.sh
修改workflow.xml,其实也是上面第一个示例
<workflow-app xmlns="uri:oozie:workflow:1.0" name="shell-wf">
<start to="shell-node"/>
<action name="shell-node">
<shell xmlns="uri:oozie:shell-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${shellScript}</exec>
<file>/user/oozie/workflow/cron/${shellScript}#${shellScript}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<kill name="fail-output">
<message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
</kill>
<end name="end"/>
</workflow-app>
修改coordinator.xml,内容如下:
frequency频率最低五分钟,时区调整为中国时区
<coordinator-app name="cron-coord" frequency="${coord:minutes(5)}" start="${start}" end="${end}" timezone="GMT+0800"
xmlns="uri:oozie:coordinator:0.2">
<action>
<workflow>
<app-path>${workflowAppUri}</app-path>
<configuration>
<property>
<name>resourceManager</name>
<value>${resourceManager}</value>
</property>
<property>
<name>nameNode</name>
<value>${nameNode}</value>
</property>
<property>
<name>queueName</name>
<value>${queueName}</value>
</property>
</configuration>
</workflow>
</action>
</coordinator-app>
把cron整个目录推送到HDFS
$ cd ..
$ sudo -u oozie hadoop fs -put cron /user/oozie/workflow/
执行
$ sudo -u oozie /usr/bin/oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/ -config cron/job.properties -run
1、编辑好shell脚本和workflow.xml文件
$ mkdir -p /opt/test/oozie/workflow/shell
$ vi /opt/test/oozie/workflow/shell/ooziehello.sh
#!/bin/bash
name=$1
echo "hello $name" >> /tmp/oozieshell.log
$ vi /opt/test/oozie/workflow/shell/workflow.xml
<workflow-app xmlns="uri:oozie:workflow:1.0" name="shell-wf">
<start to="shell-node"/>
<action name="shell-node">
<shell xmlns="uri:oozie:shell-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>${shellScript}</exec>
<file>/user/oozie/workflow/oozieshell/${shellScript}#${shellScript}</file>
<capture-output/>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<kill name="fail-output">
<message>Incorrect output, expected [Hello Oozie] but was [${wf:actionData('shell-node')['my_output']}]</message>
</kill>
<end name="end"/>
</workflow-app>
3、把上面两个文件上传到HDFS
$ sudo -u oozie hadoop fs -mkdir /user/oozie/workflow/oozieshell/
$ sudo -u oozie hadoop fs -put * /user/oozie/workflow/oozieshell/
4、代码执行提交任务
package com.bigdata;
/**
* workflow shell test
*/
import org.apache.oozie.client.OozieClient;
import org.apache.oozie.client.WorkflowAction;
import org.apache.oozie.client.WorkflowJob;
import java.util.List;
import java.util.Properties;
public class WorkFlowShellTest {
public static void main(String[] args) {
System.setProperty("user.name", "oozie");
OozieClient oozieClient = new OozieClient("http://hadoop-cdhslave02-168-182-163:11000/oozie/");
try {
System.out.println(oozieClient.getServerBuildVersion());
Properties properties = oozieClient.createConfiguration();
properties.put("oozie.wf.application.path", "${nameNode}/user/${user.name}/workflow/oozieshell");
properties.put("queueName", "default");
properties.put("nameNode", "hdfs://hadoop-cdhslave01-168-182-162:8020");
properties.put("resourceManager", "hadoop-cdhslave01-168-182-162:8032");
properties.put("shellScript", "ooziehello.sh");
properties.put("argument", "oozie");
//运行workflow
String jobid = oozieClient.run(properties);
System.out.println("jobid:" + jobid);
//根据workflow id获取作业运行情况
WorkflowJob workflowJob = oozieClient.getJobInfo(jobid);
//获取作业日志
System.out.println(oozieClient.getJobLog(jobid));
//获取workflow中所有ACTION
List<WorkflowAction> list = workflowJob.getActions();
for (WorkflowAction action : list) {
//输出每个Action的 Appid 即Yarn的Application ID
System.out.println(action.getExternalId());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}


其它的示例也类似,就是把之前的job.properties,用java格式加载,运行,查询,其它都一样。所以其它示例就由小伙伴自行练习了。
# 启动
$ oozied.sh start
# 停止
$ oozied.sh stop
# 提交任务并启动任务(submit和start命令合并)
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie -config job.properties –run
# 提交任务不启动
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie -config job.properties –submit
# 启动任务
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie -start 0001837-220423150913947-oozie-oozi-W
### workflow任务
# 查看所有workflow任务
$ oozie jobs
# 查看信息
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie -info 0001837-220423150913947-oozie-oozi-W
# 查看日志
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie -log 0001837-220423150913947-oozie-oozi-W
# Kill任务
$ oozie job -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/ -kill 0001831-220423150913947-oozie-oozi-W
# 或者下面这句
$ oozie job -kill 0001831-220423150913947-oozie-oozi-W
### coordinator 定时任务
# 查看定时任务
$ oozie jobs -jobtype coordinator -oozie http://hadoop-cdhslave02-168-182-163:11000/oozie/
$ oozie jobs -jobtype coordinator
# 删除定时任务
$ oozie job -kill 0000345-220423150913947-oozie-oozi-C
| 对比指标 | Azkaban | Oozie |
|---|---|---|
| 功能 | Azkaban与Oozie均可以调度mapreduce、pig、java脚本工作流任务;Azkaban与Oozie均可以定时执行工作流任务。 | 与Azkaban 一样 |
| 工作流传参 | Azkaban支持直接传参,例如${input}。 | Oozie支持参数和EL表达式,例如${fs:dirSize(myInputDir)}。 |
| 定时执行 | Azkaban的定时执行任务是基于时间的。 | Oozie的定时执行任务是基于时间和输入数据资源管理。 |
| 工作流执行 | Azkaban有两种运行模式,分别是solo server mode(executor server和web server部署在同⼀台节点)和multi server mode(executor server和web server可以部署在不同节点)。 | Oozie作为工作流服务运行,支持多用户和多工作流。 |
综上所述,Oozie相比Azkaban是一个重量级的任务调度系统,功能全面,但配置使用也更复杂(xml)。如果可以不在意某些功能的缺失,轻量级调度Azkaban是很不错的候选对象。所以如果不是用CDH,还是使用Azkaban方便简单~
关于Azkaban,可以参考我之前的文章:
大数据Hadoop之——任务调度器Azkaban(Azkaban环境部署)
大数据Hadoop之——Azkaban API详解
关于Oozie的概述和简单使用就到这结束了,如果小伙伴有疑问,欢迎给我留言,未完待续,请耐心等待~
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co
我正在尝试在Rails上安装ruby,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,