데이터 업데이트하기
데이터 업데이트하기 (Update data)
Apache Druid는 데이터와 인덱스를 시간별로 파티셔닝된 세그먼트 파일(segment files)에 저장해요. Druid가 세그먼트를 만든 뒤에는 그 내용을 수정할 수 없어요. 전체 세그먼트의 데이터를 교체하거나, 어떤 경우에는 세그먼트 데이터의 일부를 overshadow할 수 있어요.
출처: 문서
본문
Druid에서는 트랜잭션 데이터베이스에서 흔히 쓰는 기본 키나 dimensions 대신 시간 범위(time range)로 업데이트할 데이터를 지정해요. 지정된 교체 시간 범위 밖의 데이터는 영향을 받지 않아요. 이 Druid 기능을 사용해 트랜잭션 데이터베이스의 UPSERT 기능처럼 데이터 업데이트, 삽입, 삭제를 수행할 수 있어요.
이 튜토리얼은 Druid SQL의 REPLACE 함수를 OVERWRITE 절과 함께 사용해 기존 데이터를 업데이트하는 방법을 보여 드릴게요.
튜토리얼은 다음 사용 사례를 안내해요:
- 모든 데이터 덮어쓰기
- 특정 시간 범위의 레코드 덮어쓰기
- 부분 세그먼트 overshadowing으로 행 업데이트하기
모든 예시는 멀티-스테이지 쿼리(MSQ) 태스크 엔진을 사용해 SQL 문을 실행해요.
사전 준비 (Prerequisites)
이 튜토리얼의 단계를 따라가기 전에, Quickstart (local)에 설명된 대로 Druid를 다운로드하고 로컬 머신에서 실행 중이어야 해요. Druid 클러스터에 데이터를 로드할 필요는 없어요.
Druid에서 데이터를 쿼리하는 방법에 익숙해야 해요. 아직 안 하셨다면 먼저 Query data 튜토리얼을 진행해 주세요.
샘플 데이터 로드하기 (Load sample data)
REPLACE 와 EXTERN 함수를 사용해 샘플 데이터셋을 로드해 볼게요. Druid SQL에서 REPLACE 함수는 새 데이터소스를 만들거나 기존 데이터소스를 업데이트할 수 있어요.
Druid 웹 콘솔 (Druid web console)에서 Query 뷰로 이동해 다음 쿼리를 실행해 주세요:
REPLACE INTO "update_tutorial" OVERWRITE ALL
WITH "ext" AS (
SELECT *
FROM TABLE(
EXTERN(
'{"type":"inline","data":"{\"timestamp\":\"2024-01-01T07:01:35Z\",\"animal\":\"octopus\", \"number\":115}\n{\"timestamp\":\"2024-01-01T05:01:35Z\",\"animal\":\"mongoose\", \"number\":737}\n{\"timestamp\":\"2024-01-01T06:01:35Z\",\"animal\":\"snake\", \"number\":1234}\n{\"timestamp\":\"2024-01-01T01:01:35Z\",\"animal\":\"lion\", \"number\":300}\n{\"timestamp\":\"2024-01-02T07:01:35Z\",\"animal\":\"seahorse\", \"number\":115}\n{\"timestamp\":\"2024-01-02T05:01:35Z\",\"animal\":\"skunk\", \"number\":737}\n{\"timestamp\":\"2024-01-02T06:01:35Z\",\"animal\":\"iguana\", \"number\":1234}\n{\"timestamp\":\"2024-01-02T01:01:35Z\",\"animal\":\"opossum\", \"number\":300}"}',
'{"type":"json"}'
)
)
EXTEND ("timestamp" VARCHAR, "animal" VARCHAR, "number" BIGINT)
)
SELECT
TIME_PARSE("timestamp") AS "__time",
"animal",
"number"
FROM "ext"
PARTITIONED BY DAY
결과로 만들어진 update_tutorial 데이터소스에서 개별 행은 __time, animal, number 로 고유하게 식별돼요. 결과를 보려면 새 탭을 열고 다음 쿼리를 실행해 주세요:
SELECT * FROM "update_tutorial"
결과 보기 (View the results)
__time |
animal |
number |
|---|---|---|
| 2024-01-01T01:01:35.000Z | lion | 300 |
| 2024-01-01T05:01:35.000Z | mongoose | 737 |
| 2024-01-01T06:01:35.000Z | snake | 1234 |
| 2024-01-01T07:01:35.000Z | octopus | 115 |
| 2024-01-02T01:01:35.000Z | opossum | 300 |
| 2024-01-02T05:01:35.000Z | skunk | 737 |
| 2024-01-02T06:01:35.000Z | iguana | 1234 |
| 2024-01-02T07:01:35.000Z | seahorse | 115 |
결과에는 이틀에 걸친 여덟 마리 동물의 레코드가 들어 있어요.
모든 데이터 덮어쓰기 (Overwrite all data)
REPLACE 함수를 OVERWRITE ALL 과 함께 사용해 기존 데이터를 버리면서 전체 데이터소스를 새 데이터로 교체할 수 있어요.
웹 콘솔에서 새 탭을 열고 다음 쿼리를 실행해 update_tutorial 데이터소스 전체의 타임스탬프 데이터를 덮어써 주세요:
REPLACE INTO "update_tutorial" OVERWRITE ALL
WITH "ext" AS (SELECT *
FROM TABLE(
EXTERN(
'{"type":"inline","data":"{\"timestamp\":\"2024-01-02T07:01:35Z\",\"animal\":\"octopus\", \"number\":115}\n{\"timestamp\":\"2024-01-02T05:01:35Z\",\"animal\":\"mongoose\", \"number\":737}\n{\"timestamp\":\"2024-01-02T06:01:35Z\",\"animal\":\"snake\", \"number\":1234}\n{\"timestamp\":\"2024-01-02T01:01:35Z\",\"animal\":\"lion\", \"number\":300}\n{\"timestamp\":\"2024-01-03T07:01:35Z\",\"animal\":\"seahorse\", \"number\":115}\n{\"timestamp\":\"2024-01-03T05:01:35Z\",\"animal\":\"skunk\", \"number\":737}\n{\"timestamp\":\"2024-01-03T06:01:35Z\",\"animal\":\"iguana\", \"number\":1234}\n{\"timestamp\":\"2024-01-03T01:01:35Z\",\"animal\":\"opossum\", \"number\":300}"}',
'{"type":"json"}'
))
EXTEND ("timestamp" VARCHAR, "animal" VARCHAR, "number" BIGINT)
)
SELECT
TIME_PARSE("timestamp") AS "__time",
"animal",
"number"
FROM "ext"
PARTITIONED BY DAY
결과 보기 (View the results)
__time |
animal |
number |
|---|---|---|
| 2024-01-02T01:01:35.000Z | lion | 300 |
| 2024-01-02T05:01:35.000Z | mongoose | 737 |
| 2024-01-02T06:01:35.000Z | snake | 1234 |
| 2024-01-02T07:01:35.000Z | octopus | 115 |
| 2024-01-03T01:01:35.000Z | opossum | 300 |
| 2024-01-03T05:01:35.000Z | skunk | 737 |
| 2024-01-03T06:01:35.000Z | iguana | 1234 |
| 2024-01-03T07:01:35.000Z | seahorse | 115 |
__time 컬럼의 값이 하루 뒤로 바뀐 것에 주목해 주세요.
특정 시간 범위의 레코드 덮어쓰기 (Overwrite records for a specific time range)
REPLACE 함수로 데이터소스의 특정 시간 범위를 덮어쓸 수 있어요. 특정 시간 범위를 덮어쓸 때 그 시간 범위는 PARTITIONED BY 절에 지정된 granularity와 정렬되어야 해요.
웹 콘솔에서 새 탭을 열고 다음 쿼리를 실행해 새 행을 삽입하고 특정 행들을 업데이트해 주세요. OVERWRITE WHERE 절이 2024-01-03 날짜의 레코드만 업데이트하도록 쿼리에 지시한다는 점에 주목해 주세요.
REPLACE INTO "update_tutorial"
OVERWRITE WHERE "__time" >= TIMESTAMP'2024-01-03 00:00:00' AND "__time" < TIMESTAMP'2024-01-04 00:00:00'
WITH "ext" AS (SELECT *
FROM TABLE(
EXTERN(
'{"type":"inline","data":"{\"timestamp\":\"2024-01-03T01:01:35Z\",\"animal\":\"tiger\", \"number\":300}\n{\"timestamp\":\"2024-01-03T07:01:35Z\",\"animal\":\"seahorse\", \"number\":500}\n{\"timestamp\":\"2024-01-03T05:01:35Z\",\"animal\":\"polecat\", \"number\":626}\n{\"timestamp\":\"2024-01-03T06:01:35Z\",\"animal\":\"iguana\", \"number\":300}\n{\"timestamp\":\"2024-01-03T01:01:35Z\",\"animal\":\"flamingo\", \"number\":999}"}',
'{"type":"json"}'
))
EXTEND ("timestamp" VARCHAR, "animal" VARCHAR, "number" BIGINT)
)
SELECT
TIME_PARSE("timestamp") AS "__time",
"animal",
"number"
FROM "ext"
PARTITIONED BY DAY
결과 보기 (View the results)
__time |
animal |
number |
|---|---|---|
| 2024-01-02T01:01:35.000Z | lion | 300 |
| 2024-01-02T05:01:35.000Z | mongoose | 737 |
| 2024-01-02T06:01:35.000Z | snake | 1234 |
| 2024-01-02T07:01:35.000Z | octopus | 115 |
| 2024-01-03T01:01:35.000Z | flamingo | 999 |
| 2024-01-03T01:01:35.000Z | tiger | 300 |
| 2024-01-03T05:01:35.000Z | polecat | 626 |
| 2024-01-03T06:01:35.000Z | iguana | 300 |
| 2024-01-03T07:01:35.000Z | seahorse | 500 |
결과 데이터소스의 변경 사항에 주목해 주세요:
flamingo라는 새 행이 생겼어요.opossum행이tiger값을 가져요.skunk행이polecat값을 가져요.iguana와seahorse행은 서로 다른 number를 가져요.
부분 세그먼트 overshadowing으로 행 업데이트하기 (Update a row using partial segment overshadowing)
Druid에서는 특정 파티션 안의 세그먼트 전체 또는 세그먼트 일부에 대해 이전 데이터 위에 새 데이터를 겹칠(overlay) 수 있어요. 이 기능을 overshadowing이라고 해요.
부분 overshadowing을 사용하면, 기존 데이터 위에 더 작은 시간 granularity의 세그먼트를 추가해서 단일 행을 업데이트할 수 있어요. 이는 전체 시간 청크를 교체하는 더 흔한 접근 방식의 덜 흔한 변형이에요.
다음 예시는 혼합 세그먼트 granularity로 부분 overshadowing을 사용해 데이터를 업데이트하는 방법을 보여 줘요. 예시에 대한 다음 중요 사항들을 확인해 주세요:
- 쿼리가 특정 number 행의 단일 레코드를 업데이트해요.
- 원본 데이터소스는
DAY세그먼트 granularity를 사용해요. - 새 데이터 세그먼트는
HOURgranularity이고 기존 데이터보다 작은 시간 범위를 나타내요. OVERWRITE WHERE절과WHERE TIME_IN_INTERVAL절은 각각 업데이트가 발생하는 대상 위치와 업데이트의 소스를 지정해요.- 쿼리는 지정된 구간 안의 모든 것을 교체해요. 그 구간의 데이터 하위 집합만 업데이트하려면, 변경하려는 것만 바꾸면서 모든 레코드를 carry forward해야 해요.
SELECT목록에서 CASE 함수를 사용하면 그렇게 할 수 있어요.
REPLACE INTO "update_tutorial"
OVERWRITE
WHERE "__time" >= TIMESTAMP'2024-01-03 05:00:00' AND "__time" < TIMESTAMP'2024-01-03 06:00:00'
SELECT
"__time",
"animal",
CAST(486 AS BIGINT) AS "number"
FROM "update_tutorial"
WHERE TIME_IN_INTERVAL("__time", '2024-01-03T05:01:35Z/PT1S')
PARTITIONED BY FLOOR(__time TO HOUR)
결과 보기 (View the results)
__time |
animal |
number |
|---|---|---|
| 2024-01-02T01:01:35.000Z | lion | 300 |
| 2024-01-02T05:01:35.000Z | mongoose | 737 |
| 2024-01-02T06:01:35.000Z | snake | 1234 |
| 2024-01-02T07:01:35.000Z | octopus | 115 |
| 2024-01-03T01:01:35.000Z | flamingo | 999 |
| 2024-01-03T01:01:35.000Z | tiger | 300 |
| 2024-01-03T05:01:35.000Z | polecat | 486 |
| 2024-01-03T06:01:35.000Z | iguana | 300 |
| 2024-01-03T07:01:35.000Z | seahorse | 500 |
polecat 의 number가 626에서 486으로 바뀐 것에 주목해 주세요.
부분 세그먼트 overshadowing을 여러 번 수행하면 쿼리 성능에 영향을 줄 수 있는 세그먼트 파편화(fragmentation)가 생길 수 있어요. 파편화를 바로잡으려면 컴팩션(compaction)을 사용해 주세요.
더 알아보기 (Learn more)
자세한 내용은 다음 주제를 참고해 주세요:
- Data updates — Druid에서 데이터 업데이트 개요.
- Load files with SQL-based ingestion — 외부에 호스팅된 데이터를 참조하는 쿼리 생성.
- Overwrite data with REPLACE — MSQ 태스크 엔진이 SQL
REPLACE쿼리를 실행하는 방법.