2016년 12월 13일 엔지니어링

Kibana 스크립트 필드에서 Painless 사용

By Tanya Bragin

Kibana는 Elasticsearch에 저장된 데이터를 검색하고 시각화할 수 있는 강력한 방법을 제공합니다. 시각화 도구로써, Kibana는 Elasticsearch 매핑에 정의된 필드를 찾아 사용 가능한 옵션으로 제공하여 사용자가 차트를 작성할 수 있게 합니다. 그러나 중요한 값을 스키마에서 별도 필드로 정의하지 못하였거나 또는 두 개 필드를 결합하여 단일 필드로 처리하고자 하는 경우에는 어떻게 해야할까요? 이 때 유용한 것이 바로 Kibana의 스크립트 필드입니다.

실제로 스크립트 필드가 처음 나온 것은 Kibana 4 초기때였습니다. 처음 도입되었을 때는 Elasticsearch 스크립트 언어 중 Lucene Expressions, 으로만 사용 가능하였고 숫자값만 정의할 수 있었으므로 스크립트 필드의 효과가 특정 용도로써 매우 제한적이었습니다. 5.0에서는 Elasticsearch가 다양한 데이터 유형에서 실행 가능한 안전하고 강력한 스크립트 언어인 Painless를 도입함으로써 Kibana 5.0의 스크립트 필드 역시 훨씬 더 강력해졌습니다.

이 블로그의 나머지 부분에서는 일반적인 사용 사례에 맞는 스크립트 필드를 생성하는 방법을 설명합니다. 이를 위해 Kibana 시작하기 자습서의 데이터 세트와 Elastic Cloud에서 실행 중인 Elasticsearch 및 Kibana 인스턴스를 사용합니다. 이 인스턴스는 Elastic Cloud에서 무료로 사용할 수 있습니다.

다음 동영상은 Elastic Cloud에서 개인 Elasticsearch 및 Kibana 인스턴스를 생성하고 샘플 데이터 세트를 로드하는 방법을 안내합니다. 

스크립트 필드 동작 방식

Elasticsearch에서는 모든 요청에 스크립트 필드를 사용할 수 있습니다. Kibana는 스크립트 필드를 관리(Management) 메뉴에서 한 번만 정의하여 이후 UI의 여러 위치에서 사용할 수 있다는 점에서 스크립트 필드의 효과를 향상시킵니다. Kibana는 스크립트 필드를 .kibana 인덱스에서 다른 구성과 함께 저장하지만 이 구성은 Kibana 고유 구성이기 때문에 Kibana 스크립트 필드가 Elasticsearch의 API 사용자에게 노출되지 않습니다.

Kibana에서 스크립트 필드를 정의하는 경우 스크립트 언어를 선택할 수 있습니다. 즉 동적 스크립트가 활성화된 Elasticsearch 노드에 설치된 모든 언어를 선택할 수 있습니다. 기본적으로 5.0의 경우 "expression", "painless"이고 2.x에서는 "expression"만 지원합니다. 다른 스크립트 언어를 설치하여 동적 스크립트를 활성화할 수도 있지만 샌드박스가 보장되지 않고 더 이상 사용되지 않으므로 권장하지 않습니다.

스크립트 언어는 한 번에 하나의 Elasticsearch 문서에서 실행되지만 해당 문서의 여러 필드를 참조할 수 있습니다. 따라서 스크립트 필드를 사용하여 단일 문서 내 필드를 결합 또는 변환할 수 있지만, 여러 문서를 기반으로 하는 계산(예를 들어 시계열 수식)을 수행하는 것은 적합하지 않습니다. Painless 및 Lucene expressions 모두 doc_values에 저장된 필드에서 실행됩니다. 따라서 문자열 데이터의 경우 keyword 유형으로 저장해야 합니다. Painless를 기반으로 하는 스크립트 필드는 또한 _source에서 직접 실행할 수 없습니다.

스크립트 필드가 “관리(Management)” 메뉴에서 정의되면 사용자는 Kibana 나머지 부분의 다른 필드와 동일한 방법으로 스크립트 필드를 사용할 수 있습니다. 스크립트 필드는 Discover 메뉴의 필드 목록에 자동으로 나타나며 시각화 생성을 위해 Visualize 메뉴에서 사용할 수 있습니다. Kibana는 연산을 위해 쿼리 시점에 스크립트 필드 정의를 Elasticsearch로 전달합니다. 결과 데이터 세트는 Elasticsearch의 다른 결과와 결합되어 테이블 또는 차트 형식으로 나타납니다.

이 블로그 작성 시점에는 스크립트 필드 사용에 있어 몇 가지 알려진 제한사항이 있습니다. Kibana 시각화 도구에서 사용 가능한 대부분의 Elasticsearch 어그리게이션을 스크립트 필드에 적용할 수 있지만 significant terms 어그리게이션은 예외입니다. 또한, 검색(Discover), 시각화(Visualize) 및 대시보드(Dashboard)의 필터 막대를 통해 스크립트 필드를 필터링할 수 있지만 아래 제시된 것과 같이 잘 정의된 값을 반환하는 올바른 스크립트를 작성해야 합니다. 아래 "모범 사례" 섹션을 참조하여 스크립트 필드 사용 시 환경을 안정적인 상태로 유지하는 것도 중요합니다.

다음 동영상은 Kibana를 사용하여 스크립트 필드를 생성하는 방법을 보여줍니다. 

스크립트 필드 예제

이 섹션에서는 일반적인 시나리오에서 Kibana의 Lucene expressions 및 Painless 스크립트 필드에 대한 몇 가지 예를 제시합니다. 앞에서 말한 것처럼 이들 예시는 Kibana 시작 튜토리얼의 데이터 세트로 개발되었으며 Elasticsearch와 Kibana 5.1.1을 사용하는 것을 가정합니다. 이전 버전에서는 특정 유형의 스크립트 필드 필터링 및 정렬과 관련하여 몇 가지 알려진 문제가 있기 때문입니다.

대부분 Elasticsearch 5.0에서는 기본적으로 Lucene expression과 Painless가 활성화되어 있으므로 스크립트 필드가 기본적으로 작동합니다. 단 정규식(regex) 기반 필드 구문 분석이 필요한 스크립트는 예외입니다. 이 경우에는 elasticsearch.yml에서 다음과 같이 설정을 저장하여 Painless에 대한 regex 지원을 활성화해야 합니다: script.painless.regex.enabled: true

단일 필드에서 계산 수행

  • 예제: 바이트로부터 킬로바이트 계산
  • 언어: expressions
  • 반환 유형: 숫자
 doc['bytes'].value / 1024

참고: Kibana 스크립트 필드는 한 번에 하나의 문서에서만 실행되므로 스크립트 필드에서 시계열 연산은 수행할 수 없습니다.

날짜 수식 계산

  • : 날짜 데이터를 하루 중 시간으로 계산
  • 언어: expressions
  • 반환 유형: 숫자

Lucene expressions는 처음부터 수많은 날짜 연산 함수를 제공합니다. 그러나 Lucene expressions는 숫자값만 반환하므로 요일값을 문자열로 반환하려면 Painless를 사용해야 합니다(아래 참조).

 doc['@timestamp'].date.hourOfDay

참고: 위 스크립는 1-24를 반환합니다.

doc['@timestamp'].date.dayOfWeek

참고: 위 스크립는 1-7을 반환합니다.

두 문자열 값 결합

  • : 시작점과 끝점 또는 이름과 성 결합
  • 언어: painless
  • 반환 유형: 문자열
 doc['geo.dest.keyword'].value + ':' + doc['geo.src.keyword'].value

참고: 스크립트 필드가 doc_values필드에서 실행되어야 하므로 위에서는 문자열의 .keyword필드값을 사용합니다.

논리연산 소개

  • : 10000바이트를 초과하는 모든 문서에 “big download” 레이블 반환
  • 언어: painless
  • 반환 유형: 문자열
 if (doc['bytes'].value > 10000) { 
    return "big download";
}
return "";

참고: 논리연산을 실행할 때는 모든 실행 경로가 잘 정의된 반환문과 잘 정의된 반환값(null이 아님)을 갖는지 확인합니다. 예를 들어, 위 스크립트 필드는 Kibana 필터에서 사용할 때 종료 시 반환문이 없거나 명령문이 null을 반환하는 경우 컴파일 오류와 함께 실패합니다. 또한, Kibana 스크립트 필드에서는 논리연산을 함수로 분해할 수 없습니다. 

하위 문자열 반환

  • : URL에서 마지막 슬래시 뒤에 파트를 반환합니다.
  • 언어: painless
  • 반환 유형: 문자열
 def path = doc['url.keyword'].value;
if (path != null) {
    int lastSlashIndex = path.lastIndexOf('/');
    if (lastSlashIndex > 0) {
    return path.substring(lastSlashIndex+1);
    }
}
return "";

참고: 가능하면 하위 문자열을 추출하기 위해 정규 표현식을 사용하지 마십시오. indexOf() 연산은 리소스를 많이 사용하지 않고 오류 발생이 적기 때문입니다. 

정규식을 사용하여 문자열 일치에 대한 조치 수행

  • : “referer” 필드에 하위 문자열 “error”가 있는 경우 문자열 “error”를 반환하고 그렇지 않으면 문자열 “no error”를 반환합니다.
  • 언어: painless
  • 반환 유형: 문자열
if (doc['referer.keyword'].value =~ /error/) { 
return "error"
} else {
return "no error"
}

참고: 정규식 일치 조건을 찾는데는 단순 정규식(Simplified regex) 구문이 유용합니다. 

문자열 일치 및 일치 문자열 반환

  • : “host” 필드에서 마지막 마침표 뒤 문자열인 도메인을 반환합니다.
  • 언어: painless
  • 반환 유형: 문자열
def m = /^.*\.([a-z]+)$/.matcher(doc['host.keyword'].value);
if ( m.matches() ) {
   return m.group(1)
} else {
   return "no match"
}

참고: 정규식의 matcher() 함수를 통해 개체를 정의하면 정규식과 일치하는 문자 그룹을 추출하여 반환할 수 있습니다. 

숫자 일치 및 일치 숫자 반환

  • 예: IP 주소의 첫 번째 옥텟(문자열로 저장된)을 반환하고 숫자로 처리합니다.
  • 언어: painless
  • 반환 유형: 숫자
 def m = /^([0-9]+)\..*$/.matcher(doc['clientip.keyword'].value);
if ( m.matches() ) {
   return Integer.parseInt(m.group(1))
} else {
   return 0
}

참고: 반드시 스크립트에 올바른 데이터 유형을 반환해야 합니다. 정규식 일치는 숫자가 일치하더라도 문자열을 반환하므로 반환 시 정수로 명시적으로 변환해야 합니다. 

날짜 수식의 문자열 반환

  • : 날짜를 요일 문자열로 구문 분석
  • 언어: painless
  • 반환 유형:: 문자열
LocalDateTime.ofInstant(Instant.ofEpochMilli(doc['@timestamp'].value), ZoneId.of('Z')).getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())

참고: Painless는 모든 Java 기본 유형을 지원하므로 이들 유형과 관련된 원시 함수(예를 들어, LocalDateTime()에 액세스할 수 있습니다. 이는 고급 날짜 수식을 처리하는 데 유용합니다.

모범 사례

보셨다시피, Painless 스크립트 언어는 Kibana 스크립트 필드를 통해 Elasticsearch에 저장된 임의 필드에서 유용한 정보를 추출할 수 있는 강력한 방법을 제공합니다. 그러나 강력한 힘에는 큰 책임이 뒤따릅니다. 

다음은 Kibana 스크립트 필드 사용과 관련된 몇 가지 모범 사례에 대한 개괄적인 설명입니다.

  • 스크립트 필드 실험을 위해서는 항상 개발 환경을 사용합니다. 스크립트 필드는 Kibana의 관리(Management) 섹션에 저장한 후 즉시 활성화되므로(예를 들어 해당 인덱스 패턴에 대한 검색(Discover) 화면에 나타나 모든 사용자가 볼 수 있음) 운영 환경에서 직접 스크립트 필드를 개발해서는 안 됩니다. 먼저 개발 환경에서 구문을 시험해보고 스테이징에서 실제 데이터 세트 및 데이터 볼륨에 대한 스크립트 필드의 영향을 평가한 후 운영 환경으로 이관시키는 것이 좋습니다. 
  • 스크립트 필드가 사용자에게 가치를 제공한다는 확신을 얻게 되면 수집 환경 설정을 수정하여 새 데이터의 색인 시점에 필드를 추출하는 방법을 고려할 수 있습니다. 이 방법을 사용하면 검색 시점에 Elasticsearch 처리 시간이 단축되어 Kibana 사용자에 대한 응답 시간이 빨라집니다. 또한, Elasticsearch의 _reindex API를 사용하여 기존 데이터를 다시 색인 할 수도 있습니다.