쿼리 차원(Query dimensions)
쿼리 차원(Query dimensions)
Apache Druid는 Druid SQL과 네이티브 쿼리 두 가지 쿼리 언어를 지원해요. 이 문서는 네이티브 언어를 설명합니다. 다음 JSON 필드는 쿼리에서 차원 값을 조작하는 데 사용될 수 있어요. 이 문서에서는 DimensionSpec과 각종 추출 함수(Extraction Functions)를 설명드릴게요.
출처: 문서
본문
Apache Druid는 Druid SQL과 네이티브 쿼리 두 가지 쿼리 언어를 지원합니다. 이 문서는 네이티브 언어를 설명해요. 다음 JSON 필드는 쿼리에서 차원 값을 조작하는 데 사용될 수 있습니다.
DimensionSpec
DimensionSpec은 집계 이전에 차원 값을 어떻게 변환할지 정의합니다.
기본 DimensionSpec(Default DimensionSpec)
차원 값을 그대로 반환하고 선택적으로 차원 이름을 변경합니다.
{
"type" : "default",
"dimension" : <dimension>,
"outputName": <output_name>,
"outputType": <"STRING"|"LONG"|"FLOAT">
}
숫자 컬럼에 DimensionSpec을 지정할 때는 outputType 필드에 컬럼의 타입을 포함해야 합니다. outputType은 지정하지 않으면 기본적으로 STRING입니다. 자세한 내용은 Output Types를 참고하세요.
추출 DimensionSpec(Extraction DimensionSpec)
주어진 추출 함수를 사용해 변환된 차원 값을 반환합니다.
{
"type" : "extraction",
"dimension" : <dimension>,
"outputName" : <output_name>,
"outputType": <"STRING"|"LONG"|"FLOAT">,
"extractionFn" : <extraction_function>
}
ExtractionDimensionSpec에서 outputType을 지정해 병합 전에 결과에 타입 변환을 적용할 수 있어요. outputType은 지정하지 않으면 기본적으로 STRING입니다. 자세한 내용은 Output Types 섹션을 참고하세요.
필터링된 DimensionSpec(Filtered DimensionSpecs)
필터링된 DimensionSpec은 다중값 차원(multi-value dimensions)에서만 유용합니다. Apache Druid에 ["v1", "v2", "v3"] 값을 가진 다중값 차원이 있는 행이 있고, "v1" 값에 대한 쿼리 필터로 그 차원을 기준으로 그룹화하는 groupBy/topN 쿼리를 보낸다고 가정해 봅시다. 응답에서 "v1", "v2", "v3"을 포함한 3개의 행을 받게 됩니다. 이 동작은 일부 사용 사례에서는 직관적이지 않을 수 있어요.
이것은 Druid가 내부적으로 비트맵에 "쿼리 필터"를 사용해 쿼리 결과 처리에 포함할 행을 매칭하기 때문에 발생합니다. 다중값 차원의 경우 "쿼리 필터"는 포함(contains) 검사처럼 동작해 차원 값이 ["v1", "v2", "v3"]인 행과 매칭됩니다. 자세한 내용은 segment 문서의 "Multi-value columns" 섹션을 참고하세요. 그런 다음 groupBy/topN 처리 파이프라인이 모든 다중값 차원을 "explode"해서 "v1", "v2", "v3" 각각에 대해 3개의 행을 만듭니다.
처리할 행을 효율적으로 선택하는 "쿼리 필터"에 더해, 필터링된 dimension spec을 사용해 다중값 차원의 값 안에서 특정 값을 필터링할 수 있어요. 이 dimension spec들은 위임(delegate) DimensionSpec과 필터링 기준(criteria)을 받습니다. "exploded"된 행 중 주어진 필터링 기준과 일치하는 행만 쿼리 결과로 반환됩니다.
다음 필터링된 dimension spec은 isWhitelist 속성 값에 따라 포함하거나 제외할 값을 정의합니다.
{ "type" : "listFiltered", "delegate" : <dimensionSpec>, "values": <array of strings>, "isWhitelist": <optional attribute for true/false, default is true> }
다음 필터링된 dimension spec은 regex와 일치하는 값만 보존합니다. 포함/제외 사용 사례에는 더 빠른 listFiltered 함수를 사용해야 합니다.
{ "type" : "regexFiltered", "delegate" : <dimensionSpec>, "pattern": <java regex pattern> }
다음 필터링된 dimension spec은 같은 접두사로 시작하는 값만 보존합니다.
{ "type" : "prefixFiltered", "delegate" : <dimensionSpec>, "prefix": <prefix string> }
자세한 내용과 예시는 multi-value dimensions 문서를 참고하세요.
Lookup DimensionSpec
lookup dimension spec을 사용해 lookup 구현을 dimension spec으로 직접 정의할 수 있어요. 일반적으로 lookup 구현에는 두 종류가 있습니다. 첫 번째 종류는 map 구현처럼 쿼리 시간에 전달됩니다.
{
"type":"lookup",
"dimension":"dimensionName",
"outputName":"dimensionOutputName",
"replaceMissingValueWith":"missing_value",
"retainMissingValue":false,
"lookup":{"type": "map", "map":{"key":"value"}, "isOneToOne":false}
}
retainMissingValue와 replaceMissingValueWith 속성은 쿼리 시간에 지정해 누락 값을 처리하는 방법을 힌트로 줄 수 있어요. replaceMissingValueWith를 ""로 설정하는 것은 null로 설정하거나 속성을 생략하는 것과 같은 효과가 있습니다. retainMissingValue를 true로 설정하면 lookup에서 찾을 수 없을 때 차원의 원래 값을 사용합니다. 기본값은 replaceMissingValueWith = null과 retainMissingValue = false이며, 이는 누락 값을 누락으로 취급하게 합니다. retainMissingValue = true를 설정하면서 replaceMissingValueWith를 지정하는 것은 불법입니다. lookup 기반 추출 필터의 최적화를 허용하는 optimize 속성을 제공할 수 있습니다(기본값 optimize = true).
두 번째 종류는 크기 때문에 쿼리 시간에 전달할 수 없는 것으로, 이미 구성 파일이나 Coordinator를 통해 등록된 외부 lookup 테이블이나 리소스에 기반합니다.
{
"type":"lookup",
"dimension":"dimensionName",
"outputName":"dimensionOutputName",
"name":"lookupName"
}
Output Types
dimension spec은 컬럼 값의 출력 타입을 지정하는 옵션을 제공합니다. 주어진 이름의 컬럼이 서로 다른 세그먼트에서 서로 다른 값 타입을 가질 수 있기 때문에 필요한 것이며, 병합 전에 결과가 outputType이 지정한 타입으로 변환됩니다. 참고로 모든 DimensionSpec 사용 사례가 현재 outputType을 지원하는 것은 아니며, 아래 표는 이 옵션을 지원하는 사용 사례를 보여줍니다:
| Query Type | Supported? |
|---|---|
| GroupBy (v1) | no |
| GroupBy (v2) | yes |
| TopN | yes |
| Search | no |
| Select | no |
| Cardinality Aggregator | no |
추출 함수(Extraction Functions)
추출 함수는 각 차원 값에 적용되는 변환을 정의합니다. 변환은 일반(문자열) 차원과, 쿼리 집계 granularity에 따라 현재 시간 버킷을 나타내는 특별한 __time 차원에 모두 적용될 수 있습니다. 참고: 문자열 값을 받는 함수(예: 정규 표현식)의 경우 __time 차원 값은 추출 함수에 전달되기 전에 ISO-8601 형식으로 포맷됩니다.
정규 표현식 추출 함수
주어진 정규 표현식의 첫 번째 매칭 그룹을 반환합니다. 매칭이 없으면 차원 값을 그대로 반환합니다.
{
"type" : "regex",
"expr" : <regular_expression>,
"index" : <group to extract, default 1>
"replaceMissingValue" : true,
"replaceMissingValueWith" : "foobar"
}
예를 들어 "expr" : "(\\w\\w\\w).*"를 사용하면 'Monday', 'Tuesday', 'Wednesday'가 'Mon', 'Tue', 'Wed'로 변환됩니다. "index"가 설정되면 매치에서 추출할 그룹을 제어합니다. 인덱스 0은 전체 패턴과 일치하는 문자열을 추출합니다. replaceMissingValue 속성이 true이면 추출 함수가 regex 패턴과 일치하지 않는 차원 값을 사용자 지정 String으로 변환합니다. 기본값은 false입니다. replaceMissingValueWith 속성은 replaceMissingValue가 true일 때 일치하지 않는 차원 값이 대체될 String을 설정합니다. replaceMissingValueWith가 지정되지 않으면 일치하지 않는 차원 값은 null로 대체됩니다. 예를 들어 위 예시 JSON에서 expr이 "(a\w+)"이면, 문자 a로 시작하는 단어와 일치하는 regex이고, 추출 함수는 banana 같은 차원 값을 foobar로 변환합니다.
부분 추출 함수(Partial Extraction Function)
정규 표현식이 일치하면 차원 값을 그대로 반환하고, 그렇지 않으면 null을 반환합니다.
{ "type" : "partial", "expr" : <regular_expression> }
검색 쿼리 추출 함수
주어진 SearchQuerySpec이 일치하면 차원 값을 그대로 반환하고, 그렇지 않으면 null을 반환합니다.
{ "type" : "searchQuery", "query" : <search_query_spec> }
부분 문자열 추출 함수(Substring Extraction Function)
제공된 인덱스에서 시작해 원하는 길이만큼 차원 값의 부분 문자열을 반환합니다. 인덱스와 길이 모두 문자열이 UTF-16으로 인코딩된 것처럼 문자열에 존재하는 유니코드 코드 단위(code unit)의 수로 측정됩니다. 일부 유니코드 문자는 두 개의 코드 단위로 표현될 수 있음을 주목하세요. 이는 Java String 클래스의 "substring" 메서드와 같은 동작입니다. 원하는 길이가 차원 값의 길이를 초과하면 인덱스에서 시작하는 문자열의 나머지가 반환됩니다. 인덱스가 차원 값의 길이보다 크면 null이 반환됩니다.
{ "type" : "substring", "index" : 1, "length" : 4 }
substring의 길이는 생략할 수 있으며, 그 경우 인덱스에서 시작하는 차원 값의 나머지를 반환합니다. 인덱스가 차원 값의 길이보다 크면 null입니다.
{ "type" : "substring", "index" : 3 }
Strlen 추출 함수
문자열이 UTF-16으로 인코딩된 것처럼 문자열에 존재하는 유니코드 코드 단위의 수로 측정한 차원 값의 길이를 반환합니다. 일부 유니코드 문자는 두 개의 코드 단위로 표현될 수 있음을 주목하세요. 이는 Java String 클래스의 "length" 메서드와 같은 동작입니다. null 문자열은 길이가 0인 것으로 간주됩니다.
{ "type" : "strlen" }
시간 형식 추출 함수(Time Format Extraction Function)
주어진 형식 문자열, 시간대, 로케일에 따라 포맷된 차원 값을 반환합니다. __time 차원 값의 경우 집계 granularity로 버킷 처리된 시간 값을 포맷합니다. 일반 차원의 경우 문자열이 ISO-8601 날짜와 시간 형식이라고 가정합니다.
format: 결과 차원 값의 날짜 시간 형식으로, Joda Time DateTimeFormat을 사용하거나 기본 ISO8601 형식을 쓰려면 null을 사용.locale: 사용할 로케일(언어와 국가)로, IETF BCP 47 언어 태그로 제공. 예:en-US,en-GB,fr-FR,fr-CA등.timeZone: IANA tz database 형식으로 사용할 시간대. 예:Europe/Berlin(집계 시간대와 다를 수 있음).granularity: 포맷 전에 적용할 granularity, 또는 어떤 granularity도 적용하지 않으려면 생략.asMillis: boolean 값. true로 설정하면 입력 문자열을 ISO8601 문자열이 아니라 millis로 취급합니다. 추가로format이 null이거나 지정되지 않으면 출력은 ISO8601이 아니라 millis가 됩니다.
{ "type" : "timeFormat",
"format" : <output_format> (optional),
"timeZone" : <time_zone> (optional, default UTC),
"locale" : <locale> (optional, default current locale),
"granularity" : <granularity> (optional, default none) },
"asMillis" : <true or false> (optional) }
예를 들어 다음 dimension spec은 몬트리올(Montréal)의 요일을 프랑스어로 반환합니다:
{
"type" : "extraction",
"dimension" : "__time",
"outputName" : "dayOfWeek",
"extractionFn" : {
"type" : "timeFormat",
"format" : "EEEE",
"timeZone" : "America/Montreal",
"locale" : "fr"
}
}
시간 파싱 추출 함수(Time Parsing Extraction Function)
주어진 입력 형식을 사용해 차원 값을 타임스탬프로 파싱하고, 주어진 출력 형식을 사용해 포맷해 반환합니다. 참고로 __time 차원에서 작업한다면 문자열 값이 아닌 시간 값에 직접 작동하는 time 추출 함수를 대신 사용하는 것을 고려하세요. "joda"가 true이면 시간 형식은 Joda DateTimeFormat 문서에 설명됩니다. "joda"가 false(또는 미지정)이면 형식은 SimpleDateFormat 문서에 설명됩니다. 일반적으로 "joda"를 true로 설정할 것을 권장합니다. Joda 형식 문자열이 Druid API에서 더 흔하고, Joda가 달력 연도의 시작과 끝 근처의 주(weeks)와 주 연도(weekyears) 같은 특정 경계 사례를 더 ISO8601 준수하게 처리하기 때문입니다. 제공된 timeFormat으로 값을 파싱할 수 없으면 그대로 반환됩니다.
{ "type" : "time",
"timeFormat" : <input_format>,
"resultFormat" : <output_format>,
"joda" : <true, false> }
JavaScript 추출 함수
주어진 JavaScript 함수로 변환된 차원 값을 반환합니다. 일반 차원의 경우 입력 값은 문자열로 전달됩니다. __time 차원의 경우 입력 값은 1970년 1월 1일 UTC 이후의 밀리초 수를 나타내는 숫자로 전달됩니다.
일반 차원의 예시:
{
"type" : "javascript",
"function" : "function(str) { return str.substr(0, 3); }"
}
{
"type" : "javascript",
"function" : "function(str) { return str + '!!!'; }",
"injective" : true
}
injective 속성은 JavaScript 함수가 유일성(uniqueness)을 보존하는지 지정합니다. 기본값은 false로 유일성이 보존되지 않는다는 뜻입니다. __time 차원의 예시:
{
"type" : "javascript",
"function" : "function(t) { return 'Second ' + Math.floor((t % 60000) / 1000); }"
}
JavaScript 기반 기능은 기본적으로 비활성화되어 있습니다. Druid의 JavaScript 기능을 사용하는 방법(활성화 방법 포함)에 대한 지침은 Druid JavaScript programming guide를 참고하세요.
등록된 lookup 추출 함수(Registered lookup extraction function)
Lookup은 차원 값이 (선택적으로) 새 값으로 대체되는 Druid의 개념입니다. lookups 사용에 대한 자세한 문서는 Lookups 문서를 참고하세요. "registeredLookup" 추출 함수를 사용하면 클러스터 전체 구성에 등록된 lookup을 참조할 수 있습니다. 예시:
{
"type":"registeredLookup",
"lookup":"some_lookup_name",
"retainMissingValue":true
}
retainMissingValue와 replaceMissingValueWith 속성은 쿼리 시간에 지정해 누락 값을 처리하는 방법을 힌트로 줄 수 있어요. replaceMissingValueWith를 ""로 설정하는 것은 null로 설정하거나 속성을 생략하는 것과 같은 효과가 있습니다. retainMissingValue를 true로 설정하면 lookup에서 찾을 수 없을 때 차원의 원래 값을 사용합니다. 기본값은 replaceMissingValueWith = null과 retainMissingValue = false이며, 이는 누락 값을 누락으로 취급하게 합니다. injective 속성은 lookup 자체가 가지는 injective 여부에 대한 판단을 재정의할 수 있습니다. 지정하지 않으면 Druid는 등록된 클러스터 전체 lookup 구성을 사용합니다. lookup 기반 추출 필터의 최적화를 허용하는 optimize 속성을 제공할 수 있습니다(기본값 optimize = true). 최적화 레이어는 Broker에서 실행되며 추출 필터를 selector 필터의 절(clause)로 다시 작성합니다. 예를 들어 다음 필터
{
"filter": {
"type": "selector",
"dimension": "product",
"value": "bar_1",
"extractionFn": {
"type": "registeredLookup",
"optimize": true,
"lookup": "some_lookup_name"
}
}
}
는 "product_1"과 "product_3"을 값 "bar_1"에 매핑하는 lookup을 가정할 때 다음 더 단순한 쿼리로 다시 작성됩니다:
{
"filter":{
"type":"or",
"fields":[
{
"filter":{
"type":"selector",
"dimension":"product",
"value":"product_1"
}
},
{
"filter":{
"type":"selector",
"dimension":"product",
"value":"product_3"
}
}
]
}
}
null 차원 값은 lookup 파일에서 키로 빈 문자열을 지정하면 특정 값으로 매핑될 수 있습니다. 이렇게 하면 null 차원과 null을 결과로 가지는 lookup을 구분할 수 있어요. 예를 들어 차원 값 [null, "foo", "bat"]에 대해 {"":"bar","bat":"baz"}를 지정하고 누락 값을 "oof"로 대체하면 ["bar", "oof", "baz"] 결과를 얻습니다. 빈 문자열 키를 생략하면 누락 값이 대신 적용됩니다. 예를 들어 차원 값 [null, "foo", "bat"]에 대해 {"bat":"baz"}를 지정하고 누락 값을 "oof"로 대체하면 ["oof", "oof", "baz"] 결과를 얻습니다.
인라인 lookup 추출 함수(Inline lookup extraction function)
Lookup은 차원 값이 (선택적으로) 새 값으로 대체되는 Druid의 개념입니다. lookups 사용에 대한 자세한 문서는 Lookups 문서를 참고하세요. "lookup" 추출 함수를 사용하면 클러스터 전체 구성에 등록하지 않고 인라인 lookup 맵을 지정할 수 있습니다. 예시:
{
"type":"lookup",
"lookup":{
"type":"map",
"map":{"foo":"bar", "baz":"bat"}
},
"retainMissingValue":true,
"injective":true
}
{
"type":"lookup",
"lookup":{
"type":"map",
"map":{"foo":"bar", "baz":"bat"}
},
"retainMissingValue":false,
"injective":false,
"replaceMissingValueWith":"MISSING"
}
인라인 lookup은 map 타입이어야 합니다. retainMissingValue, replaceMissingValueWith, injective, optimize 속성은 등록된 lookup 추출 함수와 비슷하게 동작합니다.
캐스케이드 추출 함수(Cascade Extraction Function)
추출 함수의 연결(chained) 실행을 제공합니다. extractionFns 속성은 어떤 추출 함수든 배열로 포함하며, 배열 인덱스 순서대로 실행됩니다. 정규 표현식 추출 함수, JavaScript 추출 함수, substring 추출 함수를 연결하는 예시는 다음과 같습니다.
{
"type" : "cascade",
"extractionFns": [
{
"type" : "regex",
"expr" : "/([^/]+)/",
"replaceMissingValue": false,
"replaceMissingValueWith": null
},
{
"type" : "javascript",
"function" : "function(str) { return \"the \".concat(str) }"
},
{
"type" : "substring",
"index" : 0, "length" : 7
}
]
}
이것은 차원 값을 지정된 추출 함수를 언급된 순서대로 변환합니다. 예를 들어 '/druid/prod/historical'는 정규 표현식 추출 함수가 먼저 'druid'로 변환하고, JavaScript 추출 함수가 'the druid'로 변환한 다음, 마지막으로 substring 추출 함수가 'the dru'로 변환하기 때문에 'the dru'로 변환됩니다.
문자열 형식 추출 함수(String Format Extraction Function)
주어진 형식 문자열에 따라 포맷된 차원 값을 반환합니다.
{ "type" : "stringFormat", "format" : <sprintf_expression>, "nullHandling" : <optional attribute for handling null value> }
예를 들어 실제 차원 값의 앞뒤에 "["와 "]"를 연결하려면 형식 문자열로 "[%s]"를 지정해야 합니다. "nullHandling"은 nullString, emptyString 또는 returnNull 중 하나일 수 있습니다. "[%s]" 형식으로 각 구성은 [null], [], null 결과를 냅니다. 기본값은 nullString입니다.
대문자/소문자 추출 함수(Upper and Lower extraction functions)
차원 값을 모두 대문자 또는 소문자로 반환합니다. 선택적으로 대문자/소문자 변환을 수행할 언어를 지정할 수 있습니다.
{
"type" : "upper",
"locale":"fr"
}
또는 "locale"을 설정하지 않고(이 경우 이 Java Virtual Machine 인스턴스의 기본 로케일 현재 값이 사용됨):
{
"type" : "lower"
}
버킷 추출 함수(Bucket Extraction Function)
버킷 추출 함수는 주어진 크기의 각 범위에 있는 숫자 값을 같은 기본 값으로 변환해 버킷 처리합니다. 숫자가 아닌 값은 null로 변환됩니다.
size: 버킷의 크기(선택 사항, 기본 1)offset: 버킷의 오프셋(선택 사항, 기본 0)
다음 추출 함수는 2에서 시작하는 크기 5의 버킷을 만듭니다. 이 경우 [2, 7) 범위의 값은 2로, [7, 12) 범위의 값은 7로 변환됩니다.
{
"type" : "bucket",
"size" : 5,
"offset" : 2
}
더 알아보기 (Learn more)
- multi-value dimensions: 필터링된 dimension spec을 자세히.
- Lookups: Druid의 lookup 개념.
- Druid SQL: SQL 언어에서의 함수.