什么是流
Stream在Java中的定义
A sequence of elements supporting sequential and parallel aggregate operations.
语翻译过来就是:支持数据处理操作的一个source 中的元素序列
- Sequence of elements(元素序列):简单来说,就是我们操作的集合中的所有元素
- source(数据源) :Stream流的作用就是操作数据,那么source 就是为Stream提供可操作的源数据(一般,集合、数组或I/OI/O resources 都可以成为Stream的source )
- Data processing operations(数据处理操作):上面菜单程序代码中出现的filter、sorted、map、collect,以及我们后来会用到的reduce、find、match`等都属于Stream 的一些操作数据的方法接口。这些操作可以顺序进行,也可以并行执行。
- Pipelining(管道、流水线):Stream对数据的操作类似数据库查询,也像电子厂的生产流线一样,Stream的每一个中间操作(后面解释什么是中间操作)比如上面的filter、sorted、map,每一步都会返回一个新的流,这些操作全部连起来就是想是一个工厂得生产流水线, like this:
- Internal iteration(内部迭代):Stream API 实现了对数据迭代的封装,不用你再像操作集合一样,手动写for循环显示迭代数据。
为什么用Stream
在《java8 in action》书中,作者说目前我们在几乎所有开发中都会用到集合,但是目前集合在程序开发中的表现还不够完美,比如你利用集合处理大量数据时,你不得不面对性能问题,不得不考虑进行并行代码的编写,这些工作都是比较繁重的,于是作者便创造了Stream流。
Stream 三大部分
创建Stream实例
通过集合、数组等都可以创建Stream流实例
中间操作
可以连接起来的Stream流操作,诸如filter或sorted等可以返回一个Stream 流的操作,就叫中间操作。只有存在一个终端操作,且触发了终端操作,中间操作才会开始执行。
终端操作
可以启动中间操作和关闭中间流的操作称为终端操作,终端操作会从流的流水线(中间操作)生成结果。其结果是任何非Stream的值,比如可能是List、Integer,甚至void。
ekuiper的Stream
ekuiper的基础,所有ekuiper的应用和配置都是围绕着stream来运行的。
在 eKuiper 中,每个列或表达式都有一个相关的数据类型。 数据类型描述(约束)该类型的列可以容纳的一组值或该类型可以产生的表达式。
数据类型
以下是支持的数据类型的列表。
语义定义
CREATE STREAM
stream_name
( column_name <data_type> [ ,...n ] )
WITH ( property_name = expression [, ...] );
属性名称
demo:
my_stream
(id bigint, name string, score float)
WITH ( datasource = "topic/temperature", FORMAT = "json", KEY = "id");
该流将订阅 MQTT 主题topic/temperature,服务器连接使用配置文件$ekuiper/etc/mqtt_source.yaml 中默认部分的 servers 键。
demo:
demo (
USERID BIGINT,
FIRST_NAME STRING,
LAST_NAME STRING,
NICKNAMES ARRAY(STRING),
Gender BOOLEAN,
ADDRESS STRUCT(STREET_NAME STRING, NUMBER BIGINT),
) WITH (DATASOURCE="test/", FORMAT="JSON", KEY="USERID", CONF_KEY="demo");
流将订阅 MQTT 主题 test/,服务器连接使用配置文件$ekuiper/etc/mqtt_source.yaml 中 demo 部分的设置。
ekuiper/etc/mqtt_source.yaml
#Global MQTT configurations
default:
qos: 1
servers: [tcp://127.0.0.1:1883]
#username: user1
#password: password
#certificationPath: /var/kuiper/xyz-certificate.pem
#privateKeyPath: /var/kuiper/xyz-private.pem.key
#kubeedgeVersion:
#kubeedgeModelFile: ""
demo_conf: #Conf_key
qos: 0
servers: [tcp://10.211.55.6:1883, tcp://127.0.0.1]
属性名称
SHARED:共享源实例
默认情况下,每个规则会创建自己的源实例。在某些场景中,用户需要不同的规则处理完全相同的数据流。例如,在处理传感器的温度数据时,用户可能需要一个规则,当一段时间的平均温度大于30度时触发警告;而另一个规则则是当一段时间的平均温度小于0度时触发警告。使用默认配置时,两个规则各自独立实例化源实例。由于网络延迟等原因,规则可能得到不同顺序,甚至各有缺失数据的数据流,从而在不同的数据维度中计算平均值。通过配置共享源实例,用户可以确保两个规则处理完全相同的数据。同时,由于节省了额外的源实例开销,规则的性能也能得到提升。
使用共享源实例模式,只需要共享源实例的流时,将其 SHARED 属性设置为 true 。
demo (
...
) WITH (DATASOURCE="test", FORMAT="JSON", KEY="USERID", SHARED="true");
StrictValidation
StrictValidation 的值可以为 true 或 false。
1)True:如果消息不符合流定义,则删除消息。
2)False:保留消息,但用默认的空值填充缺少的字段。
bigint: 0
float: 0.0
string: “”
datetime: (NOT support yet)
boolean: false
array: zero length array
struct: null value
Schema-less 流
如果流的数据类型未知或不同,我们可以不使用字段来定义它。 这称为 schema-less。 通过将字段设置为空来定义它。
schemaless_stream
()
WITH ( datasource = "topic/temperature", FORMAT = "json", KEY = "id");
二进制流
对于二进制数据流,例如图像或者视频流,需要指定数据格式为 “BINARY” 。二进制流的数据为一个二进制数据块,不区分字段。
所以,其流定义必须仅有一个 bytea 类型字段。如下流定义示例中,二进制流的数据将会解析为 demoBin 流中的 image 字段。
demoBin (
image BYTEA
) WITH (DATASOURCE="test/", FORMAT="BINARY");
如果 “BINARY” 格式流定义为 schemaless,数据将会解析到默认的名为 self 的字段。
流管理(使用)
eKuiper 流命令行工具可用于管理流,例如创建、描述、显示和删除流定义。
创建流
create stream $stream_name '$stream_def' | create stream -f $stream_def_file
在命令行中指定流定义
示例:
# bin/kuiper create stream my_stream '(id bigint, name string, score float) WITH ( datasource = "topic/temperature", FORMAT = "json", KEY = "id")'
stream my_stream created
在文件中指定流定义。 如果流很复杂,或者流已经通过明确的格式写在文本文件中,则只需通过 -f 选项规定流定义
以下为调试信息
- 创建Stream
# ./kuiper create stream -f StreamDemo.txt
Connecting to 127.0.0.1:20498...
Creating a new stream from file StreamDemo.txt.
Stream StreamDemo is created.
以下是StreamDemo.txt的内容
StreamDemo(id bigint, name string, score float)
WITH ( datasource = "topic/temperature", FORMAT = "json", KEY = "id");
Stream name为: StreamDemo;
Column name 分别为:id,name,score
data type 分别为:bigint,string,float
数据源为MQTT的topic-“topic/temperature” ,json格式
- 查询接收数据
#./kuiper query
Connecting to 127.0.0.1:20498...
kuiper >
在此状态下可以输入SQL语句,完成查询
#kuiper > SELECT id ,name ,score FROM StreamDemo
Query was submit successfully.
实时接收StreamDemo流的数据,数据内容为id,name,source
- 模拟MQTT Client 发送topic数据
mosquitto_pub -h localhost -t "topic/temperature" -m "{\"id\":2,\"name\" :\"david\",\"score\":1.3}"
mosquitto_pub -h localhost -t "topic/temperature" -m "{\"id\":3,\"name\" :\"david\",\"score\":1.3}"
topic 为 “topic/temperature”
MQTT数据为Json :"{“id”:2,“name” :“david”,“score”:1.3}"
实际接收数据如下
# ./kuiper query
Connecting to 127.0.0.1:20498...
kuiper > SELECT id ,name ,score FROM StreamDemo
Query was submit successfully.
kuiper > [{"id":2,"name":"david","score":1.3}]
[{"id":3,"name":"david","score":1.3}]