본문으로 건너뛰기

맥락화: 시계열을 배치에 결합하기

📍 현재 위치: 3부 · 저장하고 연결하기 — 17장. 이제 히스토리언(historian)에는 수백만 건의 판독값이 쌓여 있습니다. 이 장에서는 각 판독값을 그것이 비롯된 배치(batch), 장비, 단계(phase)에 결합함으로써 모든 판독값에 의미를 부여합니다.

쉽게 말하면

가공되지 않은 히스토리언은 날짜가 떨어져 나간 영수증이 담긴 신발 상자와 같습니다. 각 쪽지에는 어느 순간엔가 BR101.Temp.PV = 37.00 °C라고 적혀 있습니다. 바이오리액터 BR101에서 측정된(PV = 공정 값, process value) 온도로, 사실이긴 하지만 아무 말도 하지 않습니다. 맥락화(contextualization)는 각 영수증을 올바른 배치 기록의 올바른 페이지에 스테이플로 박아 넣습니다. 판독값은 레시피(recipe) CHO-MAB-001에 따라 바이오리액터(bioreactor) BR101에서 가동된 BATCH-2026-001성장(Growth) 단계에서 발생했다고요(레시피는 제품을 만드는 배치 제조 절차로, 여기서는 중국 햄스터 난소, CHO, 세포에서 만드는 단일클론항체, MAB, 입니다). 그 순간 여러분은 "지난주 로트의 생산 단계 동안 용존 산소는 얼마였는가?" 같은 사람의 질문을 던질 수 있게 되고, 데이터베이스가 그에 답할 수 있게 됩니다.

이 장에서 다루는 내용

16장에서 우리는 모든 센서 태그(tag)를 집어삼키는 TimescaleDB 히스토리언을 구축했습니다. 4장에서는 ISA-88/95 배치 및 장비 세계(바로 아래에서 정의하는 두 산업 표준입니다. 배치 제어 — 레시피, 작업, 단계 — 를 위한 ISA-88과, 기업-제어 통합 — 장비 계층 — 을 위한 ISA-95)를 PostgreSQL에 모델링했습니다. 이 둘은 나란히 존재하면서도 지금까지 서로를 무시해 왔습니다. 이 장에서는 그 둘을 결혼시킵니다.

우리는 다음을 할 것입니다.

  • 단 하나의 SQL 뷰(view, 가상 테이블처럼 동작하는 저장된 질의 — 마치 테이블인 것처럼 질의하지만 그 행은 요청 시에 계산됩니다)로 히스토리언 스트림을 ISA-88 단계 및 ISA-95 장비 계층(equipment hierarchy)에 결합합니다.
  • 가공되지 않은 태그를 대상으로는 불가능한 배치 인식(batch-aware) 질의 — "배치 X의 생산 단계 동안의 DO" — 를 실행합니다.
  • 골든 배치(golden-batch) 오버레이 — 알려진 양호한 배치들로부터 구축되어 새 런이 그에 대조되는 기준 추적선 — 의 토대가 되는, 단계별·태그별 요약을 구축합니다.
  • 그리고 단계 경계를 Postgres에서 Grafana 대시보드로 밀어 넣어, 분석가가 레시피가 그 위에 그려진 채로 추세를 볼 수 있게 합니다.

이 장의 핵심을 이루는 두 개의 뷰는 examples/platform/db/60-views.sql에 있으며 데이터베이스가 처음 초기화될 때(make up, make load, make seed는 컴패니언 저장소의 셋업 명령으로, 각각 데이터베이스를 시작하고, 히스토리언 행을 적재하고, 배치 모델을 시드합니다) 생성됩니다. 이 뷰들은 make load로 적재된 히스토리언 행(examples/platform/db/20-historian.sql)을 make seed로 시드(seed)된 배치 모델(examples/platform/db/seed/seed_cho_line.sql)에 결합합니다. 뒤에 나오는 구체화 뷰(materialized view)와 Grafana 스니펫은 예시입니다. 이들은 모델이 다음으로 어디로 향하는지를 보여주며 18장에서 구축됩니다. 해당하는 곳마다 그렇게 표시해 두었습니다.

우리가 결합하는 두 세계

히스토리언 테이블은 일부러 멍청하게 만들어졌습니다. 다음은 examples/platform/db/20-historian.sql에서 가져온 그 정의입니다.

CREATE TABLE ts.sensor_reading (
ts timestamptz NOT NULL,
tag text NOT NULL,
value double precision,
unit text,
quality smallint NOT NULL DEFAULT 192, -- legacy OPC DA: 192 Good, 64 Uncertain, 0 Bad
batch_id text
);

여섯 개의 열, 그 어떤 견해도 없습니다. 전형적인 단면은 다음과 같습니다.

ts | tag | value | unit | quality | batch_id
------------------------+---------------+---------+------+---------+----------------
2026-01-13T08:00:00Z | BR101.Temp.PV | 36.9993 | degC | 192 | BATCH-2026-001
2026-01-13T08:00:00Z | BR101.DO.PV | 36.4576 | %sat | 192 | BATCH-2026-001
2026-01-13T08:00:00Z | BR101.pH.PV | 6.9922 | pH | 192 | BATCH-2026-001

(그 세 태그는 BR101 안 배양물의 온도, 용존 산소 — DO, 포화도의 백분율인 %sat로 보고됨 — 그리고 pH입니다.) 이 테이블이 이미 batch_id를 가지고 있다는 점에 주목하세요. 그것이야말로 포착 계층 전체에서 가장 중요한 설계 결정입니다. 수집기(collector)는 판독값을 기록하면서 활성 배치를 각 판독값에 도장처럼 찍습니다(이 작업은 7장에서 설정했습니다). 그것이 없다면 맥락화는 "그 화요일 08:00에 BR101에서 돌아가던 게 어느 런이었지?"를 추측하는 취약한 게임이 됩니다. 그것이 있으면 결합은 정확합니다.

하지만 batch_id는 이야기의 절반에 불과합니다. 그것은 어느 런인지는 알려주지만, 그 런의 어느 단계인지는 알려주지 않습니다. 08:00은 종균 배양(seed train, BR101에 종균을 대기 위해 점점 키워 가는 더 작은 배양물들의 확장 시리즈로, 1권에서 다룸)이 BR101으로 이송된 직후의 접종/지체(lag) 단계였을까요, 아니면 역가(titer, 1권 생산 바이오리액터에서 쌓아 올린, 축적되는 항체 제품의 농도)가 축적되는 생산 단계로 배양물이 넘어간 뒤였을까요? 그 답은 4장에서 구축한 관계형 세계에 있습니다.

ISA-88 배치 제어 표준은 우리에게 절차적 어휘를 제공합니다. 레시피는 작업(operation)들로 이루어지고, 각 작업은 단계들로 이루어지며, 단계는 의미 있는 가장 작은 절차적 요소입니다 [1]. ISA-95 기업 제어 표준은 물리적 측면을 제공합니다. 기업 → 사이트 → 영역 → 유닛(unit)으로 이어지므로 모든 태그를 그것이 가동된 장비에, 그리고 배치를 통해 그 로트에 묶을 수 있습니다 [2]. 두 모델은 모두 로열티 없는 기계 판독 가능한 XML 스키마(B2MML/BatchML)로 배포되며, 바로 그 덕분에 우리는 이들을 산문이 아니라 구체적인 관계형 테이블로 바꿀 수 있었습니다 [3].

examples/platform/db/seed/seed_cho_line.sql에서 유가식(fed-batch, 영양분 피드를 런 시작 시 한꺼번에가 아니라 런 도중에 추가하는 배양 모드 — 1권 생산 바이오리액터 참조) 레시피는 네 개의 작업과 다섯 개의 단계로 쪼개집니다.

INSERT INTO s88.phase VALUES
('PH1', 'OP1', 1, 'Inoculate'),
('PH2', 'OP2', 1, 'Growth'),
('PH3', 'OP2', 2, 'Production'),
('PH4', 'OP3', 1, 'Harvest'),
('PH5', 'OP4', 1, 'Capture') ON CONFLICT DO NOTHING;

Growth 같은 레시피 단계는 추상적인 템플릿입니다. 추적선(trace)을 시간 속에 실제로 고정하는 것은 배치 단계(batch phase) — 그 단계가 하나의 특정 배치에 대해 실제로 언제 가동되었는지의 기록 — 입니다. 실제 생산에서 이 start_ts/end_ts 경계는 손으로 입력하지 않습니다. 배치 실행 엔진(batch execution engine, BR101에서 레시피를 돌리는 자동화 계층)이 접종에서 성장으로, 다시 생산으로 진행할 때마다 단계 전이 이벤트를 내보내며, batch_id를 각 판독값에 찍는 바로 그 제어 계층에서 나오는 그 이벤트의 타임스탬프가 batch_phase에 들어갑니다. 여기서는 결합이 대조할 무언가를 갖도록 동등한 윈도를 손으로 시드합니다. 결합이 의존하는 윈도(window)가 바로 그것이며, 이 역시 시드 파일에 있습니다.

-- phase windows for the golden batch (drives the contextualization view)
INSERT INTO s88.batch_phase (batch_id, phase_id, unit_id, start_ts, end_ts) VALUES
('BATCH-2026-001', 'PH1', 'BR101', '2026-01-05T00:00:00Z', '2026-01-05T12:00:00Z'),
('BATCH-2026-001', 'PH2', 'BR101', '2026-01-05T12:00:00Z', '2026-01-12T00:00:00Z'),
('BATCH-2026-001', 'PH3', 'BR101', '2026-01-12T00:00:00Z', '2026-01-18T00:00:00Z'),
('BATCH-2026-001', 'PH4', 'BR101', '2026-01-18T00:00:00Z', '2026-01-19T00:00:00Z')
ON CONFLICT DO NOTHING;

이 네 행을 하나의 타임라인으로 읽어 보세요. 반나절의 접종, 그다음 일주일의 성장, 그다음 세포가 항체를 만드는 긴 생산 단계, 그다음 수확입니다. (PH5 Capture는 나중에 Protein A 스키드 PA01에서 가동되며 바이오리액터 윈도가 없으므로, 이 BR101 타임라인에는 나타나지 않습니다.) 1월 13일 08:00의 우리 판독값은 세 번째 윈도 안에 들어가므로, 그것은 진짜로 생산 단계 판독값입니다. 우리는 단지 SQL이 그것을 자동으로 알아내게 하면 됩니다.

PH5 Capture 행은 잠시 멈춰 볼 가치가 있습니다. 결합이 하류(downstream)로 내딛는 첫걸음이기 때문입니다. 바이오리액터의 접종-수확 런을 감싸는 바로 그 batch_phase 테이블이, 그 뒤에 다른 장비에서 이어지는 정제 트레인(purification train)도 감쌉니다. Protein A 캡처(PA01), 그다음 — 완전한 공정 모델에서는 — 저 pH 바이러스 불활화 홀드, 폴리싱 크로마토그래피, 바이러스 여과, 그리고 UF/DF(한외여과/정용여과, ultrafiltration/diafiltration)로, 1권이 캡처 크로마토그래피부터 이어서 다루는 하류 단계들입니다. 맥락화 뷰는 PA01이 교반 탱크가 아니라 크로마토그래피 스키드라는 점을 신경 쓰지 않습니다. 그것은 어떤 단계 윈도든 어떤 유닛의 태그에 대해 감싸므로, 생산 단계 DO 판독값을 찾는 바로 그 한 줄의 SQL이 크로마토그램 위의 캡처 단계 UV280 판독값을, 또는 용출(elution)의 전도도와 pH 추적선을 찾아냅니다. unit_id는 바이오리액터의 BR101.DO.PV와 스키드의 PA01.UV280.PV를 각자의 장비에 묶어 두면서도, 공유된 batch_id가 여전히 이들을 하나의 로트 기록으로 꿰게 합니다 — 바로 그것이 질의가 나중에 그 로트를 그것을 키운 배양물에서 그것을 정제한 컬럼까지 따라갈 수 있는 방식입니다.

손으로 시드한 윈도가 얼버무리고 넘어가는 제조 측면의 미묘함 하나. 실제 플랜트에서 이 start_ts/end_ts는 단계 경계의 유일한 — 심지어 가장 깨끗한 — 출처도 아닙니다. 배치 실행 엔진은 진행할 때마다 단계 전이 이벤트를 내보내지만, 운전원은 일시 정지하고, 홀드하고, 재개하기도 합니다. 단계는 중단되었다가 다시 가동될 수 있고, 수동 오버라이드가 레시피가 예측하지 못한 경계를 옮길 수 있습니다. 맥락화 계층은 레시피의 계획된 지속 시간이 아니라 기록된 batch_phase(MES/전자 배치 기록이 실제로 일어났다고 말하는 것)에 묶여야 합니다. 설계 의도가 아니라 가동된 그대로(as-run)의 단계 시각이라는 검증된 기록이야말로 지속적 공정 검증 추세와 일탈 조사가 정렬해야 하는 대상이기 때문입니다. 우리가 시드한 윈도는, 노트북에서 결합이 대조할 무언가를 갖도록, 그 권위 있는 이벤트 로그를 대신합니다.

히스토리언 태그가 왼쪽에서 오른쪽으로 흐르며 batch_id 도장을 얻고, 그다음 타임라인 위의 ISA-88 단계 윈도와 ISA-95 장비 트리에 대조된 뒤, 오른쪽에서 자신의 배치, 단계, 유닛, 레시피를 명시하는 완전히 맥락화된 행으로 나타난다.

아무 말도 못 하던 태그에서 의미 있는 기록으로: 맥락화 결합은 각 히스토리언 판독값을 그것이 들어가는 단계 윈도와, 그것이 속한 장비/레시피에 스테이플로 박아 넣는다. 저자가 AI의 도움을 받아 직접 제작한 그림입니다.

맥락화된 판독값의 해부: v_batch_sensor 한 행

결합을 작성하기 전에, 그 결합이 만들어내는 것 — s88.v_batch_sensor의 한 행 — 을 해부해 볼 가치가 있습니다. 이 장에서 계속 사용하는 예시를 가져옵시다. 2026-01-13T08:00:00ZBR101.Temp.PV 온도 판독값입니다. 맨몸의 히스토리언에서 그것은 여섯 개의 열입니다. 뷰가 실행된 뒤에는 열한 개가 되며, 그 열한 개는 네 개의 의미 있는 밴드로 나뉩니다.

원시 밴드(raw band)는 그대로 통과해 들어온 여섯 개의 히스토리언 열입니다. ts, tag, value, unit, quality, 그리고 batch_id. 이들은 정확히 16장에서 저장한 것입니다. 뷰는 여기에 아무것도 더하지 않고, 그저 통과시킵니다. 36.9993이라는 valuedegC라는 unit 없이는 무의미합니다. 192라는 quality는 레거시 OPC DA(OPC Data Access, 더 오래된 산업 데이터 통신 프로토콜)의 패킹된 품질 바이트 Good 값으로 — 192, 64, 0은 임의의 숫자가 아니라 OPC 표준이 정의한 비트 코드 값입니다(192 Good / 64 Uncertain / 0 Bad). 7장(OT의 언어: OPC UA, MQTT)에서 확립한 대로이며, Good이 0x00000000인 더 새로운 OPC UA(OPC Unified Architecture)의 32비트 StatusCode와는 다릅니다 — 불확실한 점이 슬그머니 평균에 섞이지 않도록 값 옆에 함께 따라옵니다. 이는 맥락화된 기록을 정확하고 완전하게 유지하는데, 이것이 바로 규제 당국이 모든 GMP(우수 제조 관리 기준, Good Manufacturing Practice) 기록에 적용하는 ALCOA+(Attributable 귀속 가능, Legible 판독 가능, Contemporaneous 동시 기록, Original 원본, Accurate 정확, 그리고 Complete 완전, Consistent 일관, Enduring 지속, Available 이용 가능) 데이터 무결성 기대치입니다 — 이는 23장, 구성으로 달성하는 ALCOA+에서 코드로 구현됩니다. 그리고 batch_id는 수집기가 취득 시점(7장)에 찍은 도장으로, 아래의 모든 것을 가능하게 하는 키입니다.

배치 밴드(batch band)는 그 batch_id를 따라 s88.batch에서 뷰가 결합해 들여온 세 개의 열입니다. product_id(MAB-001), recipe_id(CHO-MAB-001), 그리고 unit_id(BR101). 이것은 어느 런인지, 무엇의, 어느 레시피 아래, 어느 장비에서에 대한 답입니다. (s88.batch 행은 status — 여기서는 released — 와 lotL26001도 가지고 있습니다. 뷰는 이들을 투영(project), 즉 열 목록에 포함하지 않지만, 소비자가 필요로 하면 열 목록을 한 번 편집하는 것으로 끝납니다.) 시드는 실제로 동일한 CHO-MAB-001 레시피를 BR101에서 돌린 6개 배치 캠페인을 적재합니다. 골든 배치 BATCH-2026-001에 더해 출시된 형제들 002, 003, 005, 거부된(규격 외, out-of-specification) 로트 004, 그리고 완료된 006(실행은 끝났고 QA 처분을 기다리는 중)입니다. 이 장의 나머지는 001을 중심으로 하지만, 골든 배치 비교가 애초에 가능한 것은 바로 그 형제들 덕분입니다.

단계 밴드(phase band)는 결합이 만들어내기 전까지는 어디에도 존재하지 않던 두 개의 열입니다. phase_id(PH3)와 phase_name(Production). 이들은 저장된 것이 아니라 파생된(derived) 것이며, 다음 절 전체가 바로 그 방법에 관한 것입니다. 이것이 판독값을 "어느 순간의 한 숫자"에서 "생산 단계 판독값"으로 바꾸는 필드이며, 행에서 가장 가치 있는 단 하나의 것입니다. 카드가 그것을 강조하는 이유입니다.

네 번째 조각은 열이 아니라 디코드(decode)입니다. tagBR101.Temp.PV는 그 자체가 asset . measurement . role로 구조화되어 있습니다. ISA-95 유닛, 측정되는 양, 그리고 레시피 설정값인 .SP가 아니라 공정 값(process value), 즉 증거를 뜻하는 PV입니다. 같은 문법 덕분에 질의는 BR101의 모든 PV를, 또는 공장 전체의 모든 온도를 선택할 수 있습니다.

2026-01-13T08:00:00Z의 BR101.Temp.PV에 대한 s88.v_batch_sensor 한 행의 신분증 카드로, 그대로 통과해 들어온 여섯 개 히스토리언 열의 원시 밴드, s88.batch에서 결합된 세 개 열의 배치 밴드, phase_id PH3와 phase_name Production이 시간적 결합으로 파생되는 강조된 초록색 단계 밴드, 그리고 태그 이름을 asset, measurement, role로 디코드하는 보라색 패널로 묶여 있다. 맥락화된 한 행을, 필드 하나하나: 여섯 개의 원시 히스토리언 열, 배치에서 결합된 세 개, 그리고 시간적 결합이 즉석에서 파생하는 두 개의 단계 열. 저자가 AI의 도움을 받아 직접 제작한 그림입니다.

이 행은 어디에서 오는가 — 삼부작의 등뼈

이 열한 개짜리 행은 다른 두 책이 깔아 놓은 아이디어의 오픈 소스 구현입니다. 36.9993 °C라는 값은 1권 생산 바이오리액터 장의 바이오리액터에서 물리적으로 생성되었습니다 — 센서가 지켜보던 바로 그 세포 배양 단계입니다. 그다음 2권은 그것을 데이터 포인트로 틀 지었습니다. ISA-95가 요구하는 밴드로 나뉜 맥락화된 판독값, 그리고 히스토리언을 배치 기록에 꿰매는 플랜트 시스템을 가로지르는 batch_id 결합으로요. 거기서 모델링의 포부였던 것이, 여기서는 여러분이 실행할 수 있는 두 개의 SQL 뷰입니다.

실제 일을 해내는 결합

다음이 이 장의 핵심입니다. examples/platform/db/60-views.sql에서 가져온 뷰 전체입니다.

-- A reading with its full batch + phase context.
CREATE OR REPLACE VIEW s88.v_batch_sensor AS
SELECT r.ts, r.tag, r.value, r.unit, r.quality, r.batch_id,
b.product_id, b.recipe_id, b.unit_id,
bp.phase_id, ph.name AS phase_name
FROM ts.sensor_reading r
JOIN s88.batch b ON b.batch_id = r.batch_id
LEFT JOIN s88.batch_phase bp ON bp.batch_id = r.batch_id
AND r.ts >= bp.start_ts AND (bp.end_ts IS NULL OR r.ts < bp.end_ts)
LEFT JOIN s88.phase ph ON ph.phase_id = bp.phase_id;

짧지만 모든 절(clause)이 제 몫을 합니다.

첫 번째 JOIN s88.batchbatch_id에 대한 내부(inner) 조인입니다. 일치하는 배치가 없는 판독값은 버려집니다. 그것은 의도된 것입니다. 어떤 배치도 가동되지 않는 동안 센서가 깜빡인 것은 그 어떤 GMP 기록의 일부도 아니므로, 배치 인식 질의에 슬그머니 나타나서는 안 됩니다.

시간적 포함 결합: 반열린 구간 안의 ts

영리한 부분은 LEFT JOIN s88.batch_phase입니다. 일치 조건은 키에 대한 동등성(equality)이 아니라 시간적 포함(temporal containment)입니다. r.ts >= bp.start_ts AND (bp.end_ts IS NULL OR r.ts < bp.end_ts). 각 판독값에 대해 Postgres는 그 시작/끝이 판독값의 타임스탬프를 감싸는 단계 윈도를 찾습니다. 반열린 구간(시작은 >=, 끝은 <)이 뜻하는 바는, 단계 경계에 정확히 걸친 판독값은 단계에 속하며 결코 양쪽 모두에 속하지 않는다는 것입니다. 이중 계산이 없습니다. bp.end_ts IS NULL 분기는 아직 끝이 기록되지 않은 채 실시간으로 진행 중인 단계를 처리합니다. 우리는 이것을 LEFT 조인으로 유지하는데, 그래야 어떤 단계 윈도도 열리기 전에 도착한 판독값이 사라지지 않고 (단계가 NULL인 채로) 그대로 드러납니다.

우리가 계속 사용하는 예시로 따라가 봅시다. BATCH-2026-001의 네 개 batch_phase 행은 타임라인 위에 네 개의 윈도를 펼칩니다. 우리 판독값의 ts2026-01-13T08:00:00ZPH3의 시작(2026-01-12T00:00:00Z)을 지났고 그 끝(2026-01-18T00:00:00Z) 이전이므로, 정확히 하나의 윈도에 일치하여 phase_name = Production을 물려받습니다. 2026-01-12T00:00:00Z 순간의 판독값은 PH2가 아니라 PH3에 속하는데, PH2의 조건이 자신의 끝에 <를 쓰기 때문입니다. 경계는 새 단계 쪽으로 기웁니다. 그 <<=의 단 한 번의 선택이, 모든 경계 판독값이 한 번 세어지느냐 두 번 세어지느냐의 차이입니다.

시간적 포함 결합의 메커니즘 다이어그램: BR101.Temp.PV에 대한 ts.sensor_reading 한 행이 ts가 start_ts 이상이고 ts가 end_ts 미만인지 검사하는 match-on-ts 박스로 흘러들어, phase_id PH3인 phase Production이라는 초록색 결과로 나온다. 아래에는 BATCH-2026-001의 네 개 batch_phase 윈도가 Jan 05에서 Jan 19까지의 타임라인 위에 그려지고, 판독값의 ts 표식이 강조된 Production 윈도 안에 자리 잡는다.

그 단 하나의 뷰가 모든 하류 소비자가 질의하는 계약입니다. 대시보드, 분석 노트북, 지식 그래프 로더(19장, 이 행들을 배치, 장비, 자재, 결과의 RDF 그래프로 접어 넣습니다)가 그것입니다. 이들 중 누구도 가공되지 않은 ts.sensor_reading 테이블을 다시는 건드리지 않습니다. 이제 사람의 질문은 SQL 한 줄이 됩니다.

-- "Show me dissolved oxygen during the Production phase of the golden batch."
SELECT ts, value
FROM s88.v_batch_sensor
WHERE batch_id = 'BATCH-2026-001'
AND tag = 'BR101.DO.PV'
AND phase_name = 'Production'
ORDER BY ts;
ts | value
------------------------+---------
2026-01-12T00:00:00Z | 36.8646
2026-01-12T00:01:00Z | 35.888
2026-01-12T00:02:00Z | 36.5891
...
2026-01-17T23:59:00Z | 34.0293

이것을 맨몸의 히스토리언을 대상으로는 결코 작성할 수 없습니다. phase_name = 'Production'은 시계열 테이블이 애초에 담고 있지 않은 지식입니다. 결합이 그것을 즉석에서 만들어 냈습니다.

판독값에서 골든 배치 구성 요소로

추적선은 유용합니다. 하지만 단계별 요약은 공정 이해가 시작되는 지점입니다. examples/platform/db/60-views.sql의 두 번째 뷰는 맥락화된 판독값을 배치, 단계, 태그당 한 행으로 말아 올립니다.

-- Per-batch, per-phase, per-tag summary: the "golden batch" building block.
CREATE OR REPLACE VIEW s88.v_phase_summary AS
SELECT batch_id, phase_name, tag, unit,
count(*) AS n,
round(avg(value)::numeric, 4) AS avg_value,
round(min(value)::numeric, 4) AS min_value,
round(max(value)::numeric, 4) AS max_value
FROM s88.v_batch_sensor
WHERE phase_name IS NOT NULL
GROUP BY batch_id, phase_name, tag, unit;

골든 배치 전체에 걸쳐 온도를 질의하면 간결한 공정 지문(fingerprint)이 나옵니다.

batch_id | phase_name | tag | unit | n | avg_value | min_value | max_value
----------------+------------+---------------+------+------+-----------+-----------+----------
BATCH-2026-001 | Growth | BR101.Temp.PV | degC | 9360 | 37.0002 | 36.8724 | 37.1211
BATCH-2026-001 | Production | BR101.Temp.PV | degC | 8640 | 36.9893 | 36.3571 | 37.1218
BATCH-2026-001 | Harvest | BR101.Temp.PV | degC | 1440 | 37.0008 | 36.9132 | 37.0981

7일째 이상 현상이 단계로 잘라야만 드러나는 이유

생산 단계의 그 36.36 °C 최솟값은 컴패니언 저장소의 데이터 시뮬레이터가 유가식 추적선에 일부러 심어 놓은 7일째 이상 현상(excursion, 정상 범위를 벗어나는 일시적 일탈)입니다. 그리고 요약이 단계별로 잘려 있기 때문에, 그것은 14일간의 런 전체에 평균되어 보이지 않게 되는 대신 정확히 일어난 그 자리에 나타납니다. 그 이상 현상 동안 DO와 온도 프로브는 그 약 3시간에 대해 64 Uncertain도 표시하므로, 온도 하락을 찾아내는 바로 그 질의가 Uncertain 점들을 평균에 섞는 대신 배제할 수 있습니다. 품질 코드가 값 옆에 함께 따라오는 이유를 보여주는 구체적인 사례입니다.

왜 잘라내는 것이 중요한지 산수로 따져 봅시다. 배치 전체에 걸친 온도 평균은 본질적으로 37.0 °C입니다. 몇 시간 지속되는 36.36 °C로의 단 한 번의 하락은 14일 평균을 천분의 몇 도만큼 움직일 뿐입니다. 여러분이 보고할 그 어떤 반올림보다도 한참 안쪽입니다. 단계별로 잘리면, 같은 하락이 생산 행의 최솟값이 되고, 생산 최솟값(36.3571)과 그 평균(36.9893) 사이의 간격은 반 도가 넘습니다. 놓칠 수 없는 신호입니다. 이상 현상이 커진 게 아닙니다. 분모가 정직해진 것입니다. 그것이 바로 배치 전체 집계로 모니터링할 때의 실패 양상입니다. 실제의 국소적 일탈이, 그 주위를 둘러싼 정상 가동 시간들에 의해 보고 임계값 아래로 희석되고, 배치 수준 숫자를 스크롤하는 조사자는 그것을 결코 보지 못합니다.

이 단계별 축약은 편의 기능이 아니라, 배치 공정을 제대로 모니터링하기 위한 통계적 전제 조건입니다. 배치 모니터링에 관한 선구적인 다중 PCA(multiway-PCA, 다중 주성분 분석 — 시간에 걸친 많은 상관된 공정 변수를 몇 개의 요약 궤적으로 압축하는 통계적 방법으로, 5권에서 자세히 다룹니다) 연구는 정상 과거 배치들을 정렬하고 새 런을 그에 대조함으로써 기준 궤적 — "골든 배치" — 을 구축했습니다 [4]. 그리고 우리가 벽시계 시간이 아니라 ISA-88 단계로 먼저 잘라내는 이유는, 유가식 궤적이 공정 단계와 지표 변수에 정렬된 뒤에야 비로소 배치 간에 서로 들어맞기 때문입니다. 한 배치는 아직 접종 중인데 다른 배치는 이미 피드 중이라면, 두 배치의 30분 지점끼리 비교하는 것은 무의미합니다 [5]. v_phase_summary는 이 모든 것의 소박하고 질의 가능한 씨앗입니다. 모든 형제 배치가 동일한 단계 키(phase-keyed) 형태로 축약되어, 쌓을 준비가 된 상태입니다.

맥락화된 뷰는 모델의 피처 계약이기도 하다

v_phase_summary 한 행은 골든 배치 포락선이기 이전에 피처(feature)이며, 그래서 이 뷰는 머신러닝이 정직한 데이터를 얻거나 속아 넘어가거나 하는 계층이 됩니다. 결합이 이미 강제하는 두 가지가, 바로 ML 파이프라인이 필요로 하면서도 가장 자주 건너뛰는 규율입니다. 첫째, 모든 행의 batch_id는 누수 없는 분할이 존중해야 하는 그룹화 키(grouping key)입니다. 각 유가식 런은 진정으로 독립적인 단 하나의 관측이므로(701개 파장이나 16개 태그가 16개의 독립 표본이 되지는 않습니다), 소프트 센서는 배치 그룹화/배치 단위 제외(leave-one-batch-out) 교차 검증(전체 배치로 학습하고 따로 떼어 둔 배치로 검정하며, 같은 런의 행을 학습/검정 경계 양쪽으로 결코 나누지 않는 것) 아래에서 검증되어야 하며, 그러지 않으면 보고된 정확도는 모델이 이미 본 배치에 대해 채점된 인공물에 불과합니다. 5권의 학습 문제 장모델과 검증 장은 이것을 바이오공정 ML의 콜드 스타트(cold-start) 규칙으로 삼습니다. 여기 batch_id가 그것을 강제 가능하게 만드는 열입니다. 둘째, phase_name정렬 키(alignment key)입니다. MSPC(다변량 통계적 공정 관리, multivariate statistical process control) 모니터나 Raman 소프트 센서는 행이 단계 정렬되었을 때에만 같은 것끼리 비교하며, 이것이 골든 배치 오버레이가 벽시계 시간이 아니라 단계로 잘라내는 바로 그 이유입니다.

quality 바이트도 여기서 두 번째 일을 해냅니다. 7일째 이상 현상 동안 64 Uncertain으로 찍힌 행은 모델이 슬그머니 학습해서는 안 되고 가중치를 낮추거나 걸러내야 하는 행입니다. 이는 적용 범위(applicability domain) 검사(모델의 학습 영역 바깥에 놓인 입력을, 그 예측을 신뢰하기 전에 표시하는 게이트로, 5권의 검증 장에서 구축됩니다)의 데이터베이스 수준 유사물입니다. 그리고 이 장이 맥락화된 판독값과 그 뒤의 관계형 모델 사이에 긋는 구분은, 정확히 5권의 MLOps 장공정 드리프트(process drift)(살아 있는 배양물이 배치 간에 진짜로 떠도는 것 — v_phase_summary측정하도록 만들어진 것)와 모델 드리프트(model drift)(프로브가 오염되며 소프트 센서가 쇠퇴하는 것 — 같은 단계 키 추세 위의 잔차 관리도가 잡아내도록 만들어진 것) 사이에 긋는 구분입니다. 맥락화된 뷰는 그 공유 기반입니다. 골든 배치 오버레이를 먹이는 바로 그 단계 정렬되고 배치 그룹화되고 품질 표시된 행들이, 그 하류의 모든 모델을 먹이고 — 그리고, 결정적으로, 검증하는 — 행들입니다.

결합이 비싸질 때 맥락을 구체화하기

v_batch_sensor는 평범한 뷰입니다. 시간적 결합이 매 질의마다 다시 실행됩니다. 몇 개의 태그에 대한 골든 배치라면 그것은 순식간입니다. 하지만 시드된 6개 배치 캠페인, 그것의 16개 태그, 그리고 자동 갱신되는 대시보드에 걸쳐서라면, 동일한 포함 결합이 거듭거듭 실행됩니다.

두 가지 OSS 메커니즘이 모델을 바꾸지 않고도 이를 해결합니다.

원시 레이트(raw-rate) 롤업의 경우, TimescaleDB 연속 집계(continuous aggregate)는 하이퍼테이블(hypertable) 위의 구체화 뷰로, 새 데이터가 도착하면 증분적으로 갱신되므로 전체 이력을 다시 계산하지 않아도 됩니다 [6]. 우리는 이미 16장에서 이들을 생성했습니다(ts.sensor_1m, ts.sensor_1h). 히스토리언은 태그당 분당 한 행을 저장하므로(60 × 24 × 14 = 14일 런 동안 태그당 약 20,160행), 단계 인식 대시보드는 1분 단위 판독값을 일일이 스캔하는 대신 미리 말아둔 1시간 연속 집계 버킷(bucket)(ts.sensor_1h)을 단계 윈도에 결합합니다.

맥락 계층의 경우, 평범한 PostgreSQL 구체화 뷰(materialized view)는 결합 결과를 디스크에 스냅샷으로 떠 두고 여러분이 REFRESH할 때까지 그것을 제공합니다 [7]. 요약을 구체화로 바꾸는 것은 한 단어짜리 변경입니다. 아래 블록은 예시 스니펫입니다. 저장소(repo)에 커밋되어 있지 않으며 make seed로 생성되지 않습니다. 라이브 결합이 비싸질 때 여러분이 추가할 패턴을 보여줍니다.

-- Illustrative — not in the repo; shows how you would materialize v_phase_summary.
CREATE MATERIALIZED VIEW s88.mv_phase_summary AS
SELECT * FROM s88.v_phase_summary;
-- refresh after a batch completes (or on a schedule):
REFRESH MATERIALIZED VIEW s88.mv_phase_summary;

정직한 아키텍처 노트 하나. 이 책에서 히스토리언과 관계형 모델은 동일한 PostgreSQL 인스턴스에 살고 있으므로(TimescaleDB는 별도의 데이터베이스가 아니라 Postgres 확장입니다), s88.batchts.sensor_reading은 네이티브로 결합됩니다. 실제 세계에서는 여러분의 히스토리언이 흔히 다른 서버 — 별도의 Postgres이거나, AVEVA PI 같은 상용 시스템 — 입니다. PostgreSQL은 같은 SQL인데 서버가 다른 이 경우를 postgres_fdw로 해결합니다. 이는 원격 테이블을 마치 로컬인 것처럼 노출하는 외부 데이터 래퍼(foreign-data wrapper)로, 하나의 뷰가 여전히 그 경계를 가로질러 결합할 수 있게 해줍니다 [8]. 우리가 여기서 단일 인스턴스 결합을 쓰는 것은 그것이 노트북에서 돌아가는 방식이기 때문입니다. FDW 패턴은 정확히 이 뷰를 두 서버에 걸쳐 늘이는 방법이며, 브리지(bridge) 장들(20–22장)은 그 아이디어를 PI와 SAP에까지 끝까지 밀고 갑니다.

추세 위에 레시피 그리기: Grafana 오버레이

맥락화된 뷰는 사람이 그것을 보는 순간 제값을 합니다. Grafana는 PostgreSQL/TimescaleDB를 네이티브로 읽습니다. 시간 열(time column)이 필요하고, 데이터를 패널 너비에 맞춰 버킷화하는 $__timeFiltertime_bucket 헬퍼를 제공합니다 [9]. 아래 두 질의는 예시입니다. 이들은 make seed가 아니라 Grafana 내부에서 실행되며, 이들을 감싸는 프로비저닝된(provisioned) 대시보드는 18장에서 구축됩니다. 추세 패널은 그저 우리 뷰입니다.

-- Illustrative Grafana panel query (runs in Grafana, not via make seed).
SELECT ts AS "time", value, tag
FROM s88.v_batch_sensor
WHERE batch_id = '$batch'
AND tag IN ($tags)
AND $__timeFilter(ts)
ORDER BY ts;

마법은 두 번째 질의에 있습니다. 이 질의는 단계 윈도를 추세 뒤에 그려지는 음영 처리된 주석(annotation) 영역으로 바꿉니다.

-- Illustrative Grafana annotation query (runs in Grafana, not via make seed).
SELECT bp.start_ts AS "time", bp.end_ts AS "timeEnd", ph.name AS text
FROM s88.batch_phase bp
JOIN s88.phase ph ON ph.phase_id = bp.phase_id
WHERE bp.batch_id = '$batch'
ORDER BY bp.start_ts;

이제 분석가는 출렁이는 선들의 벽을 읽지 않습니다. 그들은 성장생산 밴드가 아래에 칠해진 채로 용존 산소를 보고, 7일째 온도 하락이 생산 안에 눈에 띄게 자리 잡은 것을 봅니다. 맥락이 그림 위에 있는 것입니다. 런을 비교하려면, 출시된 세 형제 배치(002, 003, 005 — 004는 거부된 로트이므로 제외됩니다)에 대한 v_phase_summary를 흐릿한 포락선(envelope)으로 쌓고 그 위에 새 배치를 그립니다. 그것이 바로 골든 배치 오버레이이며, 18장에서 구축됩니다.

세 개의 관계형 소스 — 가공되지 않은 ts.sensor_reading 히스토리언, s88.batch_phase 단계 윈도, 그리고 s88.batch 유닛 및 레시피 ISA-88/95 맥락 — 가 s88.v_batch_sensor 시간적 결합 뷰로 수렴하고, 이 뷰는 다시 s88.v_phase_summary 골든 배치 지문과 Grafana 단계 밴드 추세로 펼쳐지며, 요약은 또다시 18장에서 구축되는 골든 배치 오버레이로 이어진다.

왜 중요한가

맥락화는 데이터 수집공정 이해 사이의 경첩입니다. 맥락화되지 않으면 히스토리언은 "그 숫자가 얼마였는가?"에만 답할 수 있습니다. 그것은 어떤 조사자도, 어떤 통계학자도, 어떤 검사관도 실제로는 결코 묻지 않는 질문입니다. 맥락화되면 히스토리언은 "그 숫자가, 어느 단계 동안, 어느 배치의, 어느 장비에서 얼마였는가?"에 답합니다. 그것이야말로 중요한 모든 질문입니다.

그것은 또한 두 가지 규제 기대의 기술적 기반(substrate)입니다. 지속적 공정 검증(Continued Process Verification) — FDA의 3단계 공정 검증 생애주기의 3단계(1단계 공정 설계, 2단계 공정 적격성 평가, 3단계 검증된 공정이 제어 상태에 머무르는지의 지속적 검증) — 은 공정이 배치를 거듭하며 제어 상태에 머무른다는, 지속적이고 문서화된 보증을 요구합니다 [10]. 가공되지 않은 태그로는 CPV를 할 수 없습니다. 단계 정렬되고 배치 키가 부여된(batch-keyed) 추세로 합니다. 바로 v_phase_summary가 만들어내는 것입니다. 그리고 ICH Q10 — 국제의약품규제조화위원회(International Council for Harmonisation)의 제약 품질 시스템 가이드라인 — 은 공정 성능 및 제품 품질 모니터링을 제약 품질 시스템의 상시 목표로 삼아, 예외 검토(review-by-exception)와 지속적 개선을 가능하게 합니다 [11]. 단일한 재현 가능 질의로 모든 배치의 생산 단계 DO를 꺼내고, 일탈한 배치만 볼 수 있는 검토자는 예외 검토를 수행하는 것입니다. 그것은 종이를 스크롤하는 것보다 훨씬 빠르고 오류가 훨씬 적습니다.

실제 현장에서는

이 패턴은 여러 이름으로 도처에 존재합니다. 상용 히스토리언은 이를 "자산 프레임워크(asset framework)" 또는 "배치 컨텍스트(batch context)"로 판매합니다(예를 들어 AVEVA PI AF는 PI 태그 위에 장비/이벤트 모델을 얹어, 포인트 이름이 아니라 자산과 이벤트로 질의할 수 있게 합니다). MES(제조 실행 시스템, Manufacturing Execution System) 플랫폼은 이를 전자 배치 기록(electronic batch record)이라고 부릅니다. 우리가 두 개의 SQL 뷰로 만든 것은 모든 엔지니어가 이미 아는 개방형 관계형 기본 요소로 표현된 동일한 아이디어입니다.

OSS 대 검증된 자산 모델, 정직한 이음매

OSS 대 상용에 관한 정직한 셈법은 이렇습니다. 결합 자체는 오픈 소스에서 진정으로 해결되었고, 잘 해결되었습니다. PostgreSQL의 시간적 결합, TimescaleDB의 연속 집계(16장에서 언급한 대로 무료이고 소스가 공개된 TSL 기능이며, OSI 오픈 소스는 아닙니다), FDW, 그리고 Grafana가 그 메커니즘을 완전히, 그리고 라이선스 비용 없이 다룹니다. 순수 OSS가 여러분에게 건네주지 않는 것은 그 주변의 관리입니다. 공급사가 유지보수하고 검증한 자산 모델, 포인트 앤 클릭 방식의 이벤트 프레임 구성, 컨텍스트 모델 자체에 대한 변경 관리, 그리고 GAMP-5(우수 자동화 제조 관리 기준, Good Automated Manufacturing Practice) 감사가 기대하는 공급사 책임성 말입니다. 우리 뷰로는 여러분이 컨텍스트 모델을 소유합니다. 그것은 곧 여러분이 그것을 검증하고, DDL(데이터 정의 언어, Data Definition Language — 스키마를 정의하는 CREATE 문들)을 버전 관리하며(이는 Git에 살아 있는데, 그것은 진짜 이점입니다), 적격성 평가(qualification) 아래에서 결합 로직이 올바름을 입증하는 일도 소유한다는 뜻입니다.

구체적으로, 그 이음매는 해부 카드를 정확히 관통합니다. 원시 밴드와 배치 밴드는 신뢰하기에 값쌉니다. 그대로 저장된 값들과 키 동등성이기 때문입니다. 단계 밴드 — 파생된 두 열 — 가 바로 검증 부담이 사는 곳입니다. 반열린 시간적 포함 술어(predicate)로 계산되기 때문이며, 단 하나의 경계 조건 버그(<를 의도했는데 <=를 쓰거나, end_ts가 빠진 윈도)가 판독값을 잘못된 단계에 슬그머니 잘못 배정하여 그 위에 쌓아 올린 모든 골든 배치 비교를 오염시킬 것입니다. 상용 자산 프레임워크는 여러분에게 공급사가 테스트한 이벤트 프레임 엔진을 신뢰하라고 요구합니다. OSS 경로는 어떤 판독값도 두 단계에 걸치지 않고 어떤 것도 틈으로 빠지지 않음을 증명하는 테스트를 여러분이 소유하라고 요구합니다. DDL이 Git 안의 검사 가능한 세 줄짜리 SQL이라는 점이야말로 그 테스트를 애초에 작성 가능하게 만듭니다. 하지만 그것을 작성하는 일은 여러분 몫입니다. 그것이 이 책에서 거듭 나타나는 모습입니다. 오픈 소스는 여러분에게 깨끗하고 검사 가능한 약 80%를 가져다주고, 그것을 감싸는 검증된 시스템 래퍼는 여러분이 만들거나 사야 할 몫입니다.

같은 맥락을 트리플로, 셰이프로, 역량 질문으로

관계형 뷰는 맥락화된 판독값의 한 가지 표현이고, 시맨틱 표현은 다음 장의 것입니다. 위의 결합이 이미 작은 온톨로지를 변장하고 있다는 점은 볼 만합니다. 각 v_batch_sensor 행은 19장의 RDF 그래프 안에서 하나의 판독값에 관한 몇 개의 트리플(triple, 주어-술어-목적어 사실)을 단언합니다. 그것이 어떤 ISA-95 유닛에서 wasMeasuredOn(측정되었고), 어떤 ISA-88 단계 duringPhase(동안에) 일어났으며, 어떤 로트에 belongsToBatch(속한다)는 것입니다. 배치 밴드는 객체 속성(object property)(걸어갈 수 있는 에지 — BATCH-2026-001 ranOn BR101)으로, 정확히 4권이 관계 장에서 긋는 객체 대 데이터타입 속성의 갈림길입니다. 가공되지 않은 value/unit데이터타입 속성(datatype property)(읽어내는 타입 지정 리터럴 — 이상적으로는 맨몸의 문자열 degC가 아니라 기계 판독 가능한 QUDT 양으로 단위를 지니는 것)입니다. 관계형 batch_id 외래 키가 로컬에서 하는 일을, 전역에서 유일한 IRI(국제화 자원 식별자, Internationalized Resource Identifier)가 시스템을 가로질러 합니다 — LIMS, MES, 히스토리언이 같은 배치를 뜻한다고 동의하게 하는 속성으로, 4권의 식별자 장에서 다룹니다.

방금 이음매가 요구한 경계 조건 테스트에도 형식적 쌍둥이가 있습니다. "어떤 판독값도 두 단계에 걸치지 않고, 어떤 것도 틈으로 빠지지 않는다"는 SHACL 셰이프(Shapes Constraint Language — 그래프 데이터가 요구된 구조를 갖췄는지 검증하는 W3C 표준)이며, 4권이 출시 게이트 장에서 구축하는 폐쇄 세계(closed-world) 게이트입니다. 각 맥락화된 판독값에 대한 sh:NodeShape에서 그 duringPhase 에지에 건 sh:maxCount 1이 이중 계산을 잡고, sh:minCount 1이 틈을 잡습니다 — 손으로 쓴 SQL 단언을 잊지 않고 돌려야 하는 대신, 검증기가 강제하는 제약으로 표현된 반열린 구간 불변식입니다. 그리고 이 장이 거듭 답하는 사람의 질문 — "배치 X의 생산 단계 동안의 DO" — 은 온톨로지 공학 용어로 역량 질문(competency question)(모델이 답할 수 있어야 하는 평범한 말의 질문으로, 합격/불합격 인수 테스트로 쓰임)입니다. 4권은 그중 23개를 역량 질문 장에서 실행 가능한 합격/불합격 검사로 바꿉니다. 위의 SQL은 그런 질문 하나에 대한 관계형 답이고, 지식 그래프 로더는 같은 맥락이 PROV-O 스타일의 출처(provenance, 무엇이 어떤 활동에 의해 무엇으로부터 파생되었는가를 위한 W3C 어휘)와 함께 로트 계보를 세포 은행까지 거슬러 걷는 질의가 되는 곳입니다. 관계형, RDF, SHACL은 하나의 모델을 세 가지로 렌더링한 것이며 — 이들이 서로 갈라지지 않게 막는 것이야말로 정확히 다음 장이 닫음말로 삼는 단일 진실 출처(single-source-of-truth) 규율(LinkML)입니다.

핵심 용어

  • 맥락화(Contextualization) — 가공되지 않은 시계열 판독값을 그것이 속한 배치, 장비, 단계, 레시피에 결합하여, 데이터가 공정 지식으로서 질의 가능해지게 하는 것.
  • 배치 단계(batch phase, batch_phase) — 특정 ISA-88 단계가 하나의 배치에 대해 실제로 언제 가동되었는지의 기록으로, start_ts/end_ts 윈도로 주어진다. 히스토리언 결합이 대조하는 그 타임라인.
  • 시간적 결합(temporal join) — 일치 조건이 키 동등성이 아니라 시간 포함 검사(ts >= start AND ts < end)인 결합. 여기서는 각 판독값을 그 단계에 배정한다.
  • 반열린 구간(half-open interval) — 시작 순간은 포함하되 끝은 제외하는 윈도 [start, end). 단계 경계에 정확히 걸친 판독값이 새 단계에 세어지고 결코 양쪽 모두에 세어지지 않게 한다. 시간적 결합을 모호하지 않게 만드는 >= start AND < end 술어.
  • 뷰(view) — 이름으로 저장되어 가상 테이블처럼 동작하는 저장된 질의. 마치 테이블인 것처럼 SELECT하지만, 매 질의마다 기저 테이블로부터 그 행을 다시 계산한다. v_batch_sensorv_phase_summary가 뷰이다.
  • v_batch_sensor — 맥락화된 판독값. 네 개 밴드의 열한 개 열로, 그대로 통과해 들어온 여섯 개 원시 히스토리언 필드, s88.batch에서 결합된 세 개 배치 열, 그리고 시간적 결합이 즉석에서 파생하는 두 개 단계 열(phase_id, phase_name).
  • 자산 프레임워크/자산 모델(asset framework/asset model) — 히스토리언 태그 위에 얹힌, 공급사가 유지보수하는 장비 및 이벤트 모델(예: AVEVA PI AF)로, 데이터를 포인트 이름이 아니라 자산과 이벤트로 질의하게 한다. 여기서 구축한 두 SQL 뷰의, 검증되고 공급사 책임성을 갖춘 대응물.
  • 골든 배치(golden batch) — 정상 과거 배치들로부터 구축되어 새 런이 그에 대조되는 기준 궤적. v_phase_summary는 그것의 단계 키 구성 요소이다.
  • 연속 집계(continuous aggregate) — 하이퍼테이블 위의 TimescaleDB 구체화 뷰로, 새 데이터가 도착하면 증분적으로 갱신된다. 빠른 사전 롤업 요약에 사용된다.
  • 구체화 뷰(materialized view) — 결과가 디스크에 저장되어 명시적으로 REFRESH될 때까지 제공되는 PostgreSQL 뷰. 맥락화 결합을 캐시하는 데 사용된다.
  • postgres_fdw — PostgreSQL의 외부 데이터 래퍼로, 원격 서버의 테이블을 마치 로컬인 것처럼 노출하여 하나의 뷰가 서버를 가로질러 결합할 수 있게 한다.
  • 지속적 공정 검증(Continued Process Verification, CPV) — 공정 검증의 3단계로, 공정이 제어 상태에 머무른다는 지속적 보증이며, 맥락화되고 단계 정렬된 배치 데이터로 수행된다.
  • 예외 검토(review-by-exception) — 모든 값이 아니라 일탈만 검사하는 품질 검토 관행으로, 맥락화되고 예외를 표시하는 질의에 의해 가능해진다.
  • 배치 그룹화 교차 검증(batch-grouped cross-validation) — 한 런의 모든 행을 학습/검정 경계 한쪽에 두는 배치 단위 제외 검증. 유가식 런이 하나의 독립 관측이기 때문이며, batch_id가 소프트 센서를 그것이 학습한 배치로 채점하는 것을 막는 그룹화 키이다.
  • 적용 범위(applicability domain) — 모델이 학습한 입력의 영역. 64 Uncertain으로 표시되거나 그 영역 밖에 놓인 판독값은 모델의 신뢰 범위에서 걸러지며, 값 옆에 함께 따라오는 품질 바이트의 데이터 수준 유사물이다.
  • 공정 드리프트 대 모델 드리프트(process drift vs. model drift) — 살아 있는 배양물이 배치 간에 진짜로 떠도는 것(v_phase_summary가 측정하도록 만들어진 것) 대 프로브가 오염되며 소프트 센서가 쇠퇴하는 것(같은 단계 키 추세 위의 잔차 관리도가 잡아내도록 만들어진 것).
  • SHACL 셰이프(SHACL shape) — 맥락화된 판독값의 RDF 렌더링을 검증하는 Shapes Constraint Language 규칙. 그 단계 에지에 건 sh:maxCount 1은 어떤 판독값도 두 단계에 걸치지 않는다는 반열린 불변식을, sh:minCount 1은 어떤 것도 틈으로 빠지지 않는다는 것을 형식화한다.
  • 역량 질문(competency question) — 데이터 모델이 답해야 하는 평범한 말의 질문으로, 합격/불합격 인수 테스트로 쓰인다. "배치 X의 생산 단계 동안의 DO"가 그중 하나로, 여기서는 관계형으로, 19장에서는 그래프 질의로 답한다.

다음 이야기

우리는 모든 판독값에 의미를 부여했고, 시드된 골든 배치를 대상으로 한 실제 질의로 결합을 입증했습니다. 하지만 SQL 출력은 숫자의 벽이고, 공정 제어는 시각적 분야입니다. 18장 — Grafana로 시각화와 추세 보기에서 우리는 이 장의 v_batch_sensor 추세와 batch_phase 주석 질의를 가져다 프로비저닝된 코드형 대시보드(dashboards-as-code)로 바꿉니다. 레시피 단계가 추세 뒤에 칠해지고, 어제의 골든 배치가 오늘의 런 뒤에 흐릿하게 그려지는 배치 오버레이 대시보드입니다.