DataPrime 연산자
이 가이드에서는 IBM® Cloud Logs DataPrime 연산자에 대한 용어집을 제공합니다.
block
filter 의 부정. 조건이 참인 모든 이벤트를 필터링합니다. !(condition) 과 함께 filter 을 사용하면 동일한 효과를 얻을 수 있습니다.
block $d.status_code >= 200 && $d.status_code <= 299 # Leave all events which don't have a status code of 2xx
데이터는 다음 필드를 사용하여 노출됩니다:
-
m - 이벤트 메타데이터
timestampseverity- 가능한 값은Verbose,Debug,Info,Warning,Error입니다,Criticalpriorityclass- 가능한 값은high,medium입니다,lowlogid
-
l - 이벤트 레이블
applicationnamesubsystemnamecategoryclassnamecomputernamemethodnamethreadidipaddress
-
d -사용자의 데이터
bottom
그룹화 변형이 없습니다: 반환되는 행을 지정된 수로 제한하고 표현식 집합에 따라 결과 순서를 지정합니다.
order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
예를 들면, 다음 조회를
bottom 5 $m.severity as $d.log_severity by $d.duration
다음과 같은 형식의 로그가 생성됩니다:
[
{ "log_severity": "Debug", "duration": 1000 }
{ "log_severity": "Warning", "duration": 2000 },
...
]
그룹화 변형: 반환되는 행을 지정된 수로 제한하고 집계 표현식 집합을 기준으로 그룹화하고 표현식 집합을 기준으로 정렬합니다.
order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]
예를 들면, 다음 조회를
bottom 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
다음과 같은 형식의 로그가 생성됩니다:
[
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
...
]
지원되는 집계 함수는 '집계 함수' 섹션에 나열되어 있습니다.
choose
제공된 키 경로만 남겨두고 다른 키는 모두 버립니다. 출력에서 중첩된 키 경로를 완벽하게 지원합니다.
(choose|select) <keypath1> [as <new_keypath>],<keypath2> [as <new_keypath>],...
예:
choose $d.mysuperkey.myfield
choose $d.my_superkey.mykey as $d.important_value, 10 as $d.the_value_ten
convert
키의 데이터 유형을 변환합니다.
datatypes 키워드는 선택 사항이며 가독성을 위해 사용할 수 있습니다.
(conv|convert) [datatypes] <keypath1>:<datatype1>,<keypath2>:<datatype2>,...
예:
convert $d.level:number
conv datatypes $d.long:number,$d.lat:number
convert $d.data.color:number,$d.item:string
count
앞의 연산자가 생성한 행 수를 포함하는 단일 행을 반환합니다.
count [into <keypath>]
별칭을 제공하여 결과가 기록될 키 경로를 재정의할 수 있습니다.
예를 들어 쿼리의 다음 부분이 있습니다:
count into $d.num_rows
다음 형식의 단일 행이 생성됩니다:
{ "num_rows": 7532 }
countby
표현식으로 그룹화된 모든 행을 계산한 행을 반환합니다.
countby <expression> [as <alias>] [into <keypath>]
별칭을 제공하여 결과가 기록될 키 경로를 재정의할 수 있습니다.
예를 들어 쿼리의 다음 부분은 다음과 같습니다
countby $d.verb into $d.verb_count
각 그룹에 대한 행이 생성됩니다.
기능적으로 다음과 동일합니다
groupby $data.verb calculate count() as $d.verb_count
create
새 키를 만들고 그 값을 표현식의 결과로 설정합니다. 키 생성은 세분화되어 있으므로 경로의 상위 키를 덮어쓰지 않습니다.
(a|add|c|create) <keypath> from <expression> [on keypath exists (fail|skip|overwrite)] [on keypath missing (fail|create|skip)] [on datatype change (skip|fail|overwrite)
다음 절을 추가하여 생성을 제어할 수 있습니다:
-
keypath exists을 추가하면 키 경로가 이미 존재할 때 수행할 작업을 선택할 수 있습니다.-
overwrite- 이전 값을 덮어씁니다. (기본값) -
fail- 쿼리 실패 -
skip- 키 생성을 건너뜁니다
-
-
keypath missing을 추가하면 새 키 경로가 존재하지 않을 때 수행할 작업이 선택됩니다.-
create- 키를 생성합니다. (기본값) -
fail- 쿼리 실패 -
skip- 새 키 생성을 건너뜁니다
-
-
datatype changed에 추가하면 키가 이미 존재하고 새 데이터로 인해 값의 데이터 유형이 변경되는 경우 수행할 작업을 선택합니다.-
overwrite- 값을 덮어씁니다. 이는 기본값입니다. -
fail- 쿼리 실패 -
skip- 키에 원래 값(및 유형)을 남깁니다
-
예:
create $d.radius from 100+23
c $d.log_data.truncated_message from $d.message.substring(1,50)
c $data.trimmed_name from $data.username.trim()
create $d.temperature from 100*23 on datatype changed skip
distinct
제공된 표현식의 각 고유한 조합에 대해 하나의 행을 반환합니다.
distinct <expression> [as <alias>] [, <expression_2> [as <alias_2>], ...]
이 연산자는 집계 함수 없이 기능적으로 groupby 와 동일합니다.
enrich
조회 테이블의 추가 컨텍스트를 사용하여 로그를 보강하세요.
데이터 흐름 > 데이터 보강 > 사용자 지정 보강을 사용하여 조회 테이블을 업로드합니다.
enrich <value_to_lookup> into <enriched_key> using <lookup_table>
-
value_to_lookup- 조회 테이블에서 조회할 문자열 표현식입니다. -
enriched_key- 대상 키는 보강 결과를 저장합니다. -
lookup_table- 사용할 사용자 지정 강화 테이블의 이름입니다.
테이블의 열이 대상 키에 하위 키로 추가됩니다. value_to_lookup 을 찾을 수 없으면 대상 키가 null이 됩니다. 그런 다음 보강된 필드에서 특정 값으로 로그를 필터링하는 등 DataPrime 기능을 사용하여 결과를 필터링할 수 있습니다.
예:
원본 로그입니다:
{
"userid": "111",
...
}
my_users 이라는 사용자 지정 강화 조회 테이블입니다:
| ID | 이름 | 부서 |
|---|---|---|
| 111 | John | 금융 |
| 222 | Emily | AI를 활용하는 |
다음 쿼리를 실행합니다:
enrich $d.userid into $d.user_enriched using my_users
다음과 같이 강화된 로그가 생성됩니다:
{
"userid": "111",
"user_enriched": {
"ID": "111",
"Name": "John",
"Department": "Finance"
},
...
}
enrich 을 사용할 때 다음 사항을 고려하십시오:
-
DataPrime 쿼리 소스
lookup_table를 실행하여 보강 테이블을 확인합니다. -
원본 로그에 이미 강화된 키가 포함되어 있는 경우:
-
lookup_table에value_to_lookup이 있는 경우 하위 키가 새 값으로 업데이트됩니다.value_to_lookup이 존재하지 않으면 현재 값이 그대로 유지됩니다. -
lookup_table의 열이 아닌 다른 하위 키는 기존 값을 그대로 유지합니다.
-
-
lookup_table의 모든 값은 문자열로 간주됩니다. 이는 다음을 의미합니다.-
value_to_lookup은 문자열 형식이어야 합니다. -
모든 값은 문자열 형식으로 보강됩니다. 그런 다음 적절한 함수를 사용하여 원하는 형식(예: JSON, 타임스탬프)으로 변환할 수 있습니다.
-
extract
일부 문자열 값에서 새 객체로 데이터를 추출합니다. 여러 추출 방법이 지원됩니다.
(e|extract) <expression> into <keypath> using <extraction-type>(<extraction-params>) [datatypes keypath:datatype,keypath:datatype,...]
다음은 지원되는 추출 방법과 해당 매개변수입니다:
-
regexp- 정규식 캡처 그룹을 기반으로 새 개체 만들기 -
e- 이름이 capture-groups인 정규식입니다.
예:
extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
-
kv- 키=값 키=값... 쌍이 포함된 문자열에서 새 개체 추출하기 -
pair_delimiter- 쌍 사이에 예상되는 구분 기호입니다. 기본값은 (공백)입니다 -
key_delimiter- 키와 값 사이를 구분할 구분 기호입니다. 기본값은 =입니다.
예:
extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
-
jsonobject- 문자열에서 새 객체를 추출하면 인코딩된 json 객체가 포함되어 있으므로 문자열을 json으로 디코딩하기 전에 문자열의 이스케이프 해제를 시도할 가능성이 있습니다 -
max_unescape_count- json을 구문 분석하기 전에 이스케이프할 최대 이스케이프 레벨 수입니다. 기본값은 1입니다. 1 이상으로 설정하면 엔진은 값에 이스케이프된 JSON 문자열이 포함되어 있는지 여부를 감지하고 파싱 가능 또는 최대 이스케이프 해제 횟수를 초과할 때까지 이스케이프를 해제합니다.
예:
e $d.json_message_as_str into $d.json_message using jsonobject(max_unescape_count=1)
데이터 유형 절을 사용하여 추출의 일부로 데이터 유형 정보를 제공할 수 있습니다. 예를 들어, 추출에 데이터 유형 my_field:number 을 추가하면 추출 my_field 키 경로가 문자열이 아닌 숫자가 됩니다. 예를 들어, 다음과 같습니다.
extract $d.my_msg into $d.data using kv() datatypes my_field:number
추출된 데이터는 항상 새 키 경로로 새 객체로 이동하여 새 객체 내에서 새 키를 추가로 처리할 수 있습니다. 예를 들어, 다음과 같습니다.
# Assuming a dataset which look like that:
{ "msg": "query_type=fetch query_id=100 query_results_duration_ms=232" }
{ "msg": "query_type=fetch query_id=200 query_results_duration_ms=1001" }
# And the following DataPrime query:
source logs
| extract $d.msg into $d.query_data using kv() datatypes
query_results_duration_ms:number
| filter $d.query_data.query_results_duration_ms > 500
# The results will contain only the second message, in which the duration is greater than 500 ms
filter
이벤트를 필터링하여 조건이 true로 평가되는 이벤트만 남깁니다.
(f|filter|where) <condition-expression>
예:
f $d.radius > 10
filter $m.severity.toUpperCase() == 'INFO'
filter $l.applicationname == 'myapp'
filter $l.applicationname == 'myapp' && $d.msg.contains('failure')
널과의 비교는 스칼라 값에 대해서만 작동하며 JSON 하위 트리에서는 항상 널을 반환합니다.
조건을 사용하여 키 경로를 null과 비교할 때는 스칼라 값(문자열, 숫자, 타임스탬프 등)에 대해서만 작동합니다. 지정된 문서 내의 JSON 객체의 경우 null과 비교하면 항상 null이 반환됩니다.
복잡한 검색을 수행하려면 기능이 있는 필터를 사용하세요.
예:
filter in($l.applicationname, 'ibm-audit-event', 'ibm-platform-logs') #
filter ipInSubnet(ip_address, '155.64.5.20/24')
e - 지정된 범위의 IP 주소를 필터링합니다. 필터를 함수와 결합하여 ipInSubnet 함수와 같이 구문을 거의 사용하지 않고 복잡한 검색을 수행할 수 있습니다:
filter ipInSubnet(ip_address, ' 154.67.8.20/24 ')
groupby
지정된 그룹화 표현식에 따라 앞의 연산자 결과를 그룹화하고 생성된 모든 그룹에 대한 집계 함수를 계산합니다.
groupby <grouping_expression> [as <alias>] [, <grouping_expression_2> [as <alias_2>], ...] [calculate]
<aggregate_function> [as <result_keypath>]
[, <aggregate_function_2> [as <result_keypath_2], ...]
예를 들면, 다음 조회를
groupby $m.severity calculate sum($d.duration)
다음과 같은 형식의 로그가 생성됩니다:
{ "severity": "Warning", "_sum": 17045 }
그룹화 표현식의 키 경로는 항상 $d 아래에 있습니다. as 키워드를 사용하여 그룹화 표현식 및 집계 함수의 키 경로 이름을 변경할 수 있습니다. 예를 들어, 다음과 같습니다.
groupby $l.applicationname as $d.app calculate sum($d.duration) as $d.sum_duration
다음과 같은 형식의 로그가 생성됩니다:
{ "app": "web-api", "sum_duration": 17045 }
groupby 연산자로 쿼리할 때 결과 버킷에 집계 함수 (예: avg, max, sum)를 적용할 수 있습니다. 이 기능을 사용하면 표현식 자체 내에서 집계 표현식을 조작할 수 있으므로 데이터를 계산하고
동시에 조작할 수 있습니다.
join
Join 는 현재(왼쪽) 쿼리의 결과를 지정된 조건에 따라 두 번째(오른쪽) 쿼리와 병합합니다. 데이터 결합 방식을 제어할 수 있는 다양한 양식을 제공하고 중첩을 지원하므로 올바른 쿼리에 자체 join 명령어를 포함할 수 있습니다.
Join 는 세 가지 변형을 지원합니다:
join left|join- 왼쪽 쿼리의 각 이벤트에 대해 이 명령은 지정된 조건에 따라 오른쪽 쿼리에서 일치하는 이벤트를 선택합니다. 일치하는 항목이 없으면 왼쪽 쿼리에 있는 모든 이벤트에 대한 행이 포함됩니다. 오른쪽 쿼리에서 일치하지 않는 행은
null으로 설정됩니다. join full- 두 쿼리(왼쪽 또는 오른쪽)에 일치하는 항목이 없을 수 있는 항목을 포함하여 모든 이벤트에 대한 행을 반환하고 누락된 값을
null으로 채웁니다. join inner- 두 쿼리 모두에서 null이 아닌 결과가 있는 행만 반환합니다.
join cross- 왼쪽 쿼리의 각 행을 오른쪽 쿼리의 모든 행과 쌍으로 연결하여 전체 직교곱을 생성합니다. 다른
join유형과 달리join cross은on또는using conditions을 지원하지 않습니다.join inner과 유사하게 작동하지만 필터링 없이 가능한 모든 행 조합을 반환합니다.
left (기본값), inner, full 의 경우 on 키워드를 사용하여 join 조건을 지정하거나 keyword 를 사용하여 키 경로를 지정할 수 있습니다. 직교 곱은 조건이 참이거나 키 경로 값이 양쪽 모두 일치하는 행만 유지하도록 필터링됩니다.
수정자에 관계없이 모든 조인은 데카르트 곱을 기반으로 하므로 join 조건이 여러 번 일치하는 경우 중복 결과가 발생할 수 있습니다. 의도하지 않은 중복을 방지하려면 distinct를 사용하는 등의 방법으로 하위 쿼리를 사전 처리하는 것이 좋습니다.
구문:
<left_side_query> | join [left/inner/full] (<right_side_query>) on <condition> into <right_side_target>
<left_side_query> | join [left/inner/full] (<right_side_query>) using <join_keypath_1> [, <join_keypath_2>, ...] into <right_side_target>
<left_side_query> | join cross (<right_side_query>) into <right_side_target>
여기서:
-
<right_side_query>-<right_side_query>은 조인할 새 쿼리를 나타냅니다. -
<left_side_query>-<left_side_query>은 초기 쿼리를 나타내며, 예를 들어source logs | filter x != null | join ...쿼리에서 왼쪽 쿼리는source logs | filter x != null입니다. -
<condition>- 두 쿼리의 결과를 모두 조인해야 하는 경우의 조건입니다.조건에서
left=>및right=>접두사를 사용하여 각각 왼쪽 및 오른쪽 쿼리의 이벤트를 참조할 수 있습니다. 그러나 키 경로가 쿼리 중 하나에만 존재하는 경우에는 필요하지 않습니다.조건에서
==(등호) 연산자를 사용하는 경우 왼쪽 쿼리의 키 경로를 오른쪽 쿼리의 키 경로와 비교해야 합니다. 그러나 키 경로는 고유하거나left=>또는right=>이 접두사로 붙어야 하므로 피연산자의 순서는 중요하지 않습니다. -
<join_keypath_n>-<join_keypath_n>를 조인 키로 사용하면 지정된 키 경로가 왼쪽 쿼리와 오른쪽 쿼리의 결과에서 모두 동일한 결과를 조인할 수 있습니다. -
<right_side_target>- 조인된 데이터가 현재 쿼리에 추가될 키 경로입니다.
join예
이름과 관련된 ID에 대한 정보를 제공하는 users 이라는 사용자 지정 보강 테이블이 있습니다:
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
그리고 이 데이터는 로그인 이벤트와 사용자 ID를 제공하지만 사용자 ID와 연결된 사용자 이름은 제공하지 않습니다.
{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
join 을 사용하여 원하는 데이터를 포함한 데이터를 반환하는 쿼리를 사용할 수 있습니다.
source users | join (source logs | countby userid) on id == userid into logins
이 쿼리는 다음과 같이 처리됩니다:
-
source은 사용자 지정 강화 테이블입니다(users). -
join에서userid필드의 카운트가 생성됩니다. 이를 통해count통계가 제공됩니다. -
사용자 지정 보강 테이블의
id필드는 로그의userid필드와 비교됩니다. -
결과는
logins키에 푸시됩니다.logins키가 왼쪽 쿼리에 이미 있는 경우 덮어쓰게 됩니다.
예를 들어, 다음과 같습니다.
{ "id": "111", "name": "John", "logins": { "userid": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "userid": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
이제 오른쪽 쿼리의 결과가 logins 필드 안에 있습니다. 사용자 ID 333 (Alice)에 대한 로그인이 없었으므로 join 조건과 일치하는 결과가 없었으므로 로그인 필드는 null 입니다.
join using 키워드를 사용한 예시
로그인 데이터 세트가 있는지 고려하세요:
{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
이 경우 조인 양쪽의 데이터에는 id 필드가 포함됩니다. 이 경우 using 키워드를 사용하여 공통 데이터를 활용할 수 있습니다:
source users | join (source logins | countby id) using id into logins
결과는 비슷하지만 userid 대신 id 필드가 반환됩니다.
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
이름이 다르지만 join 쿼리를 단순화할 수 있는 두 개의 필드가 있는 경우 다음을 사용하여 move 를 사용하여 필드 중 하나를 이동하여 양쪽의 키 경로가 일치하도록 할 수 있습니다.
join left=> 및 right=> 키워드를 사용한 예시
left=> 및 right=> 접두사를 사용하여 왼쪽 및 오른쪽 쿼리의 이벤트를 참조할 수 있습니다. 그러나 키 경로가 쿼리 중 하나에만 존재하는 경우에는 필요하지 않습니다.
이전 예제의 데이터를 사용하여 쿼리를 살펴봅니다:
source users | join (source logins | countby id) on left=>id == right=>id into logins
이는 두 데이터 집합에 동일한 이름의 필드(id)가 포함되어 있기 때문에 필요합니다. DataPrime 이 필드를 고유하게 식별하려면 쿼리의 어느 쪽을 참조하는지 알아야 합니다. 이 쿼리는 using 키워드를 사용한 이전 쿼리와 동일한 결과를 출력합니다.
조건에서 == (등호) 연산자를 사용하는 경우 왼쪽 쿼리의 키 경로를 오른쪽 쿼리의 키 경로와 비교해야 합니다. 그러나 키 경로는 고유하거나 left=> 또는 right=> 이 접두사로 붙어야 하므로 피연산자의 순서는 중요하지 않습니다.
join full예
이름과 관련된 ID에 대한 정보를 제공하는 users 이라는 사용자 지정 보강 테이블이 있습니다:
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
그리고 이 데이터 집합을 생각해 보세요:
{ "id": "001", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
두 번째 문서 집합(오른쪽 쿼리)에는 첫 번째 문서 집합(왼쪽 쿼리)에 없는 "id": "001" 로그 항목이 포함되어 있습니다. 표준 조인을 사용하는 경우 오른쪽 쿼리의 이 항목은 무시되며 결과에 표시되지 않습니다. 왼쪽 또는 오른쪽 쿼리에 표시되는지 여부에 관계없이 모든 id 필드가 출력에 포함되도록 하려면 join full 을 사용하면 됩니다:
source users | join full (source logins | countby id) using id into logins
이 쿼리의 결과는 다음과 같습니다:
{ "id": "001", "name": "null", "logins": { "id": "001", "_count": 1 } }
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
join full 을 사용하면 두 데이터 집합의 모든 id 필드가 보존되고 누락된 값은 null 으로 설정됩니다.
join full 는 두 쿼리의 결과에 시간 버킷이 모두 포함될 때 특히 유용합니다. 예를 들어 왼쪽 쿼리 결과에 특정 시간에 대한 시간 버킷이 누락된 경우(예: XX:XX:XX)에는 join full 이 데이터 포인트가 포함됩니다. 이 기능은 그래프에서 두 시계열을 비교할 때 특히 유용합니다.
join inner예
왼쪽 또는 오른쪽 쿼리에 대한 열 결과가 null 값을 생성하는 경우 행을 제거하려면 join inner 을 사용합니다.
이 쿼리는 이전 데이터를 사용하여 양쪽에서 일치하지 않는 데이터가 있는 행을 제거합니다:
source users | join inner (source logins | countby id) using id into logins
-
왼쪽 쿼리
source users는id및name필드가 포함된 사용자 데이터 집합을 검색합니다. -
올바른 쿼리(
source logins | countby id)는 로그인 데이터 집합을 검색하여id으로 그룹화하고 각id에 대한 발생 횟수를 계산합니다. -
join inner은 두 데이터 집합에id이 존재하는 행을 일치시키고 데이터를 단일 레코드로 병합합니다. -
두 데이터 집합에서 일치하는 항목이 없는 행은 최종 결과에서 제외됩니다.
이 경우 위의 두 문서 세트에 대한 결과는 다음과 같습니다:
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
join cross예
join cross 은 왼쪽 쿼리의 모든 행을 오른쪽 쿼리의 모든 행과 결합하여 두 집합의 데카르트곱 곱을 생성합니다.
users 이라는 이름의 사용자 지정 강화 테이블에 다음과 같은 문서가 있다고 가정합니다.
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
이제 logs 라는 이름의 문서 집합을 살펴 보겠습니다.
{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
다음 쿼리는 일치하는 조건에 관계없이 join cross 이 왼쪽 쿼리의 모든 행을 오른쪽 쿼리의 모든 행과 쌍을 이루므로 users 및 logs 데이터 집합의 직교곱을 생성합니다.
source users | join cross (source logs) into logins
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
이 쿼리는 각 사용자를 모든 로그 항목과 쌍으로 연결합니다: users 에서 3행과 logs 에서 5행이 곱해져 15행이 됩니다. 각 사용자(John, Emily, Alice)는 모든 로그 항목과 쌍을 이룹니다.
join cross 을 사용하면 데이터의 전체 그림을 보고 싶을 때 특히 유용하며, 이러한 결과에 left 또는 right join 을 추가할 수 있습니다.
제한 사항 및 고려 사항
쿼리에 join 을 포함할 때 제한 사항과 고려 사항이 있습니다:
-
join조건은 키 경로 동일성(==)만 지원합니다. 여러 개의 동일성 조건이 필요한 경우&&(논리적 및)와 결합할 수 있습니다. -
조인의 한 쪽(현재 쿼리 또는 조인 쿼리 중 하나)은 작아야 합니다(< 200MB ). 사용할 수 있습니다
filter및remove를 사용하여 쿼리 크기를 줄일 수 있습니다. -
왼쪽 외부 조인에서는 조건의 모든 열이 null이 아니어야 합니다. Null 열은 조인되지 않습니다. 오른쪽 쿼리 null 열을 포함하려면
join full을 사용합니다. 왼쪽 및 오른쪽 조인에서 생성된 모든 null 열을 제외하려면join inner을 사용합니다.
limit
출력을 첫 번째 event-count 이벤트로 제한합니다.
limit <event-count>
예:
limit 100
move
키(하위 키가 있는 경우 그 하위 키 포함)를 새 위치로 이동합니다.
(m|move) <source-keypath> to <target-keypath>
예:
move $d.my_data.hostname to $d.my_new_data.host
m $d.kubernetes.labels to $d.my_labels
multigroupby
multigroupby 는 groupby 를 포함하는 두 개 이상의 쿼리 결과를 단일 데이터 집합으로 연결합니다.
multigroupby 을 사용합니다:
-
효율성: 여러 쿼리에 대해 데이터를 한 번만 스캔합니다.
-
동기화: 결과가 일관되게 유지되므로 별도의 쿼리를 실행할 때 발생할 수 있는 불일치를 방지할 수 있습니다.
multigroupby (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...]) [, (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...]), ...][calculate] <aggregation_expression> [as <result_keypath>] [, <aggregation_expression_2> [as <result_keypath_2], ...]
두 그룹에 동일한 별칭 app 을 사용하면 동일한 의미론적 의미가 통합된 필드로 표시됩니다. 다음 예에서는 서로 다른 별칭이 사용되며 데이터가 결합되지만 병합되지는 않습니다.
예 - 동일한 별칭을 사용하는 Multigroupby
이 예제에서는 다음과 같이 로그를 그룹화하려고 합니다:
-
먼저
applicationname(app)에서, 그리고subsystemname(ss)에서 각 조합에 대한 자세한 개수를 확인할 수 있습니다. -
그런 다음
applicationname으로 독립적으로subsystems에 관계없이 각 애플리케이션에 대한 총 로그 수를 제공합니다.
source logs
| multigroupby ($l.applicationname as app, $l.subsystemname as ss),($l.applicationname as app) calculate count() | orderby app,ss
결과는 다음과 비슷합니다:
[
{
"_count0": 241,
"app": "monitoring24",
"ss": "NO_SUBSYSTEM_NAME"
},
{
"_count0": 231,
"app": "monitoring24",
"ss": "logs-opentelemetry-agent"
},
{
"_count0": 15,
"app": "monitoring24",
"ss": "logs-opentelemetry-collector"
},
{
"_count0": 487,
"app": "monitoring24",
"ss": null
}
]
처음 세 행은 app 와 ss 의 각 고유 조합에 대한 개수를 나타냅니다. 예를 들어 애플리케이션(app)이 monitoring24 이고 하위 시스템(ss)이 NO_SUBSYSTEM_NAME 인 경우 241 개의 로그가 있습니다. 마찬가지로 동일한 애플리케이션에 대해 231개의 로그가 있지만
하위 시스템 logs-opentelemetry-agent 등이 있습니다.
마지막 행은 모든 하위 시스템을 합산한 monitoring24 애플리케이션의 총 로그 수를 제공합니다. 여기서 _count0 은 위의 모든 세부 카운트의 합계인 487입니다. ss 필드는 null 으로 설정하여 전체 애플리케이션의 합계임을 표시합니다.
두 그룹에 동일한 별칭 app 을 사용하면 동일한 의미론적 의미가 통합된 필드로 표시됩니다. 다음 예에서는 서로 다른 별칭이 사용되며 데이터가 결합되지만 병합되지는 않습니다.
예 - 별칭이 다른 Multigroupby
이제 쿼리에 서로 다른 두 가지 별칭을 도입했을 때의 효과를 고려해 보겠습니다. 이 경우 첫 번째 그룹은 applicationname 과 ss 을 결합한 경우 app1 로 레이블이 지정되고 두 번째 그룹은 applicationname alone 을 결합한 경우 app2 으로 레이블이 지정됩니다.
source logs | multigroupby ($l.applicationname as app1, $l.subsystemname as ss),($l.applicationname as app2) calculate count()
결과는 다음과 비슷합니다:
[
{
"_count0": 241,
"app1": "monitoring24",
"app2": null,
"ss": "logs-opentelemetry-agent"
},
{
"_count0": 231,
"app1": "monitoring24",
"app2": null,
"ss": "logs-opentelemetry-collector"
},
{
"_count0": 15,
"app1": "monitoring24",
"app2": null,
"ss": "no_subsystem_name"
},
{
"_count0": 487,
"app1": null,
"app2": "monitoring24",
"ss": null
}
]
별도의 별칭(app1 및 app2)을 도입하여 쿼리에서 데이터를 병합하지 않고 두 그룹 간의 구분을 유지합니다. app1 이 채워지고 app2 이 null 인 행은 applicationname 과 subsystemname 의 세부 그룹화에 해당합니다. 예를 들어,
241개의 로그가 app1 = "monitoring24" 와 ss = "logs-opentelemetry-agent" 에 연결되어 있습니다. 이것은 첫 번째 그룹화 로직을 따릅니다.
app2 이 채워지고 app1 이 null 인 행은 로그가 applicationname 에 의해서만 집계되는 두 번째 그룹화에 대한 총 개수를 반영합니다. app2 = "monitoring24" 의 경우 카운트는 487이며 app1 과 ss 모두
null 으로 상위 수준의 집계를 나타냅니다.
별도의 별칭(app1 및 app2)을 사용하면 쿼리가 데이터를 병합하지 않고 각 결과가 어느 그룹에 속하는지 명확하게 알 수 있습니다. 특정 조합에 대한 세부 카운트와 총합에 대한 집계 카운트 등 전반적인 로직은 동일하게 유지됩니다.
Multigroupby 제한사항
multigroupby 는 중복 그룹 집합에 대해 중복 행을 반환하지 않습니다.
multigroupby 를 app 및 ss와 함께 실행하면 예상 결과(중복이 허용된 경우)는 다음과 같이 표시될 수 있습니다:
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2},
{"app": "monitoring24", "ss": "logs-opentelemetry-collector", "_count0": 2}
]
제한 사항으로 인해 multigroupby 은 이러한 중복을 병합하고 데이터에서 해당 조합이 여러 번 발생하더라도 각 고유 조합에 대해 하나의 행만 반환합니다:
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2}
]
orderby / sortby / order by / sort by
표현식 값의 오름차순/내림차순으로 데이터를 정렬합니다. 여러 표현식을 통한 주문이 지원됩니다.
(orderby|sortby|order by|sort by) <expression> [(asc|desc)] , ...
예:
orderby $d.myfield.myfield
orderby $d.myfield.myfield:number desc
sortby $d.myfield desc
숫자 값 정렬은 표현식을 타입으로 변환하여 수행할 수 있습니다(예: <expression>: number). 경우에 따라 엔진에서 자동으로 추론하는 경우도 있습니다.
redact
일부 키 경로 값에서 정규식 패턴과 일치하는 모든 하위 문자열을 대체하여 원본 콘텐츠를 효과적으로 숨깁니다.
일치하는 키워드는 선택 사항이며 가독성을 높이기 위해 사용할 수 있습니다.
redact <keypath> [matching] /<regular-expression>/ to '<redacted_str>'
redact <keypath> [matching] <string> to '<redacted_str>'
예:
redact $d.mykey /[0-9]+/ to 'SOME_INTEGER'
redact $d.mysuperkey.user_id 'root' to 'UNKNOWN_USER'
redact $d.mysuperkey.user_id matching 'root' to 'UNKNOWN_USER'
remove
개체에서 키 경로를 제거합니다.
r|remove <keypath1> [ "," <keypath2> ]...
예:
r $d.mydata.unneeded_key
remove $d.mysuperkey.service_name, $d.mysuperkey.unneeded_key
replace
일부 키의 값을 새 값으로 바꿉니다.
대체 값으로 인해 키 경로의 데이터 유형이 변경되는 경우 다음 옵션을 사용할 수 있습니다:
-
skip- 교체는 무시됩니다 -
fail- 쿼리가 실패합니다 -
overwrite- 새 값은 이전 값을 덮어쓰고 키 경로의 데이터 유형을 변경합니다
replace <keypath> with <expression> [on datatype changed skip/fail/overwrite]
예:
replace $d.message with null
replace $d.some_superkey.log_length_plus_10 with $d.original_log.length()+10 on datatype changed overwrite
roundtime
이벤트의 시간을 일정 시간 간격으로 반올림하여 결과에 대한 새 키를 생성할 수 있습니다.
-
source-timestamp을 제공하지 않으면$m.timestamp이 소스 타임스탬프로 사용됩니다. -
source-timestamp이 제공된 경우timestamp형식을 사용하거나 으로 캐스팅해야 합니다.
기본적으로 반올림된 결과는 소스 키 경로 source-timestamp 에 다시 기록됩니다. target-keypath 이 제공되면 source-timestamp 은 수정되지 않고 새로운 target-keypath 에 기록됩니다.
지원되는 시간 간격은 다음과 같습니다:
- Xns - X 나노초(소스 타임스탬프의 해상도에 주의)
- Xms - X밀리초
- X초 - X초
- Xm - X분
- X시간 - X시간
- Xd - X일
예를 들어 1h30m15s 과 같이 더 큰 시간 단위에서 더 작은 시간 단위까지 모든 조합이 가능합니다.
roundtime [source-timestamp] to <time-interval> [into <target-keypath>]
예:
roundtime to 1h into $d.tm
roundtime $d.timestamp to 1h
roundtime $d.my_timestamp: timestamp to 60m
roundtime to 60s into $d.rounded_ts_to_the_minute
source
DataPrime 쿼리의 기반이 되는 데이터 소스를 설정합니다.
(source|from) <data_store>
data_store 어느 쪽이든 가능합니다:
-
logs -
사용자 지정 인텐시티의 이름입니다. 이 경우 명령은 사용자 지정 보강 테이블을 표시합니다.
예:
source logs
stitch
stitch 명령은 두 데이터 집합을 나란히 결합하여 수평 유니온을 수행합니다. 한 데이터 집합의 행을 다른 데이터 집합의 행과 정렬하고 열을 연결하여 하나의 통합된 데이터 집합을 만듭니다.
stitch 명령을 사용하는 경우:
-
데이터 집합은 행이 순서대로 결합되므로(즉, 데이터 집합 A의 행 1이 데이터 집합 B의 행 1과 스티칭됨) 순서를 지정해야 합니다.
-
한 데이터 집합에 다른 데이터 집합보다 많은 행이 있는 경우, 일치하지 않는 행은 스티칭된 열에서 null 값을 갖습니다.
-
결과 데이터 집합에는 두 데이터 집합의 모든 열이 포함됩니다.
stitch union stitch 은 열을 행 단위로 추가하여 데이터 집합을 가로로 결합합니다. union 은 행을 세로로 추가하여 데이터 집합을 서로 쌓아 올립니다.
... | stitch (<subquery>) into <target-keypath>
예:
이러한 사용자 지정 보강 테이블이 있습니다:
sales 데이터 세트:
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue 데이터 세트:
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
{ "product": "Dashboard", "revenue": 6000 }
이 쿼리에서는 이러한 데이터 집합을 나란히 결합하여 한 데이터 집합의 각 행이 다른 데이터 집합의 해당 행과 정렬되도록 합니다:
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
-
source sales은 제품과 해당 판매 수치가 포함된sales데이터 집합에서 모든 행을 가져옵니다. -
orderby product은product필드를 기준으로sales데이터 집합을 정렬하여 행 정렬의 일관된 순서를 생성합니다. -
stitch (source revenue | orderby product)은revenue데이터 집합에서 행을 가져와product필드를 기준으로 정렬합니다.sales및revenue데이터 집합은 정렬 후 순서에 따라 행을 정렬하여 가로로 결합합니다. -
into combined_data는 결합된 데이터 집합을combined_data라는 변수에 저장합니다.
쿼리 결과는 다음과 같습니다:
{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": 6000 } }
데이터 집합에 행이 같지 않은 경우 stitch 명령은 누락된 값을 null 으로 채웁니다.
예를 들어 다음 데이터 집합을 생각해 보겠습니다:
sales 데이터 집합(3행):
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue 데이터 집합(2행):
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
이 쿼리를 실행합니다:
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
결과:
{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": null } }
stitch 사용법 참고
-
의미 있는 결과를 만들려면 행이 논리적으로 상호 연관되어야 합니다. 두 데이터 집합의 행이 동일한 엔티티를 나타내고 동일한 순서로 되어 있는지 확인합니다. 예를 들어
sales데이터 집합의product필드가 해당 행에 대한revenue데이터 집합의product필드와 일치하지 않는 경우, 스티칭이 예상대로 작동하지 않습니다. -
데이터 집합의 행 수가 다른 경우, 더 짧은 데이터 집합의 누락된 데이터에 대한
null값이 결과에 포함됩니다.
top
그룹화 변형이 없습니다: 반환되는 행을 지정된 수로 제한하고 표현식 집합에 따라 결과 순서를 지정합니다.
order_direction := "descending"/"ascending" according to top/bottom
top <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
예를 들면, 다음 조회를
top 5 $m.severity as $d.log_severity by $d.duration
다음과 같은 형식의 로그가 생성됩니다:
[
{ "log_severity": "Warning", "duration": 2000 },
{ "log_severity": "Debug", "duration": 1000 }
...
]
그룹화 변형: 반환되는 행을 지정된 수로 제한하고 집계 표현식 집합을 기준으로 그룹화하고 표현식 집합을 기준으로 정렬합니다.
order_direction := "descending"/"ascending" according to top/bottom
top <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]
예를 들면, 다음 조회를
top 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
다음과 같은 형식의 로그가 생성됩니다:
[
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
...
]
집계 함수를 적용할 수 있습니다...
union
union 명령은 두 개 이상의 데이터 집합의 결과를 하나의 데이터 집합으로 연결합니다. 이를 통해 사용자는 여러 쿼리의 결과를 하나의 원활한 데이터 집합으로 결합할 수 있습니다. 하나의 데이터 집합은 union 명령으로 파이핑된 결과 집합을 다른 데이터 집합과 연결할 수 있습니다.
한 데이터 집합에서 다른 데이터 집합으로 행을 추가해야 하는 경우 유니온을 사용합니다.
대규모 데이터 집합을 처리할 때 성능을 최적화하려면 union 을 사용하기 전에 filter 을 사용하여 각 데이터 집합의 행을 제한하는 것이 좋습니다.
사용자는 우선순위 인사이트 데이터에 대한 쿼리당 최대 10개의 union 명령으로 제한됩니다. 기타 데이터에는 제한이 없습니다.
union 의 차이점 join
-
union는 한 데이터 집합의 행을 다른 데이터 집합에 추가하여 결과 집합을 결합합니다. 여러 문서의 열을 병합하거나 비교하지 않습니다. -
join는 조건에 따라 두 테이블의 열을 일치시키고 결합하여 두 테이블의 데이터가 포함된 행을 만듭니다.
<query> | union <query>
2개의 데이터 집합 결합 예시
이 두 데이터 세트가 있습니다:
다음에 대한 로그 Team 58942
{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
다음에 대한 로그 Team 98361
{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
그리고 이를 하나의 데이터 집합으로 결합하려고 합니다. union 을 사용하여 이 작업을 수행할 수 있습니다.
source logs(teamId=58942) | union logs(teamId=98361)
쿼리는 두 데이터 집합을 처리합니다:
source logs(teamId=58942): 다음에 대한 모든 문서를 검색합니다Team 58942union logs (teamID=98361):Team 58942데이터 집합에Team 98361데이터 집합을 추가합니다
이렇게 하면 다음과 같은 데이터 세트가 생성됩니다:
{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }