Druid 통합
Druid 통합 (Integration)
Hive와 Druid를 통합한 기능에 대한 문서예요. Hive 2.2.0(HIVE-14217)에서 소개되었으며, 처음에는 그 시점의 최신 안정 릴리스인 Druid 0.9.1.1과 호환되었습니다. 이 통합을 통해 Hive에서 데이터를 Druid로 인덱싱하고, Hive에서 Druid 데이터소스를 쿼리할 수 있게 됩니다.
출처: 문서
본문
목표 (Objectives)
주요 목표는 Hive에서 Druid로 데이터를 인덱싱하고, Hive에서 Druid 데이터소스를 쿼리하는 것입니다. 이 작업이 완성되면 Druid와 Hive 양쪽에 이점이 있어요.
- Hive에서 OLAP 쿼리의 효율적 실행: Druid는 이벤트 데이터에 대한 OLAP 쿼리 실행에 특화된 시스템이에요. Hive는 이 타입의 쿼리 실행에서 그 효율성을 활용할 수 있습니다.
- Druid 위에 SQL 인터페이스 도입: Druid 쿼리는 JSON으로 표현되고 HTTP를 통한 REST API로 쿼리돼요. 사용자가 Druid에 저장된 Hive 테이블을 선언하면, 입력된 Hive SQL 쿼리에서 Druid JSON 쿼리를 투명하게 생성할 수 있게 됩니다.
- Druid 데이터에 복잡한 연산 실행: Druid가 아직 네이티브로 지원하지 않는 여러 연산(예: join)이 있습니다. Hive를 Druid 위에 두면 Druid 데이터소스에서 더 복잡한 쿼리를 실행할 수 있어요.
- Hive를 사용해 Druid에 복잡한 쿼리 결과 인덱싱: 현재 Druid 인덱싱은 보통 MapReduce 작업으로 이뤄져요. Hive가 주어진 쿼리의 결과를 새 테이블이나 구체화된 뷰(HIVE-10459)로 Druid에 직접 인덱싱하고, 그 데이터셋을 즉시 쿼리·사용하도록 할 수 있습니다.
HIVE-14217에서 시작된 초기 구현은 1) Hive에서 이미 Druid에 저장된 데이터의 발견, 2) Druid의 고급 쿼리 기능을 활용해 그 데이터를 쿼리하는 것에 집중했어요. 예를 들어 가능한 한 많은 계산을 Druid로 푸시하고, Druid가 특히 효율적인 쿼리 타입(예: timeseries, groupBy)을 인식하는 데 특히 중점을 뒀습니다. 첫 단계 완료 후의 향후 작업은 HIVE-14473에 나열되어 있어요.
사전 지식 (Preliminaries)
Druid: Druid는 이벤트 데이터에 대한 비즈니스 인텔리전스(OLAP) 쿼리를 위해 설계된 오픈소스 분석 데이터 저장소예요. 낮은 지연(실시간) 데이터 수집, 유연한 데이터 탐색, 빠른 데이터 집계를 제공합니다. 기존 Druid 배포는 수조 개의 이벤트와 페타바이트의 데이터로 확장됐어요. Druid는 사용자 대면 분석 애플리케이션을 구동하는 데 가장 흔히 사용됩니다.
Storage Handlers: Hive Storage Handlers에 대한 개요가 있으며, Hive와 Druid의 통합은 그 프레임워크에 의존합니다.
사용법 (Usage)
예시에는 Druid의 quickstart 튜토리얼에 포함된 wikiticker 데이터셋을 사용합니다.
Hive에서 Druid 데이터소스의 발견과 관리 (Discovery and management of Druid datasources from Hive)
기존 Druid 데이터소스에 연결된 테이블 생성
앞서 언급한 wikiticker 데이터셋이 이미 Druid에 저장되어 있고, Druid broker 주소가 10.5.0.10:8082라고 가정해요. 먼저 Hive 속성 hive.druid.broker.address.default를 구성에서 broker 주소를 가리키도록 설정해야 합니다.
SET hive.druid.broker.address.default=10.5.0.10:8082;
그런 다음 Hive에서 쿼리할 수 있는 테이블을 만들기 위해 다음 문을 실행합니다.
CREATE EXTERNAL TABLE druid_table_1
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler'
TBLPROPERTIES ("druid.datasource" = "wikiticker");
druid.datasource 속성을 사용해 TBLPROPERTIES로 데이터소스를 지정해야 한다는 점을 기억하세요. 또 데이터가 Druid에 저장되므로 테이블을 EXTERNAL로 만들어야 해요. 테이블은 쿼리를 표현하는 데 쓰는 논리적 엔티티일 뿐이며, 테이블을 만들어도 데이터 이동은 없습니다. 실제로 이 문을 실행하면 Hive가 Druid에 세그먼트 메타데이터 쿼리를 보내 데이터소스의 스키마(컬럼과 타입)를 발견해요. 행 수 같은 통계 정보의 검색은 로드맵에 있지만 아직 지원되지 않습니다.
마지막으로 기본 broker 주소의 Hive 속성 값을 바꾸면, 주소가 테이블에 저장되지 않으므로 이 테이블의 쿼리가 자동으로 새 broker 주소에 대해 실행됩니다.
DESCRIBE 문을 실행하면 테이블 정보를 볼 수 있어요.
hive> DESCRIBE FORMATTED druid_table_1;
OK
# col_name data_type comment
__time timestamp from deserializer
added bigint from deserializer
channel string from deserializer
cityname string from deserializer
comment string from deserializer
count bigint from deserializer
countryisocode string from deserializer
countryname string from deserializer
deleted bigint from deserializer
delta bigint from deserializer
isanonymous string from deserializer
isminor string from deserializer
isnew string from deserializer
isrobot string from deserializer
isunpatrolled string from deserializer
metrocode string from deserializer
namespace string from deserializer
page string from deserializer
regionisocode string from deserializer
regionname string from deserializer
user string from deserializer
user_unique string from deserializer
# Detailed Table Information
Database: druid
Owner: user1
CreateTime: Thu Aug 18 19:09:10 BST 2016
LastAccessTime: UNKNOWN
Retention: 0
Location: hdfs:/tmp/user1/hive/warehouse/druid.db/druid_table_1
Table Type: EXTERNAL_TABLE
Table Parameters:
COLUMN_STATS_ACCURATE {\"BASIC_STATS\":\"true\"}
EXTERNAL TRUE
druid.datasource wikiticker
numFiles 0
numRows 0
rawDataSize 0
storage_handler org.apache.hadoop.hive.druid.DruidStorageHandler
totalSize 0
transient_lastDdlTime 1471543750
# Storage Information
SerDe Library: org.apache.hadoop.hive.druid.serde.DruidSerDe
InputFormat: null
OutputFormat: null
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params: serialization.format 1
Time taken: 0.111 seconds, Fetched: 55 row(s)
Druid 카테고리에 해당하는 세 가지 컬럼 그룹이 있는 것을 볼 수 있어요. Druid에서 필수인 타임스탬프 컬럼(__time), 디멘전(dimension) 컬럼(타입이 STRING), 메트릭(metrics) 컬럼(나머지 전부)입니다.
Hive에서 Druid 데이터소스 생성
Hive에서 Druid 데이터소스의 데이터를 관리하고 싶다면 여러 가능한 시나리오가 있어요. 예를 들어 CREATE TABLE 문으로 Druid에 의해 백업된 빈 테이블을 만들고, INSERT와 INSERT OVERWRITE Hive 문으로 각각 데이터를 추가·덮어쓸 수 있습니다.
CREATE EXTERNAL TABLE druid_table_1
(`__time` TIMESTAMP, `dimension1` STRING, `dimension2` STRING, `metric1` INT, `metric2` FLOAT)
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler';
또 다른 시나리오는 데이터가 Hive 테이블에 있고, SQL 쿼리 워크로드를 가속화하기 위해 Hive에서 전처리해 Druid 데이터소스를 만드는 것입니다. 이것은 Create Table As Select(CTAS) 문으로 할 수 있어요.
CREATE EXTERNAL TABLE druid_table_1
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler'
AS
<select `timecolumn` as `__time`, `dimension1`, `dimension2`, `metric1`, `metric2`....>;
두 문 모두에서 컬럼 타입(CREATE TABLE 문에서는 정적 지정, CTAS 문에서는 쿼리 결과에서 추론)이 해당 Druid 컬럼 카테고리를 추론하는 데 사용됩니다. 또 druid.datasource 속성 값을 지정하지 않으면, Hive가 자동으로 테이블의 완전한 이름(FQN)을 사용해 같은 이름의 데이터소스를 만듭니다.
Version Info 2.2.0 — 데이터를 hive로 관리할 때의 CREATE TABLE 구문:
CREATE TABLE druid_table_1
(`__time` TIMESTAMP, `dimension1` STRING, `dimension2` STRING, `metric1` INT, `metric2` FLOAT)
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler';
NOTE: Hive 3.0.0 이전에는 EXTERNAL 테이블을 사용하지 않고
druid.datasource속성 값을 지정하지 않아요. 3.0.0+ 버전에서는 모든 Druid 테이블이 EXTERNAL입니다 (HIVE-20085).
Hive에서 Druid Kafka 수집
Druid Kafka Indexing Service와의 통합은 Hive 3.0.0(HIVE-18976)에서 도입되었습니다. Druid Kafka Indexing Service는 Kafka indexing 태스크의 생성·수명을 관리해 Kafka 토픽에서 exactly-once 수집을 지원해요. 아래처럼 Hive CREATE TABLE 문으로 Druid Kafka 수집을 관리할 수 있습니다.
CREATE EXTERNAL TABLE druid_kafka_table_1(`__time` timestamp,`dimension1` string, `dimension1` string, `metric1` int, `metric2 double ....)
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler'
TBLPROPERTIES (
"kafka.bootstrap.servers" = "localhost:9092",
"kafka.topic" = "topic1",
"druid.kafka.ingestion.useEarliestOffset" = "true",
"druid.kafka.ingestion.maxRowsInMemory" = "5",
"druid.kafka.ingestion.startDelay" = "PT1S",
"druid.kafka.ingestion.period" = "PT1S",
"druid.kafka.ingestion.consumer.retries" = "2"
);
kafka 토픽 이름과 kafka bootstrap 서버를 테이블 속성으로 지정한 것을 볼 수 있어요. Druid Kafka Indexing Service를 위한 다른 튜닝도 druid.kafka.ingestion. 접두사를 붙여 지정할 수 있습니다. 예를 들어 druid ingestion 태스크의 지속 시간을 구성하려면 "druid.kafka.ingestion.taskDuration" = "PT60S"를 테이블 속성으로 추가할 수 있어요.
Druid Kafka 수집 시작/중지/리셋
다음 SQL 문으로 druid kafka ingestion을 시작/중지/리셋할 수 있습니다.
ALTER TABLE druid_kafka_test SET TBLPROPERTIES('druid.kafka.ingestion' = 'START');
ALTER TABLE druid_kafka_test SET TBLPROPERTIES('druid.kafka.ingestion' = 'STOP');
ALTER TABLE druid_kafka_test SET TBLPROPERTIES('druid.kafka.ingestion' = 'RESET');
참고: ingestion을 리셋하면 druid가 유지하는 kafka consumer offset이 다음 오프셋으로 리셋돼요. druid가 유지하는 consumer offset은 druid.kafka.ingestion.useEarliestOffset 테이블 속성에 따라 earliest나 latest offset으로 리셋됩니다. 이로 인해 중복/누락 이벤트가 생길 수 있어요. 보통 현재 consumer offset의 Kafka 메시지가 더 이상 소비에 사용할 수 없어 Druid로 수집되지 않을 때만 kafka ingestion을 리셋해야 합니다.
INSERT, INSERT OVERWRITE, DROP 문
- Version 2.2.0: 이 문들은 Druid에 의해 백업된 Hive managed 테이블(외부 아님)에서 지원됩니다.
- 3.0.0+ 버전: 모든 Druid 테이블이 EXTERNAL(HIVE-20085)이며, 이 문들은 어떤 테이블에서든 지원됩니다.
Hive에서 Druid 쿼리 (Querying Druid from Hive)
DruidStorageHandler로 Druid에 저장된 첫 테이블을 만들면 Druid에 대해 쿼리를 실행할 준비가 됩니다. Druid 테이블 위에 쿼리를 표현하면, Hive는 가능한 한 많은 계산을 Druid로 푸시해 효율적으로 실행되도록 쿼리를 재작성하려 해요.
이 작업은 Apache Calcite 기반의 비용 최적화기(cost optimizer)가 수행합니다. 플랜의 패턴을 식별하고 규칙을 적용해 입력 쿼리를 (가능하면) 더 많은 연산이 Druid에서 실행되는 새 동등 쿼리로 재작성합니다. HIVE-14217에서 CALCITE-1121에서 시작된 작업 위에 최적화기 확장을 구현했으며, 더 복잡한 쿼리 패턴(timeseries 쿼리)을 식별하고, 시간 디멘전의 필터를 Druid интервals로 변환하고, limit을 Druid select 쿼리로 푸시하는 것 등의 로직을 확장합니다.
현재 timeseries, groupBy, select 쿼리 인식을 지원합니다. 최적화를 완료하면 Druid가 실행해야 하는 operator의 (서브)플랜이 유효한 Druid JSON 쿼리로 변환되고, Hive 물리적 TableScan 연산자의 속성으로 전달됩니다. Druid 쿼리는 TableScan 연산자 안에서 실행되며, Druid 쿼리 결과에서 레코드를 생성합니다.
timeseries와 groupBy에는 해당 Druid 쿼리의 단일 Hive split을 생성하고 그로부터 레코드를 만듭니다. 따라서 이 경우 병렬도는 1이에요. 하지만 limit 없는 단순 select 쿼리(필터나 프로젝션을 여전히 포함할 수는 있지만)는 원본 쿼리를 x개의 쿼리로 분할하고 각각 하나의 split을 생성해, 보통 많은 결과를 반환하는 이 쿼리들의 병렬도를 x로 높입니다.
쿼리에 따라 Druid로 계산을 푸시하지 못할 수도 있어요. 하지만 계약(contract)은 쿼리가 항상 실행되어야 한다는 것입니다. 따라서 그런 경우 Hive는 Druid에 select 쿼리를 보내는데, 기본적으로 Druid에서 모든 세그먼트를 읽고 레코드를 생성한 다음 그 레코드에 나머지 Hive 연산을 실행합니다. 이것은 비용 최적화기가 비활성화된 경우(권장하지 않음)에도 따르는 접근 방식입니다.
Druid에서 완전히 실행되는 쿼리 (Queries completely executed in Druid)
먼저 완전히 Druid로 푸시할 수 있는 쿼리를 다룹니다. 이 경우 we 위에 TableScan과 Fetch 연산자로 이루어진 단순한 플랜이 됩니다. 따라서 실행을 위해 컨테이너를 띄우는 오버헤드가 없어요.
Select 쿼리
가장 단순한 Druid 쿼리 타입인 select 쿼리부터 시작합니다. 기본적으로 select 쿼리는 데이터소스의 스캔 연산과 동등하지만, projection, filter, limit 같은 연산은 여전히 이 타입 쿼리로 푸시할 수 있습니다.
테이블의 모든 컬럼으로 10행을 가져오는 단순 select 쿼리를 생각해보세요.
SELECT * FROM druid_table_1 LIMIT 10;
Hive 플랜은 다음과 같습니다.
hive> EXPLAIN
> SELECT * FROM druid_table_1 LIMIT 10;
OK
Plan optimized by CBO.
Stage-0
Fetch Operator
limit:-1
Select Operator [SEL_1]
Output:["_col0","_col1",...]
TableScan [TS_0]
Output:[...],properties:{"druid.query.json":"{\"queryType\":\"select\",\"dataSource\":\"wikiticker\",...}","druid.query.type":"select"}
Druid 쿼리가 TableScan에 붙은 속성에 있음을 볼 수 있어요. 가독성을 위해 올바르게 포맷하면:
{
"queryType":"select",
"dataSource":"wikiticker",
"descending":"false",
"intervals":["-146136543-09-08T08:22:17.096-00:01:15/146140482-04-24T16:36:27.903+01:00"],
"dimensions":["channel","cityname","comment","countryisocode","countryname","isanonymous","isminor","isnew","isrobot","isunpatrolled","metrocode","namespace","page","regionisocode","regionname","user","user_unique"],
"metrics":["added","count","deleted","delta"],
"pagingSpec":{"threshold":10}
}
limit을 Druid 쿼리(threshold)로 푸시하는 것을 볼 수 있어요. 또 데이터소스의 타임스탬프 디멘전에 필터를 지정하지 않으므로, (−∞,+∞) 범위를 덮는 interval을 생성합니다.
Druid에서 타임스탬프 컬럼은 중심 역할을 해요. 실제로 Druid는 모든 쿼리에서 intervals 속성을 사용해 시간 디멘전에 필터링할 수 있게 합니다. 이것은 매우 중요한데, 시간 interval이 Druid 데이터를 저장하는 노드를 결정하기 때문입니다. 따라서 정밀한 범위를 지정하면 특정 쿼리가 맞는 노드 수를 최소화합니다.
Druid PR-2880에서 영감을 받아, 쿼리의 논리 플랜에서 필터 조건으로부터 intervals 추출을 구현했어요. 예를 들어 다음 쿼리를 고려해보세요.
SELECT `__time`
FROM druid_table_1
WHERE `__time` >= '2010-01-01 00:00:00' AND `__time` <= '2011-01-01 00:00:00'
LIMIT 10;
위 SQL 쿼리에 생성된 Druid 쿼리는 다음과 같습니다 (단순한 TableScan 연산자라 플랜은 생략).
{
"queryType":"select",
"dataSource":"wikiticker",
"descending":"false",
"intervals":["2010-01-01T00:00:00.000Z/2011-01-01T00:00:00.001Z"],
"dimensions":[],
"metrics":[],
"pagingSpec":{"threshold":10}
}
지정된 날짜에 대한 interval을 올바르게 추론하는 것을 볼 수 있어요. Druid에서 interval의 시작 날짜는 포함되지만 종료 날짜는 포함되지 않기 때문입니다. 여러 interval 범위 인식도 지원합니다. 예:
SELECT `__time`
FROM druid_table_1
WHERE (`__time` BETWEEN '2010-01-01 00:00:00' AND '2011-01-01 00:00:00')
OR (`__time` BETWEEN '2012-01-01 00:00:00' AND '2013-01-01 00:00:00')
LIMIT 10;
겹치는 interval도 추론할 수 있어요. 마지막으로 시간 디멘전에 지정되지 않은 필터는 유효한 Druid 필터로 변환되어 filter 속성을 사용해 쿼리 안에 포함됩니다.
Timeseries 쿼리
Timeseries는 Druid가 매우 효율적으로 실행할 수 있는 쿼리 타입 중 하나예요. 다음 SQL 쿼리는 Druid timeseries 쿼리로 직접 변환됩니다.
-- GRANULARITY: MONTH
SELECT `floor_month`(`__time`), max(delta), sum(added)
FROM druid_table_1
GROUP BY `floor_month`(`__time`);
기본적으로 주어진 시간 단위(granularity)로 group by 하고 각 결과 그룹에 대해 집계 결과를 계산합니다. 특히 타임스탬프 디멘전 __time에 대한 floor_month 함수는 Druid의 월 단위 형식을 나타내요. 현재 floor_year, floor_quarter, floor_month, floor_week, floor_day, floor_hour, floor_minute, floor_second 단위를 지원합니다. 추가로 all과 none이라는 두 가지 특수한 단위도 지원하며 아래에서 설명합니다. duration과 period 단위 같은 다른 중요한 Druid 커스텀 단위 구문을 지원하도록 통합 작업을 확장할 계획입니다.
생성된 Druid 쿼리:
{
"queryType":"timeseries",
"dataSource":"wikiticker",
"descending":"false",
"granularity":"MONTH",
"aggregations":[
{"type":"longMax", "name":"$f1", "fieldName":"delta"},
{"type":"longSum", "name":"$f2", "fieldName":"added"}
],
"intervals":["-146136543-09-08T08:22:17.096-00:01:15/146140482-04-24T16:36:27.903+01:00"]
}
Druid 쿼리의 granularity가 MONTH인 것을 볼 수 있어요. 다소 특수한 all 단위의 경우는 예시로 소개합니다. 다음 쿼리를 고려해보세요.
-- GRANULARITY: ALL
SELECT max(delta), sum(added)
FROM druid_table_1;
전체 데이터셋에 대해 집계를 하므로 granularity all의 timeseries 쿼리로 변환됩니다.
{
"queryType":"timeseries",
"dataSource":"wikiticker",
"descending":"false",
"granularity":"ALL",
"aggregations":[
{"type":"longMax", "name":"$f1", "fieldName":"delta"},
{"type":"longSum", "name":"$f2", "fieldName":"added"}
],
"intervals":["-146136543-09-08T08:22:17.096-00:01:15/146140482-04-24T16:36:27.903+01:00"]
}
GroupBy 쿼리
현재 지원하는 마지막 쿼리 타입은 groupBy입니다. 이 종류의 쿼리는 timeseries보다 표현력이 더 높지만 성능은 떨어져요. 따라서 timeseries로 변환할 수 없을 때만 groupBy 쿼리로 폴백합니다. 예를 들어 다음 SQL 쿼리는 Druid groupBy 쿼리를 생성합니다.
SELECT max(delta), sum(added)
FROM druid_table_1
GROUP BY `channel`, `user`;
{
"queryType":"groupBy",
"dataSource":"wikiticker",
"granularity":"ALL",
"dimensions":["channel","user"],
"aggregations":[
{"type":"longMax","name":"$f2","fieldName":"delta"},
{"type":"longSum","name":"$f3","fieldName":"added"}],
"intervals":["-146136543-09-08T08:22:17.096-00:01:15/146140482-04-24T16:36:27.903+01:00"]
}
Druid와 Hive를 가로지르는 쿼리 (Queries across Druid and Hive)
마지막으로 Druid와 Hive를 가로질러 실행되는 쿼리 예시를 제공합니다. Hive에 몇 가지 데이터로 두 번째 테이블을 만들어 볼게요.
CREATE TABLE hive_table_1 (col1 INT, col2 STRING);
INSERT INTO hive_table_1 VALUES(1, '#en.wikipedia');
다음 쿼리를 실행하고 싶다고 가정합니다.
SELECT a.channel, b.col1
FROM
(
SELECT `channel`, max(delta) as m, sum(added)
FROM druid_table_1
GROUP BY `channel`, `floor_year`(`__time`)
ORDER BY m DESC
LIMIT 1000
) a
JOIN
(
SELECT col1, col2
FROM hive_table_1
) b
ON a.channel = b.col2;
이 쿼리는 channel과 col2 컬럼의 단순한 join이에요. 서브쿼리 a는 Druid에서 groupBy 쿼리로 완전히 실행됩니다. 그 결과는 Hive에서 서브쿼리 b의 결과와 join 됩니다. 실행 결과는 다음과 같습니다.
#en.wikipedia 1
오픈 이슈 (Open Issues, JIRA)
주요 오픈 이슈는 다음과 같습니다. (전체 28개 중 20개 표시)
- HIVE-14473 Druid integration II (New Feature)
- HIVE-14543 Create Druid table without specifying data source
- HIVE-14597 Support for Druid custom granularities
- HIVE-14722 Support creating vector row batches from Druid
- HIVE-15584 Early bail out when we use CTAS and Druid source already exists
- HIVE-15640 Hive/Druid integration: null handling for metrics
- HIVE-16121 Add flag to allow approximate results coming from Druid
- HIVE-16816 Chained Group by support for druid
- HIVE-17716 Not pushing postaggregations into Druid due to CAST on constant
- HIVE-18668 Really shade guava in ql
- HIVE-18731 Add Documentations about this feature
- HIVE-19044 Duplicate field names within Druid Query Generated by Calcite plan
- HIVE-19201 Hive doesn't read Druid data correctly
- HIVE-19300 Skip Druid/JDBC rules in optimizer when there are no Druid/JDBC sources
- HIVE-19672 Column Names mismatch between native Druid Tables and Hive External table map
- HIVE-20426 Upload Druid Test Runner logs from Build Slaves
- HIVE-20468 Add ability to skip creating druid bitmap indexes for specific string dimensions
- HIVE-20469 Do not rollup PK/FK columns when indexing to druid
- HIVE-20687 Cancel Running Druid Query when a hive query is cancelled
- HIVE-20997 Make Druid Cluster start on random ports
더 알아보기 (Learn more)
Hive↔Druid 통합은 Storage Handler 프레임워크 위에서 동작하며, Calcite 비용 최적화기가 가능한 한 많은 계산을 Druid로 푸시해요. 타임스탬프 디멘전 필터를 Druid interval로 자동 변환하는 것과 timeseries/grupBy 쿼리 인식이 핵심 기능입니다.