LabHub
学习 学习路径 课程

Apache Flink — 스트림을 엔진으로 돌린다 · 패턴 인식 (MATCH_RECOGNIZE) · 讲解

MATCH_RECOGNIZE — 행 여러 개에 걸친 패턴을 SQL 로 찾는다

在 LabHub 中继续学习

한 줄 요약

MATCH_RECOGNIZE 는 키별로 이벤트 시간 순서대로 줄 세운 행들에 정규식 같은 패턴을 대어 보고, 맞은 구간마다 요약 행 하나를 내는 절이다. 무엇이 한 매치가 되는지는 패턴 자체보다 수량자의 탐욕 여부, AFTER MATCH SKIP 전략, WITHIN 시간 제한이 정한다.

概念图: 이벤트 시간 순서대로 줄 세운 행들 · 수량자의 탐욕 여부 · AFTER MATCH SKIP 전략 · WITHIN 시간 제한

왜 이게 필요했나

"같은 사용자가 로그인에 세 번 넘게 연달아 실패한 뒤 성공했다" 를 찾는다고 해 보자. GROUP BY 로는 실패 횟수는 세도 "연달아" 와 "그 뒤에 바로" 를 표현할 수 없다. 창 집계는 시간 칸을 잘라 버려서 칸 경계에 걸친 시도를 놓친다. 자기 조인을 여러 번 걸면 표현은 되지만, 스트림에서는 양쪽을 영원히 기억해야 하고(5모듈) 쿼리도 읽을 수 없게 된다.

필요한 것은 "행의 순서에 대한 조건" 이다. Flink 는 복합 이벤트 처리(CEP) 라이브러리를 이미 가지고 있었고, SQL 표준(ISO/IEC TR 19075-5:2016)에 들어온 행 패턴 인식을 그 위에 올려 MATCH_RECOGNIZE 로 내놓았다(공식 문서의 Pattern Recognition).

어떻게 동작하나

한 사용자의 사건 줄: 실패 F 네 번 뒤 성공 S. 패턴 F{3,} S 를 대면 첫 실패에서 시작한 후보(실패 4번)와 둘째 실패에서 시작한 후보(실패 3번)가 모두 같은 S 에서 끝난다. AFTER MATCH SKIP PAST LAST ROW 는 먼저 시작한 하나만 내고 S 다음 행에서 다시 찾는다. SKIP TO NEXT ROW 는 시작 행의 다음 행에서 다시 찾으므로 두 후보를 모두 낸다. 아래 줄은 로그인 뒤 5·12·15·300 결제에 패턴 S T+ B 를 대면 탐욕은 T 로 5·12·15 를 먹고 300 에서 끝나고, 비탐욕은 T 로 5 만 먹고 B 가 될 수 있는 12 에서 끝난다는 것을 보여 준다

뼈대는 이렇다.

SELECT * FROM events MATCH_RECOGNIZE (  PARTITION BY user_id ORDER BY ts              -- 키별로, 이벤트 시간 순서로  MEASURES FIRST(F.ts) AS first_fail, COUNT(F.ts) AS fails, S.ts AS ok_ts  ONE ROW PER MATCH  AFTER MATCH SKIP PAST LAST ROW  PATTERN (F{3,} S) WITHIN INTERVAL '30' SECOND  DEFINE F AS F.kind = 'FAIL', S AS S.kind = 'OK') AS T;

탐욕과 비탐욕. 수량자는 기본이 탐욕(되도록 많이)이고 뒤에 ? 를 붙이면 비탐욕(되도록 적게)이다. 두 변수의 조건이 겹칠 때만 차이가 난다. 이 실습의 카드 시험 패턴 S T+ B 에서 T 는 "20 미만 결제", B 는 "10 이상 결제" 라 10–19 가 둘 다에 걸린다. 탐욕 T+ 는 20 미만 결제를 끝까지 먹고 그다음 행이 B 여야 하고, 비탐욕 T+? 는 하나를 먹은 뒤 B 가 될 수 있는 첫 행에서 끝낸다. 이 파일에서는 매치 수는 같은데 끝나는 행과 큰 결제 금액이 달라졌다.

AFTER MATCH SKIP. 매치 하나를 찾은 뒤 어디서 다시 찾을지다. SKIP PAST LAST ROW 는 매치의 마지막 행 다음에서 — 한 행은 많아야 한 매치에만 든다. SKIP TO NEXT ROW 는 매치의 시작 행 다음에서 — 실패가 다섯 번 이어진 뒤 성공하면 시작 행만 다른 매치가 세 개 나온다. SKIP TO LAST 변수·SKIP TO FIRST 변수 도 있다.

WITHIN. 첫 행과 마지막 행의 간격 제한이다(표준 밖의 Flink 확장). 넘은 후보는 버려지고, 문서 말대로 상태를 비울 근거가 되므로 스트림에서는 거의 늘 붙인다. 이 파드에서 재 보니 간격이 정확히 30초인 후보도 WITHIN INTERVAL '30' SECOND 에서 떨어졌다 — 경계는 "미만" 으로 생각하는 것이 안전하다. 또 하나 — MATCH_RECOGNIZEtable.exec.state.ttl 을 따르지 않는다. 상태를 줄이는 손잡이는 WITHIN 이다.

현장에서 만나는 모습

탐지 규칙은 거의 늘 "몇 번 이상 · 얼마 안에 · 그 뒤에" 모양이라 MATCH_RECOGNIZE 가 잘 맞는다. 대신 경보 개수가 규칙보다 AFTER MATCH 전략에 좌우된다는 것을 모르면 곤란해진다. 같은 패턴이 PAST LAST ROW 로는 경보 1건, TO NEXT ROW 로는 3건을 낸다. 경보 시스템이 "사건 수" 를 세는지 "매치 수" 를 세는지부터 맞춰야 한다.

두 번째는 늦은 행이다. 패턴은 이벤트 시간으로 정렬한 뒤 찾으므로 입력이 흐트러져도 괜찮아 보이지만, 정렬은 워터마크까지만 기다린다. 워터마크 지연을 0으로 두고 흐트러진 입력을 넣으면 늦은 행이 조용히 빠지고 매치가 줄어든다. 오류도 경고도 없다. 이 실습에서 같은 행을 순서만 흐트러뜨린 파일로 지연 10초와 0초를 비교한다.

세 번째는 끝나지 않는 패턴. 조건 없는 변수에 상한 없는 수량자를 걸면 모든 행이 그 변수에 걸려 매치가 끝나지 않고 상태만 쌓인다. 문서의 처방은 뒤 변수의 조건을 부정해 넣거나 비탐욕으로 바꾸거나 WITHIN 을 거는 것이다.

다음 실습에서 할 것

로그인·결제 사건 표를 만들어 종류별 건수로 확인한 뒤, 무차별 대입 패턴을 PAST LAST ROW · TO NEXT ROW · WITHIN 30초로 바꿔 가며 돌린다. 카드 시험 패턴을 탐욕·비탐욕으로 돌려 끝나는 행이 달라지는 것을 보고, 도착 순서를 흐트러뜨린 파일을 워터마크 지연 10초와 0초로 읽어 매치 수를 비교한 뒤, 모든 숫자를 보고서로 모은다. 채점기는 같은 규칙을 파이썬으로 다시 돌려 한 행씩 대조한다.