조건 함수

조건 함수 (Conditional Functions)

PPL 조건 함수는 WHERE나 HAVING 절 같은 특정 조건에 따라 쿼리 결과를 전역적으로 필터링할 수 있게 해줘요. 이 함수들은 OpenSearch 엔진의 검색 기능을 사용하지만 OpenSearch 플러그인의 메모리 내에서 직접 실행되지는 않아요.

출처: 문서

본문

PPL 조건 함수는 WHERE나 HAVING 절 같은 특정 조건에 따라 쿼리 결과를 전역적으로 필터링할 수 있게 해줘요. 이 함수들은 OpenSearch 엔진의 검색 기능을 사용하지만 OpenSearch 플러그인의 메모리 내에서 직접 실행되지는 않아요.

ISNULL

사용법: isnull(field)

필드가 NULL이면 TRUE를, 그렇지 않으면 FALSE를 반환해요.

isnull() 함수는 주로 다음과 같이 사용돼요:

  • 조건부 필드를 만들기 위한 eval 표현식에서
  • 기본 값을 제공하기 위한 if() 함수와 함께
  • null 레코드를 필터링하기 위한 where 절에서

매개변수:

  • field (필수): null 값 여부를 확인할 필드예요.

반환 타입: BOOLEAN

예제
source=accounts
| eval result = isnull(employer)
| fields result, employer, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | employer | firstname |
False | Pyrami | Amber
False | Netagy | Hattie
False | Quility | Nanette
True | null | Dale

다음 예제는 isnull을 if 함수와 함께 사용해 조건부 레이블을 만드는 방법을 보여줘요:

source=accounts
| eval status = if(isnull(employer), 'unemployed', 'employed')
| fields firstname, employer, status

쿼리는 다음과 같은 결과를 반환해요:

| firstname | employer | status |
Amber | Pyrami | employed
Hattie | Netagy | employed
Nanette | Quility | employed
Dale | null | unemployed

다음 예제는 where 절에서 isnull을 사용해 레코드를 필터링해요:

source=accounts
| where isnull(employer)
| fields account_number, firstname, employer

쿼리는 다음과 같은 결과를 반환해요:

| account_number | firstname | employer |
18 | Dale | null

ISNOTNULL

사용법: isnotnull(field)

필드가 NULL이 아니면 TRUE를, 그렇지 않으면 FALSE를 반환해요.

isnotnull() 함수는 주로 다음과 같이 사용돼요:

  • 불리언 플래그를 만들기 위한 eval 표현식에서
  • null 값을 걸러내기 위한 where 절에서
  • 조건부 논리를 위한 if() 함수와 함께
  • 데이터 존재 여부를 검증하는 데

동의어 (Synonyms): ISPRESENT

매개변수:

  • field (필수): non-null 값 여부를 확인할 필드예요.

반환 타입: BOOLEAN

예제
source=accounts
| eval has_employer = isnotnull(employer)
| fields firstname, employer, has_employer

쿼리는 다음과 같은 결과를 반환해요:

| firstname | employer | has_employer |
Amber | Pyrami | True
Hattie | Netagy | True
Nanette | Quility | True
Dale | null | False

다음 예제는 where 절에서 isnotnull을 사용해 레코드를 필터링하는 방법을 보여줘요:

source=accounts
| where not isnotnull(employer)
| fields account_number, employer

쿼리는 다음과 같은 결과를 반환해요:

| account_number | employer |
18 | null

다음 예제는 isnotnull을 if 함수와 함께 사용해 검증 메시지를 만드는 방법을 보여줘요:

source=accounts
| eval validation = if(isnotnull(employer), 'valid', 'missing employer')
| fields firstname, employer, validation

쿼리는 다음과 같은 결과를 반환해요:

| firstname | employer | validation |
Amber | Pyrami | valid
Hattie | Netagy | valid
Nanette | Quility | valid
Dale | null | missing employer

EXISTS

사용법: 필드 존재 여부를 테스트하려면 isnull(field) 또는 isnotnull(field)를 사용해요.

OpenSearch는 null과 누락(missing) 값을 구분하지 않으므로 ismissing/isnotmissing 같은 함수는 사용할 수 없어요. 필드 존재 여부를 테스트하려면 isnull/isnotnull을 사용해요.

예제

다음 예제는 email 필드가 없는 계정 13을 보여줘요:

source=accounts
| where isnull(email)
| fields account_number, email

쿼리는 다음과 같은 결과를 반환해요:

| account_number | email |
13 | null

IFNULL

사용법: ifnull(field1, field2)

field1이 NULL이면 field2를 반환해요.

매개변수:

  • field1 (필수): NULL 값 여부를 확인할 필드예요.
  • field2 (필수): field1이 NULL이면 반환할 값이에요.

반환 타입: 모든 타입 (입력 타입과 일치)

예제
source=accounts
| eval result = ifnull(employer, 'default')
| fields result, employer, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | employer | firstname |
Pyrami | Pyrami | Amber
Netagy | Netagy | Hattie
Quility | Quility | Nanette
default | null | Dale
중첩 ifnull 패턴

OpenSearch 3.1 이전 버전에서는 중첩 ifnull 문을 사용해 coalesce와 유사한 기능을 구현할 수 있어요. 이 패턴은 데이터 소스마다 필드 이름이 다를 수 있는 관측성(observability) 사용 사례에서 특히 유용해요. 사용법: ifnull(field1, ifnull(field2, ifnull(field3, default_value)))

예제
source=accounts
| eval result = ifnull(employer, ifnull(firstname, ifnull(lastname, "unknown")))
| fields result, employer, firstname, lastname

쿼리는 다음과 같은 결과를 반환해요:

| result | employer | firstname | lastname |
Pyrami | Pyrami | Amber | Duke
Netagy | Netagy | Hattie | Bond
Quility | Quility | Nanette | Bates
Dale | null | Dale | Adams

NULLIF

사용법: nullif(field1, field2)

두 매개변수가 같으면 NULL을, 그렇지 않으면 field1을 반환해요.

매개변수:

  • field1 (필수): field2와 다르면 반환할 필드예요.
  • field2 (필수): field1과 비교할 값이에요.

반환 타입: 모든 타입 (field1 타입과 일치)

예제
source=accounts
| eval result = nullif(employer, 'Pyrami')
| fields result, employer, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | employer | firstname |
null | Pyrami | Amber
Netagy | Netagy | Hattie
Quility | Quility | Nanette
null | null | Dale

IF

사용법: if(condition, expr1, expr2)

조건이 true면 expr1을, 그렇지 않으면 expr2를 반환해요.

매개변수:

  • condition (필수): 평가할 불리언 표현식이에요.
  • expr1 (필수): 조건이 true면 반환할 값이에요.
  • expr2 (필수): 조건이 false면 반환할 값이에요.

반환 타입: expr1과 expr2의 가장 덜 제한적인 공통 타입

예제

다음 예제는 조건이 true일 때 이름을 반환해요:

source=accounts
| eval result = if(true, firstname, lastname)
| fields result, firstname, lastname

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname | lastname |
Amber | Amber | Duke
Hattie | Hattie | Bond
Nanette | Nanette | Bates
Dale | Dale | Adams

다음 예제는 조건이 false일 때 성을 반환해요:

source=accounts
| eval result = if(false, firstname, lastname)
| fields result, firstname, lastname

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname | lastname |
Duke | Amber | Duke
Bond | Hattie | Bond
Bates | Nanette | Bates
Adams | Dale | Adams

다음 예제는 복잡한 조건을 사용해 VIP 상태를 결정해요:

source=accounts
| eval is_vip = if(age > 30 AND isnotnull(employer), true, false)
| fields is_vip, firstname, lastname

쿼리는 다음과 같은 결과를 반환해요:

| is_vip | firstname | lastname |
True | Amber | Duke
True | Hattie | Bond
False | Nanette | Bates
False | Dale | Adams

CASE

사용법: case(condition1, expr1, condition2, expr2, ... conditionN, exprN else default)

condition1이 true면 expr1을, condition2가 true면 expr2를 반환하는 식으로 동작해요. 어떤 조건도 true가 아니면 else 절의 값을 반환해요. else 절이 정의되지 않으면 NULL을 반환해요.

매개변수:

  • condition1, condition2, ..., conditionN (필수): 순서대로 평가할 불리언 표현식이에요.
  • expr1, expr2, ..., exprN (필수): 해당 조건이 true일 때 반환할 값이에요.
  • default (선택): 어떤 조건도 true가 아닐 때 반환할 값이에요. 지정하지 않으면 NULL을 반환해요.

반환 타입: 모든 결과 표현식의 가장 덜 제한적인 공통 타입

제한 사항 (Limitations)

각 조건이 숫자 리터럴에 대한 필드 비교이고 각 결과 표현식이 문자열 리터럴인 경우, push-down 최적화가 활성화되어 있으면 쿼리가 range 집계로 최적화돼요. 그러나 이 최적화에는 다음 제한 사항이 있어요:

  • NULL 값은 range 집계의 어떤 버킷에도 그룹화되지 않고 무시돼요.
  • 기본 else 절은 실제 NULL 값 대신 문자열 리터럴 "null"을 사용해요.
예제

다음 예제는 else 절이 있는 case 문을 보여줘요:

source=accounts
| eval result = case(age > 35, firstname, age < 30, lastname else employer)
| fields result, firstname, lastname, age, employer

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname | lastname | age | employer |
Pyrami | Amber | Duke | 32 | Pyrami
Hattie | Hattie | Bond | 36 | Netagy
Bates | Nanette | Bates | 28 | Quility
null | Dale | Adams | 33 | null

다음 예제는 else 절이 없는 case 문을 보여줘요:

source=accounts
| eval result = case(age > 35, firstname, age < 30, lastname)
| fields result, firstname, lastname, age

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname | lastname | age |
null | Amber | Duke | 32
Hattie | Hattie | Bond | 36
Bates | Nanette | Bates | 28
null | Dale | Adams | 33

다음 예제는 where 절에서 case를 사용해 레코드를 필터링해요:

source=accounts
| where true = case(age > 35, false, age < 30, false else true)
| fields firstname, lastname, age

쿼리는 다음과 같은 결과를 반환해요:

| firstname | lastname | age |
Amber | Duke | 32
Dale | Adams | 33

COALESCE

사용법: coalesce(field1, field2, ...)

매개변수 목록에서 첫 번째 non-null, non-missing 값을 반환해요.

매개변수:

  • field1, field2, ... (필수): non-null 값을 평가할 필드 또는 표현식이에요.

반환 타입: 모든 입력 매개변수의 가장 덜 제한적인 공통 타입

동작 (Behavior):

  • NULL이 아니고 누락되지 않은 첫 번째 값을 반환해요 (누락은 존재하지 않는 필드를 포함해요).
  • 빈 문자열("")과 공백 문자열(" ")은 유효한 값으로 간주돼요.
  • 모든 매개변수가 NULL이거나 누락이면 NULL을 반환해요.
  • 결정된 반환 타입에 맞도록 자동 타입 강제 변환이 적용돼요.
  • 타입 변환이 실패하면 값이 문자열 표현으로 변환돼요.
  • 최상의 결과를 얻으려면 예상치 못한 타입 변환을 피하기 위해 같은 데이터 타입의 매개변수를 사용해요.

성능 고려 사항 (Performance considerations):

  • 여러 필드 평가에 최적화되어 있어 중첩 ifnull 패턴보다 효율적이에요.
  • 매개변수를 순차적으로 평가하며 첫 번째 non-null 값에서 멈춰요.
  • 평가 오버헤드를 최소화하려면 값이 포함될 가능성에 따라 필드 순서를 고려해요.

제한 사항 (Limitations):

  • 타입 강제 변환은 호환되지 않는 타입에서 예상치 못한 문자열 변환을 초래할 수 있어요.
  • 인수가 너무 많으면 성능이 저하될 수 있어요.
예제
source=accounts
| eval result = coalesce(employer, firstname, lastname)
| fields result, firstname, lastname, employer

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname | lastname | employer |
Pyrami | Amber | Duke | Pyrami
Netagy | Hattie | Bond | Netagy
Quility | Nanette | Bates | Quility
Dale | Dale | Adams | null
빈 문자열 처리 예제
source=accounts
| eval empty_field = ""
| eval result = coalesce(empty_field, firstname)
| fields result, empty_field, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | empty_field | firstname |
 |  | Amber
 |  | Hattie
 |  | Nanette
 |  | Dale
source=accounts
| eval result = coalesce(" ", firstname)
| fields result, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname |
 | Amber
 | Hattie
 | Nanette
 | Dale
자동 강제 변환을 포함한 혼합 데이터 타입
source=accounts
| eval result = coalesce(employer, balance, "fallback")
| fields result, employer, balance

쿼리는 다음과 같은 결과를 반환해요:

| result | employer | balance |
Pyrami | Pyrami | 39225
Netagy | Netagy | 5686
Quility | Quility | 32838
4180 | null | 4180
존재하지 않는 필드 처리
source=accounts
| eval result = coalesce(nonexistent_field, firstname, "unknown")
| fields result, firstname

쿼리는 다음과 같은 결과를 반환해요:

| result | firstname |
Amber | Amber
Hattie | Hattie
Nanette | Nanette
Dale | Dale

ISPRESENT

사용법: ispresent(field)

필드가 존재하면 TRUE를, 그렇지 않으면 FALSE를 반환해요.

매개변수:

  • field (필수): 존재 여부를 확인할 필드예요.

반환 타입: BOOLEAN

동의어 (Synonyms): ISNOTNULL

예제
source=accounts
| where ispresent(employer)
| fields employer, firstname

쿼리는 다음과 같은 결과를 반환해요:

| employer | firstname |
Pyrami | Amber
Netagy | Hattie
Quility | Nanette

ISBLANK

사용법: isblank(field)

필드가 NULL, 빈 문자열, 또는 공백만 포함하면 TRUE를 반환해요.

매개변수:

  • field (필수): 빈(blank) 값 여부를 확인할 필드예요.

반환 타입: BOOLEAN

예제
source=accounts
| eval temp = ifnull(employer, '   ')
| eval `isblank(employer)` = isblank(employer), `isblank(temp)` = isblank(temp)
| fields `isblank(temp)`, temp, `isblank(employer)`, employer

쿼리는 다음과 같은 결과를 반환해요:

| isblank(temp) | temp | isblank(employer) | employer |
False | Pyrami | False | Pyrami
False | Netagy | False | Netagy
False | Quility | False | Quility
True |  | True | null

ISEMPTY

사용법: isempty(field)

필드가 NULL이거나 빈 문자열이면 TRUE를 반환해요.

매개변수:

  • field (필수): 빈(empty) 값 여부를 확인할 필드예요.

반환 타입: BOOLEAN

예제
source=accounts
| eval temp = ifnull(employer, '   ')
| eval `isempty(employer)` = isempty(employer), `isempty(temp)` = isempty(temp)
| fields `isempty(temp)`, temp, `isempty(employer)`, employer

쿼리는 다음과 같은 결과를 반환해요:

| isempty(temp) | temp | isempty(employer) | employer |
False | Pyrami | False | Pyrami
False | Netagy | False | Netagy
False | Quility | False | Quility
False |  | True | null

EARLIEST

사용법: earliest(relative_string, field)

필드 값이 relative_string에서 파생된 타임스탬프(현재 시간 기준) 이후이면 TRUE를, 그렇지 않으면 FALSE를 반환해요.

매개변수:

  • relative_string (필수): 지원되는 형식 중 하나의 기준 시간 사양이에요.
  • field (필수): 기준 시간과 비교할 타임스탬프 필드예요.

반환 타입: BOOLEAN

상대 문자열 형식 (Relative string formats):

  • "now" 또는 "now()": 현재 시스템 시간을 사용해요.
  • 절대 형식 (MM/dd/yyyy:HH:mm:ss 또는 yyyy-MM-dd HH:mm:ss): 문자열을 타임스탬프로 변환해 필드 값과 비교해요.
  • 상대 형식: (+|-)<time_integer><time_unit>[+<...>]@<snap_unit>

상대 시간 지정 단계:

  • 시간 오프셋: + 또는 -를 사용해 현재 시간에서의 오프셋을 나타내요.
  • 시간 수량: 시간 단위(s, m, h, d, w, M, y)가 뒤따르는 숫자 값을 제공해요.
  • 단위로 스냅: 선택적으로 @<unit>을 사용해 스냅 단위를 지정해 결과를 가장 가까운 단위(예: 시간, 일, 월)로 내림해요.

예시 (현재 시간이 2025-05-28 14:28:34라고 가정):

  • -3d+2y → 2027-05-25 14:28:34.
  • +1d@m → 2025-05-29 14:28:00.
  • -3M+1y@M → 2026-02-01 00:00:00.
예제

다음 예제는 타임스탬프를 현재 시간 및 상대 시간과 비교해요:

source=accounts
| eval now = utc_timestamp()
| eval a = earliest("now", now), b = earliest("-2d@d", now)
| fields a, b
| head 1

쿼리는 다음과 같은 결과를 반환해요:

| a | b |
False | True

다음 예제는 절대 시간 형식을 사용해 레코드를 필터링해요:

source=nyc_taxi
| where earliest('07/01/2014:00:30:00', timestamp)
| stats COUNT() as cnt

쿼리는 다음과 같은 결과를 반환해요:

| cnt |
972

LATEST

사용법: latest(relative_string, field)

필드 값이 relative_string에서 파생된 타임스탬프(현재 시간 기준) 이전이면 TRUE를, 그렇지 않으면 FALSE를 반환해요.

매개변수:

  • relative_string (필수): 지원되는 형식 중 하나의 기준 시간 사양이에요.
  • field (필수): 기준 시간과 비교할 타임스탬프 필드예요.

반환 타입: BOOLEAN

예제

다음 예제는 latest 함수로 타임스탬프를 비교해요:

source=accounts
| eval now = utc_timestamp()
| eval a = latest("now", now), b = latest("+2d@d", now)
| fields a, b
| head 1

쿼리는 다음과 같은 결과를 반환해요:

| a | b |
True | True

다음 예제는 절대 시간 형식으로 latest를 사용해 레코드를 필터링해요:

source=nyc_taxi
| where latest('07/21/2014:04:00:00', timestamp)
| stats COUNT() as cnt

쿼리는 다음과 같은 결과를 반환해요:

| cnt |
969

REGEXP_MATCH

사용법: regexp_match(string, pattern)

정규 표현식 패턴이 문자열 값의 하위 문자열과 일치하면 TRUE를, 그렇지 않으면 FALSE를 반환해요. 함수는 패턴에 Java 정규 표현식 구문을 사용해요.

매개변수:

  • string (필수): 검색할 문자열이에요.
  • pattern (필수): 대조할 정규 표현식 패턴이에요.

반환 타입: BOOLEAN

예제

다음 예제는 정규 표현식 패턴으로 로그 메시지를 필터링해요:

source=logs
| where regexp_match(message, 'ERROR|WARN|FATAL')
| fields timestamp, message
timestamp | message
2024-01-15 10:23:45 | ERROR: Connection timeout to database
2024-01-15 10:24:12 | WARN: High memory usage detected
2024-01-15 10:25:33 | FATAL: System crashed unexpectedly

다음 예제는 정규 표현식을 사용해 이메일 주소를 검증해요:

source=users
| where regexp_match(email, '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}')
| fields name, email
name | email
John | [email protected]
Alice | [email protected]

다음 예제는 정규 표현식을 사용해 유효한 공용 IP 주소를 필터링해요:

source=network
| where regexp_match(ip_address, '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') AND NOT regexp_match(ip_address, '^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)')
| fields ip_address, status
ip_address | status
8.8.8.8 | active
1.1.1.1 | active

다음 예제는 대소문자 무시 매칭으로 제품 분류에 정규 표현식을 사용해요:

source=products
| eval category = if(regexp_match(name, '(?i)(laptop|computer|desktop)'), 'Computing', if(regexp_match(name, '(?i)(phone|tablet|mobile)'), 'Mobile', 'Other'))
| fields name, category
name | category
Dell Laptop XPS | Computing
iPhone 15 Pro | Mobile
Wireless Mouse | Other

더 알아보기 (Learn more)