Dissect
출처: 문서
본문
이 문서는 OpenSearch ingest 파이프라인에서 dissect 프로세서를 사용하는 방법을 설명해요. 사용 사례가 크거나 복잡한 데이터셋을 다룬다면, OpenSearch 클러스터에서 실행되는 Data Prepper dissect processor를 사용하는 것도 고려해 보세요.
{: .note}
Dissect
dissect 프로세서는 문서의 text 필드에서 값을 추출하고, dissect 패턴을 기준으로 개별 필드에 매핑해요. 이 프로세서는 구조를 알고 있는 로그 메시지에서 필드를 추출할 때 특히 잘 어울려요. grok 프로세서와 달리 dissect는 정규식을 사용하지 않고 문법도 더 간단해요.
문법
다음은 dissect 프로세서의 문법이에요:
{
"dissect": {
"field": "source_field",
"pattern": "%{dissect_pattern}"
}
}
{% include copy.html %}
설정 파라미터
다음 표는 dissect 프로세서의 필수 파라미터와 선택 파라미터를 정리한 거예요.
| 파라미터 | 필수/선택 | 설명 |
|---|---|---|
field |
필수 | dissect할 데이터가 담긴 필드의 이름이에요. |
pattern |
필수 | 지정한 필드에서 데이터를 추출하는 데 사용하는 dissect 패턴이에요. |
append_separator |
선택 | append되는 필드들을 구분하는 구분 문자 또는 문자열이에요. 기본값은 ""(빈 문자열)예요. |
description |
선택 | 프로세서에 대한 간단한 설명이에요. |
if |
선택 | 프로세서를 실행하기 위한 조건이에요. |
ignore_failure |
선택 | 프로세서가 오류를 만나더라도 실행을 계속할지 여부를 지정해요. true로 설정하면 프로세서 실패가 무시돼요. 기본값은 false예요. |
ignore_missing |
선택 | 지정한 필드가 없는 문서를 무시할지 여부를 지정해요. true로 설정하면 필드가 존재하지 않거나 null일 때 프로세서가 문서를 수정하지 않아요. 기본값은 false예요. |
on_failure |
선택 | 프로세서가 실패했을 때 실행할 프로세서 목록이에요. |
tag |
선택 | 프로세서의 식별용 태그예요. 같은 타입의 프로세서들을 구분할 때 디버깅에 유용해요. |
프로세서 사용하기
다음 단계에 따라 파이프라인에서 프로세서를 사용해 보세요.
1단계: 파이프라인 생성하기
다음 쿼리는 dissect 프로세서를 사용해 로그 라인을 파싱하는 dissect-test라는 이름의 파이프라인을 생성해요:
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "%{client_ip} - - [%{timestamp}] \"%{http_method} %{url} %{http_version}\" %{response_code} %{response_size}"
}
}
]
}
{% include copy-curl.html %}
2단계(선택): 파이프라인 테스트하기
문서를 ingest하기 전에 파이프라인을 테스트해 보는 것을 권장해요. {: .tip}
파이프라인을 테스트하려면 다음 쿼리를 실행해 보세요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "192.168.1.10 - - [03/Nov/2023:15:20:45 +0000] \"POST /login HTTP/1.1\" 200 3456"
}
}
]
}
{% include copy-curl.html %}
응답
다음 예시 응답을 보면 파이프라인이 기대한 대로 동작하고 있음을 확인할 수 있어요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"response_code": "200",
"http_method": "POST",
"http_version": "HTTP/1.1",
"client_ip": "192.168.1.10",
"message": """192.168.1.10 - - [03/Nov/2023:15:20:45 +0000] "POST /login HTTP/1.1" 200 3456""",
"url": "/login",
"response_size": "3456",
"timestamp": "03/Nov/2023:15:20:45 +0000"
},
"_ingest": {
"timestamp": "2023-11-03T22:28:32.830244044Z"
}
}
}
]
}
3단계: 문서 ingest하기
다음 쿼리는 testindex1이라는 이름의 인덱스에 문서를 ingest해요:
PUT testindex1/_doc/1?pipeline=dissect-test
{
"message": "192.168.1.10 - - [03/Nov/2023:15:20:45 +0000] \"POST /login HTTP/1.1\" 200 3456"
}
{% include copy-curl.html %}
4단계(선택): 문서 조회하기
문서를 조회하려면 다음 쿼리를 실행해 보세요:
GET testindex1/_doc/1
{% include copy-curl.html %}
Dissect 패턴
dissect 패턴은 문자열을 구조화된 형태로 파싱하는 방법을 dissect 프로세서에게 알려주는 방식이에요. 패턴은 문자열에서 버리고 싶은 부분들로 정의돼요. 예를 들어 %{client_ip} - - [%{timestamp}] dissect 패턴은 문자열 "192.168.1.10 - - [03/Nov/2023:15:20:45 +0000] \"POST /login HTTP/1.1\" 200 3456"을 다음 필드들로 파싱해요:
client_ip: "192.168.1.1"
@timestamp: "03/Nov/2023:15:20:45 +0000"
dissect 패턴은 문자열을 일련의 규칙과 매칭하는 방식으로 동작해요. 예를 들어 첫 번째 규칙은 공백 하나를 버려요. dissect 프로세서는 이 공백을 찾은 다음, 그 공백 앞에 있는 모든 문자를 client_ip 값으로 할당해요. 다음 규칙은 [ 문자와 ] 문자를 매칭하고, 그 사이의 모든 내용을 @timestamp 값으로 할당해요.
성공적인 dissect 패턴 만들기
dissect 패턴을 만들 때는 문자열에서 버리고 싶은 부분에 주의를 기울이는 게 중요해요. 문자열을 너무 많이 버리면 dissect 프로세서가 나머지 데이터를 제대로 파싱하지 못할 수 있어요. 반대로 문자열을 충분히 버리지 않으면 프로세서가 불필요한 필드를 만들어낼 수 있어요.
패턴에 정의된 %{keyname} 중 값이 없는 것이 있다면 예외가 발생해요. on_failure 파라미터에 오류 처리 단계를 지정해서 이 예외를 처리할 수 있어요.
빈 키와 named skip 키
빈 키 %{}나 named skip key는 값을 매칭하되 최종 문서에서는 해당 값을 제외할 때 사용해요. 문자열을 파싱하긴 하지만 모든 부분을 저장할 필요는 없을 때 유용해요.
매칭된 값을 non-string 데이터 타입으로 변환하기
기본적으로 모든 매칭된 값은 string 데이터 타입으로 표현돼요. 값을 다른 데이터 타입으로 변환해야 한다면 convert 프로세서를 사용할 수 있어요.
키 수정자
dissect 프로세서는 프로세서의 기본 동작을 바꿀 수 있는 키 수정자를 지원해요. 이 수정자들은 항상 %{keyname}의 왼쪽이나 오른쪽에 위치하고, 항상 %{} 안에 감싸여 있어요. 예를 들어 %{+keyname->} 수정자는 append 수정자와 오른쪽 패딩 수정자를 함께 포함하고 있어요. 키 수정자는 여러 필드를 한 줄의 출력으로 합치거나, 데이터 항목들의 포맷된 목록을 만들거나, 여러 소스의 값을 집계할 때 유용해요.
다음 표는 dissect 프로세서의 주요 수정자를 정리한 거예요.
수정자 | 이름 | 위치 | 예시 | 설명 |
|-----------|-----------|-----------|
-> | 오른쪽 패딩 건너뛰기 | (맨) 오른쪽 | %{keyname->} | dissect 프로세서에게 오른쪽에 반복되는 문자를 건너뛰라고 지시해요. 예를 들어 %{timestamp->}는 프로세서에게 timestamp 뒤에 이어지는 패딩 문자, 즉 연속된 두 개의 공백이나 길이가 달라지는 문자 패딩을 건너뛰도록 지시하는 데 사용할 수 있어요. |
+ | append | 왼쪽 | %{keyname} %{+keyname} | 두 개 이상의 필드를 append해요. |
+ with /n | 순서 지정 append | 왼쪽과 오른쪽 | %{+keyname}/2 %{+keyname/1} | 두 개 이상의 필드를 지정한 순서대로 append해요. |
? | named skip 키 | 왼쪽 | %{?skipme} | 매칭된 값을 출력에서 건너뛰어요. %{}와 동일한 동작을 해요. |
*와 & | 참조 키 | 왼쪽 | %{*r1} %{&r1} | *의 값은 출력 키로, &의 값은 출력 값으로 설정해요. |
각 키 수정자에 대한 자세한 설명과 사용 예시는 다음 섹션에서 제공해요.
오른쪽 패딩 수정자 (->)
dissection 알고리즘은 정밀해서 패턴의 모든 문자가 소스 문자열과 정확히 일치해야 해요. 예를 들어 패턴 %{hellokey} %{worldkey}(공백 1개)은 문자열 Hello world(공백 1개)와는 매칭되지만, 문자열 Hello world(공백 2개)와는 매칭되지 않아요. 패턴에는 공백이 1개뿐인 반면 소스 문자열에는 2개가 있기 때문이에요.
_오른쪽 패딩 수정자_를 사용하면 이 문제를 해결할 수 있어요. 패턴 %{helloworldkey->} %{worldkey}에 추가하면, 오른쪽 패딩 수정자는 Hello world(공백 1개), Hello world(공백 2개), 심지어 Hello world(공백 10개)까지 모두 매칭해요.
오른쪽 패딩 수정자는 %{keyname->} 뒤에 이어지는 문자의 반복을 허용하는 데 사용해요. 오른쪽 패딩 수정자는 다른 수정자와 함께 어떤 키에도 적용할 수 있어요. 항상 가장 오른쪽에 있는 수정자여야 해요. 예를 들어 %{+keyname/1->}나 %{}처럼요.
사용 예시
다음은 오른쪽 패딩 수정자를 사용하는 방법의 예시예요:
%{city->}, %{state} %{zip}
이 패턴에서는 오른쪽 패딩 수정자 ->가 %{city} 키에 적용돼요. 두 주소는 같은 정보를 담고 있지만, 두 번째 항목은 city 필드에 City라는 단어가 하나 더 들어 있어요. 오른쪽 패딩 수정자 덕분에 형식이 조금 다르더라도 패턴이 두 주소 항목 모두와 매칭될 수 있어요:
New York, NY 10017
New York City, NY 10017
다음 예시 파이프라인은 빈 키 %{->}와 함께 오른쪽 패딩 수정자를 사용해요:
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "[%{client_ip}]%{->}[%{timestamp}]"
}
}
]
}
{% include copy-curl.html %}
다음 예시를 사용해서 파이프라인을 테스트할 수 있어요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "[192.168.1.10] [03/Nov/2023:15:20:45 +0000]"
}
}
]
}
{% include copy-curl.html %}
응답은 다음과 비슷하게 나타나야 해요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"client_ip": "192.168.1.10",
"message": "[192.168.1.10] [03/Nov/2023:15:20:45 +0000]",
"timestamp": "03/Nov/2023:15:20:45 +0000"
},
"_ingest": {
"timestamp": "2024-01-22T22:55:42.090569297Z"
}
}
}
]
}
{% include copy-curl.html %}
append 수정자 (+)
_append 수정자_는 두 개 이상의 값을 하나의 출력 값으로 합쳐요. 값들은 왼쪽에서 오른쪽으로 append돼요. 값 사이에 삽입할 구분자를 선택적으로 지정할 수도 있어요.
사용 예시
다음은 append 수정자가 있는 예시 파이프라인이에요:
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "%{+address}, %{+address} %{+address}",
"append_separator": "|"
}
}
]
}
{% include copy-curl.html %}
다음 예시를 사용해서 파이프라인을 테스트할 수 있어요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "New York, NY 10017"
}
}
]
}
{% include copy-curl.html %}
다음 응답에서 볼 수 있듯이, 부분 문자열들이 address 필드에 append돼요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"address": "New York|NY|10017",
"message": "New York, NY 10017"
},
"_ingest": {
"timestamp": "2024-01-22T22:30:54.516284637Z"
}
}
}
]
}
{% include copy-curl.html %}
순서 지정 append 수정자 (+와 /n)
_순서 지정 append 수정자_는 두 개 이상의 키의 값을, / 뒤에 지정한 순서를 기준으로 하나의 출력 값으로 합쳐요. append되는 값들을 구분하는 구분자도 자유롭게 지정할 수 있어요. append 수정자는 여러 필드를 포맷된 한 줄의 출력으로 모으거나, 데이터 항목들의 구조화된 목록을 만들거나, 여러 소스의 값을 하나로 모을 때 유용해요.
사용 예시
다음 예시 파이프라인은 앞선 파이프라인에서 정의한 패턴 순서를 뒤집기 위해 순서 지정 append 수정자를 사용해요. 이 파이프라인은 append되는 필드들 사이에 삽입할 구분자를 지정해요. 구분자를 지정하지 않으면 모든 값이 구분자 없이 append돼요.
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "%{+address/3}, %{+address/2} %{+address/1}",
"append_separator": "|"
}
}
]
}
{% include copy-curl.html %}
다음 예시를 사용해서 파이프라인을 테스트할 수 있어요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "New York, NY 10017"
}
}
]
}
{% include copy-curl.html %}
다음 응답에서 볼 수 있듯이, 부분 문자열들이 역순으로 address 필드에 append돼요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"address": "10017|NY|New York",
"message": "New York, NY 10017"
},
"_ingest": {
"timestamp": "2024-01-22T22:38:24.305974178Z"
}
}
}
]
}
{% include copy-curl.html %}
named skip 키 수정자
_named skip 키 수정자_는 패턴 안에서 빈 키 {}나 ? 수정자를 사용해 특정 매칭을 최종 출력에서 제외해요. 예를 들어 다음 두 패턴은 동일해요: %{firstName} %{lastName} %{?ignore}와 %{firstName} %{lastName} %{}. named skip 키 수정자는 관련 없거나 불필요한 필드를 출력에서 제외할 때 유용해요.
사용 예시
다음 패턴은 named skip 키를 사용해 필드(여기서는 ignore)를 출력에서 제외해요. 빈 키에 설명이 있는 이름을 지정할 수 있는데, 예를 들어 %{?ignore}처럼 이름을 붙이면 해당 값을 최종 출력에서 제외해야 한다는 걸 명확히 알 수 있어요:
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "%{firstName} %{lastName} %{?ignore}"
}
}
]
}
{% include copy-curl.html %}
다음 예시를 사용해서 파이프라인을 테스트할 수 있어요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "John Doe M.D."
}
}
]
}
{% include copy-curl.html %}
응답은 다음과 비슷하게 나타나야 해요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"firstName": "John",
"lastName": "Doe",
"message": "John Doe M.D."
},
"_ingest": {
"timestamp": "2024-01-22T22:41:58.161475555Z"
}
}
}
]
}
{% include copy-curl.html %}
참조 키 (*와 &)
참조 키는 파싱된 값들을 구조화된 콘텐츠를 위한 키-값 쌍으로 사용해요. 데이터를 부분적으로 키-값 쌍으로 로깅하는 시스템을 다룰 때 유용할 수 있어요. 참조 키를 사용하면 키-값 관계를 보존하고 추출한 정보의 무결성을 유지할 수 있어요.
사용 예시
다음 패턴은 참조 키를 사용해 데이터를 구조화된 형태로 추출해요. 이 예시에서는 이어지는 값들에서 client_ip와 두 개의 키-값 쌍이 추출돼요:
PUT /_ingest/pipeline/dissect-test
{
"description": "Pipeline that dissects web server logs",
"processors": [
{
"dissect": {
"field": "message",
"pattern": "%{client_ip} %{*a}:%{&a} %{*b}:%{&b}"
}
}
]
}
{% include copy-curl.html %}
다음 예시를 사용해서 파이프라인을 테스트할 수 있어요:
POST _ingest/pipeline/dissect-test/_simulate
{
"docs": [
{
"_index": "testindex1",
"_id": "1",
"_source": {
"message": "192.168.1.10 response_code:200 response_size:3456"
}
}
]
}
{% include copy-curl.html %}
다음 응답에서 볼 수 있듯이, 두 개의 키-값 쌍이 필드로 추출됐어요:
{
"docs": [
{
"doc": {
"_index": "testindex1",
"_id": "1",
"_source": {
"client_ip": "192.168.1.10",
"response_code": "200",
"message": "192.168.1.10 response_code:200 response_size:3456",
"response_size": "3456"
},
"_ingest": {
"timestamp": "2024-01-22T22:48:51.475535635Z"
}
}
}
]
}
{% include copy-curl.html %}