지도:
val streamMap = stream.map {x => x * 2}
flatMap
즉, 중첩 된 컬렉션은 중첩되지 않은 컬렉션으로 변환되고 병합됩니다.
예를 들어, 목록이 공백으로 구분 된 데이터를 분리하고 추출하려는 경우 다음을 수행 할 수 있습니다.
List ( "ab", "cd"). flatMap (line => line. split ( ""))의
최종 결과는 다음과 같습니다. List (a, b, c, d
val streamFlatMap = stream.flatMap {
x => x.split ( "")
}
필터
if 필터링, 람다 표현식 제공, bool 유형의 값 반환과 유사하며 최종 결과가 참인지 여부에 따라 현재 결과가 유지되는지 여부를 판단합니다
.val streamFilter = stream.filter {
x => x == 1
}
KeyBy는
먼저 그룹화 한 다음 집계됩니다
.DataStream-> KeyedStream : 스트림을 분리 된 파티션으로 논리적으로 분할합니다. 각 파티션은 동일한 키 요소를 포함하며 내부적으로 해시 형식으로 구현됩니다.
롤링 집계 연산자 (롤링 집계)
이 연산자는 KeyedStream의 각 분기에 대해 집계를 수행 할 수 있습니다.
sum ()
min ()
max ()
minBy ()
maxBy ()
줄이다
분할 및 선택
스플릿
DataStream-> SplitStream : 특정 특성에 따라 DataStram을 둘 이상의 DataStream으로 분할합니다.
고르다
SplitStream-> DataStream : SplitStream에서 하나 이상의 DataStream을 가져옵니다.
요구 사항 : 센서 데이터는 온도 (경계로 30도)에 따라 두 개의 스트림으로 나뉩니다.
연결 및 CoMap
스트림은 병합되지만 두 스트림 만 하나의 스트림으로 병합됩니다. 병합 된 두 스트림은 여전히 독립적이며 서로 영향을주지 않습니다.
DataStream, DataStream-> ConnectedStreams : 유형을 유지하는 두 개의 데이터 스트림을 연결합니다. 두 데이터 스트림이 연결된 후에는 동일한 스트림에만 배치됩니다. 두 데이터 스트림의 내부 데이터 및 형식은 변경되지 않습니다. 스트림은 서로 독립적입니다.
CoMap, CoFlatMap
ConnectedStreams-> DataStream : ConnectedStreams에서 작동하는 기능은 map 및 flatMap과 동일하며 ConnectedStreams의 각 Stream은 각각 map 및 flatMap으로 처리됩니다.
노동 조합
스트림 병합은 두 스트림의 데이터를 하나의 스트림으로 직접 병합하는 것으로 두 스트림의 데이터는 일관성이 있어야하며 그렇지 않으면 사용할 수 없습니다.
주위:
새 패키지 com.mafei.apitest를 만들고 새 scala 개체 클래스 TransformTest를 만듭니다.
package com.mafei.apitest
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, createTypeInformation}
//获取传感器数据
case class SensorReadingTest(id: String,timestamp: Long, temperature: Double)
object TransformTest {
def main(args: Array[String]): Unit = {
//创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
val inputStream= env.readTextFile("/opt/java2020_study/maven/flink1/src/main/resources/sensor.txt")
env.setParallelism(1)
// inputStream.print()
//先转换成样例类类型
val dataStream = inputStream
.map(data =>{
val arr = data.split(",") //按照,分割数据,获取结果
SensorReadingTest(arr(0), arr(1).toLong,arr(2).toDouble) //生成一个传感器类的数据,参数中传toLong和toDouble是因为默认分割后是字符串类别
})
/**
* dataStream.print() 输出样例
1> SensorReadingTest(sensor4,1603766240,40.1)
4> SensorReadingTest(sensor4,1603766284,44.0)
2> SensorReadingTest(sensor1,1603766281,41.0)
3> SensorReadingTest(sensor3,1603766283,43.0)
2> SensorReadingTest(sensor2,1603766282,42.0)
*/
//分组聚合,输出每个传感器当前最小值
val aggStream = dataStream
.keyBy("id") //根据id来进行分组
// .min("temperature") //获取每一组中temperature 为最小的数据
.min("temperature") //获取每一组中temperature 为最小的数据
/**
aggStream.print()
1> SensorReadingTest(sensor1,1603766281,41.0)
2> SensorReadingTest(sensor3,1603766283,43.0)
4> SensorReadingTest(sensor2,1603766282,42.0)
1> SensorReadingTest(sensor4,1603766240,40.1) // 所有sensor的数据只会输出最小的值
1> SensorReadingTest(sensor4,1603766240,40.1) // 所有sensor的数据只会输出最小的值
*/
//需要输出当前最小的温度值,以及最近的时间戳,要用到reduce
val resultStream = dataStream
.keyBy("id")
// .reduce((curState, newData)=>{
// SensorReadingTest(curState.id,newData.timestamp, curState.temperature.min(newData.timestamp))
// })
.reduce( new MyreduceFunction) //如果不用上面的lambda表达式,也可以自己写实现类,一样的效果,二选一
/**
print(resultStream.print())
SensorReadingTest(sensor2,1603766282,42.0)
SensorReadingTest(sensor3,1603766283,43.0)
SensorReadingTest(sensor4,1603766240,40.1)
SensorReadingTest(sensor4,1603766284,40.1) //可以看到虽然sensor4的时间戳还是在更新,但是temperature 一直是最小的一个
SensorReadingTest(sensor4,1603766249,40.1)
*/
// 多流转换操作
//分流,将传感器温度数据分成低温、高温两条流
val splitStream = dataStream
.split(data =>{
if (data.temperature > 30.0 ) Seq("high") else Seq("low")
})
val highStream = splitStream.select("high")
val lowStream = splitStream.select("low")
val allStream = splitStream.select("high", "low")
/**
*
* 数据输出样例: 大于30的都在high里面,小于30都在low
* highStream.print("high")
* lowStream.print("low")
* allStream.print("all")
*
* all> SensorReadingTest(sensor1,1603766281,41.0)
* high> SensorReadingTest(sensor1,1603766281,41.0)
* all> SensorReadingTest(sensor2,1603766282,42.0)
* high> SensorReadingTest(sensor2,1603766282,42.0)
* all> SensorReadingTest(sensor4,1603766284,20.0)
* low> SensorReadingTest(sensor4,1603766284,20.0)
* all> SensorReadingTest(sensor4,1603766249,40.2)
* high> SensorReadingTest(sensor4,1603766249,40.2)
* all> SensorReadingTest(sensor3,1603766283,43.0)
* high> SensorReadingTest(sensor3,1603766283,43.0)
* all> SensorReadingTest(sensor4,1603766240,40.1)
* high> SensorReadingTest(sensor4,1603766240,40.1)
*/
//合流,connect
val warningStream = highStream.map(data =>(data.id, data.temperature))
val connectedStreams = warningStream.connect(lowStream)
//用coMap对数据进行分别处理
val coMapResultStream = connectedStreams
.map(
warningData =>(warningData._1,warningData._2,"warning"),
lowTempData => (lowTempData.id, "healthy")
)
/**
* coMapResultStream.print()
*
* (sensor1,41.0,warning)
* (sensor4,healthy)
* (sensor2,42.0,warning)
* (sensor4,40.2,warning)
* (sensor3,43.0,warning)
* (sensor4,40.1,warning)
*/
env.execute("stream test")
}
}
class MyreduceFunction extends ReduceFunction[SensorReadingTest]{
override def reduce(t: SensorReadingTest, t1: SensorReadingTest): SensorReadingTest =
SensorReadingTest(t.id, t1.timestamp, t.temperature.min(t1.temperature))
}
사용 된 데이터 sensor.txt
센서
1,1603766281,41
센서
2,1603766282,42
센서
3,1603766283,43 센서 4,1603766240,40.1 센서 4,1603766284,44 센서 4,1603766249,40.2
최종 코드 구조 :