Esper는 이벤트 시점을 기준으로 출력 결과를 발생시킨다. 이벤트가 들어오거나 타임 윈도우에서 이벤트가 벗어나거나 할 때 관련된 이벤트 처리 결과를 리스너에 전달한다. 예를 들어, 아래 EPL을 생각해보자.
select avg(cost) from StockEvent
위 EPL을 실행하면 StockEvent가 발생할 때 마다 cost의 평균값을 리스너를 통해 받게 된다. 그런데, 단순히 평균의 추이를 알고 싶은 거라면 모든 이벤트마다 평균값을 받는 것 보다 10초, 1분과 같이 주기적으로 그 시점의 평균값을 확인해도 문제가 없을 것이다. 이렇게 출력 자체를 제어하고 싶을 때 output 절을 사용할 수 있다.
관련 시리즈:
- Esper 초보 시리즈 1 - 퀵스타트
- Esper 초보 시리즈 2 - EPL 기초
- Esper 초보 시리즈 4 - Insert into, 조인, 서브쿼리
- Esper 초보 시리즈 5 - 패턴
- Esper 초보 시리즈 6 - 컨텍스트
output 을 이용한 출력 시점 제어
output은 출력 시점을 제어하기 위해 사용된다. 예를 들어, 10초 마다 출력을 받고 싶다거나, 이벤트 5개 당 첫 번째에 대해 결과를 받고 싶다거나 할 때 output을 사용한다.
output의 기본 사용 방법은 다음과 같다.
select ... from ...
output [all | first | last | snapshot ] every N [seconds | events]
every N에서 N은 숫자이며, seconds는 초를 events는 이벤트 개수를 뜻한다. 즉, "every 10 seconds"는 매 10초마 결과를 리스너에 전달하게 된다.
output 뒤에 all, first, last, snapshot는 다음의 의미를 갖는다.
- all: 출력 주기에 발생한 모든 이벤트 출력
- first: 출력 주기에 발생한 첫 번째 이벤트 기준 출력
- last: 출력 주기에 발생한 마지막 이벤트 기준 출력
- snapshot: 현재 시점의 출력 결과. 윈도우와 함께 사용되지 않을 경우 last와 같은 결과 출력.
예를 들어, 아래 목록에 첫 번째 EPL은 매 2초 간격으로 출력을 발생시키는데, 출력 주기(2초) 범위에 발생한 모든 이벤트에 대한 출력을 발생시킨다.
- select avg(cost) as avg from StockTick output all every 2 seconds
- select avg(cost) as avg from StockTick output first every 2 seconds
- select avg(cost) as avg from StockTick output last every 2 seconds
- select avg(cost) as avg from StockTick output snapshot every 2 seconds
위 EPL에 대해 실제 리스너에 전달된 출력 결과를 시간대 별로 출력해보면 아래 그림과 같다.
위 그림에서 상위 두 개는 code1 및 code2 이벤트의 발생 시점이다. 그리고, 회색 화살표는 2초 간격을 표시한 것이다. 녹색 삼각형으로 표시된 output all의 경우, 매 2초 간격마다 발생한 모든 이벤트 처리 결과가 리스너에 전달되는 것을 알 수 있다.
위 그림에서 회색 X 표시가 output first에 의해 발생한 이벤트 발생 시점을 표시한 부분이다. output first의 경우는 약간 특이하게 동작한다. output first의 경우 현재 주기에서 발생한 이벤트가 없으면, 다음 주기가 시작할 때 현재 시점 기준으로 마지막 결과를 리스너에 전달하고, 그 다음 주기에서 새로운 이벤트가 발생하면 그 시점의 결과를 리스너에 다시 전달한다.
group by와 output
group by와 output이 만나면 약간 다른 방식으로 동작한다. group by와 output이 만나면 다음과 같은 방식으로 동작한다.
- first: 그룹 별 출력 주기에 발생한 첫 번째 이벤트를 기준으로 출력 결과 생성. 그룹 별 첫 번째 이벤트 발생 시점에 출력 생성. 출력 주기에 이벤트가 없으면 출력 결과를 생성하지 않음.
- last: 그룹 별 출력 주기에 발생한 마지막 이벤트를 기준으로 출력 결과 생성. 출력 주기 종료 시점에 마지막 출력 결과 생성. 출력 주기에 이벤트가 없으면 출력 결과를 생성하지 않음.
- all: 출력 주기 종료 시점에 마지막 출력 결과 생성. 출력 주기에 이벤트가 없어도 출력 결과 생성.
- 키워드 없음: 출력 주기에 발생한 모든 출력 결과 생성. 출력 주기 종료 시점에 출력 결과 생성. 출력 주기에 이벤트가 없으면 출력 결과를 생성하지 않음.
아래 쿼리는 작성 예이다.
- select code, avg(cost) as avg from StockTick group by code output first every 2 sec
- select code, avg(cost) as avg from StockTick group by code output last every 2 sec
- select code, avg(cost) as avg from StockTick group by code output all every 2 sec
- select code, avg(cost) as avg from StockTick group by code output every 2 sec
위 쿼리를 실행해 보면 이벤트 발생 시점에 따라 아래와 같이 출력 결과가 발생한다.
윈도우와 snapshot의 동작 방식
윈도우와 output snapshot을 함께 사용하면 윈도우를 기준으로 마지막 값이 출력된다. 아래 그림은 다음의 세 쿼리를 실행한 결과를 정리한 것이다.
- select avg(cost) as avg from StockTick.win:time_batch(3 sec) output snapshot every 1.5 sec
- select avg(cost) as avg from StockTick.win:time_batch(3 sec)
- select avg(cost) as avg from StockTick.win:time(3 sec) output snapshot every 1.5 sec
출력 주기를 1.5초로 지정했는데, 그 출력 결과를 보면 시간 배치 윈도우와 시간 윈도우에서 output snapshot이 다르게 동작하는 것을 확인할 수 있다. 시간 배치 윈도우와 output snapshot을 함께 사용한 결과를 보면 세 번째 출력 결과가 5000인데, 그 이유는 다음과 같다.
- 시간 배치 윈도우에 적용된 output snapshot의 세 번째 출력 결과 시점은 약 8.5초
- 시간 배치 윈도우의 처리 구간은 7초~9초
- 따라서, 아직 현재 시간 배치 윈도우의 결과가 없으므로, 이전 배치의 결과인 5000을 값으로 출력
추가 내용
출력 주기를 크론탭을 이용해서 표현 가능하다. 다음은 매 15분 주기로 결과를 출력하는 예이다.
- select avg(cost) as avg from StockTick.win:time_batch(30 minutes) output snapshot at(*/15, *, *, *, *)
after를 사용해서 최초 일정 시간 동안 결과를 출력하지 않도록 지정할 수 있다.
- select avg(cost) as avg from StockTick output after 4 sec last every 1.5 sec