Star-tree index
출처: 문서
본문
Star-tree 인덱스
_star-tree 인덱스_는 다양한 수준의 세분화에서 집계 값을 미리 계산하고 저장함으로써 집계 성능을 향상시키도록 설계된 특수한 인덱스 구조예요. 이 인덱싱 기법을 사용하면 특히 멀티 필드 집계에서 집계 실행 속도를 높일 수 있어요.
star-tree 인덱스를 활성화하고 나면, 필터 필드가 star-tree 매핑 구성에 정의된 차원과 일치하고 집계 필드가 정의된 메트릭과 일치하는 경우 OpenSearch가 지원되는 집계를 최적화하기 위해 star-tree 인덱스를 자동으로 빌드하고 사용해요. 쿼리 문법이나 요청 파라미터를 변경할 필요는 없어요.
집계 속도를 높이고 싶다면 star-tree 인덱스를 사용하세요:
- star-tree 인덱스는 멀티 필드 집계를 기본적으로 지원해요.
- star-tree 인덱스는 인덱싱 과정의 일부로 실시간으로 생성되기 때문에 star-tree의 데이터는 항상 최신 상태예요.
- star-tree 인덱스는 데이터를 집계해서 검색 쿼리 중 페이징 효율을 높이고 디스크 I/O를 줄여요.
Star-tree 인덱스 구조
star-tree 인덱스는 차원 필드 조합 전반에 걸쳐 데이터를 구성하고 집계하며, 수집 중 세그먼트가 flush되거나 refresh될 때마다 모든 차원 조합에 대한 메트릭 값을 미리 계산해요. 이 구조 덕분에 OpenSearch는 모든 문서를 하나씩 훑지 않고도 집계 쿼리를 빠르게 처리할 수 있어요.
다음은 star-tree 구성 예시예요:
"ordered_dimensions": [
{
"name": "status"
},
{
"name": "port"
}
],
"metrics": [
{
"name": "size",
"stats": [
"sum"
]
},
{
"name": "latency",
"stats": [
"avg"
]
}
]
이 구성은 다음을 정의해요:
- 두 개의 차원 필드:
status와port.ordered_dimension필드는 데이터가 정렬되는 방식을 지정해요(먼저status, 그다음port순). - 두 개의 메트릭 필드:
size와latency, 그리고 각각에 대응하는 집계(sum과avg). 고유한 차원 조합마다 메트릭 값(Sum(size)과Avg(latency))이 미리 집계되어 star-tree 구조에 저장돼요.
OpenSearch는 이 구성을 바탕으로 star-tree 인덱스 구조를 만들어요. 트리의 각 노드는 차원의 값(또는 와일드카드 *)에 해당해요. 쿼리 시점에는 쿼리에 지정된 차원 값을 기준으로 트리를 순회해요.
리프 노드
리프 노드에는 특정 차원 조합에 대해 미리 계산된 메트릭 집계가 담겨 있어요. 이 값들은 doc values로 저장되고 star-tree 노드에서 참조돼요.
max_leaf_docs 설정은 각 리프 노드가 참조할 수 있는 문서 수를 제어해요. 노드별로 스캔하는 문서 수를 제한해서 쿼리 지연 시간을 예측 가능하게 유지하는 데 도움이 돼요.
스타 노드
스타 노드(아래 다이어그램에서 *로 표시)는 특정 차원의 모든 값을 집계해요. 쿼리가 해당 차원에 대한 필터를 지정하지 않으면, OpenSearch는 여러 리프 노드를 하나씩 순회하는 대신 스타 노드에서 미리 계산된 집계를 가져와요. 예를 들어 쿼리가 port로는 필터링하지만 status로는 필터링하지 않는다면, OpenSearch는 모든 status 값에 대한 데이터를 집계해 둔 스타 노드를 사용할 수 있어요.
쿼리가 star-tree를 사용하는 방식
다음 다이어그램은 이 예시를 위해 만든 star-tree 인덱스와 세 가지 예시 쿼리 경로를 보여줘요. 다이어그램에서 각 브랜치가 차원(status와 port)에 해당한다는 점에 주목하세요. 일부 노드에는 미리 계산된 집계 값(예: Sum(size))이 들어 있어서 OpenSearch가 쿼리 시점에 불필요한 계산을 건너뛸 수 있어요.

색이 있는 화살표는 세 가지 쿼리 예시를 보여줘요:
-
파란색 화살표: 메트릭 집계가 있는 멀티 텀 쿼리 이 쿼리는
status = 200과port = 5600두 조건으로 모두 필터링하고 요청 크기의 합을 계산해요.- OpenSearch는 다음 경로를 따라요:
Root → 200 → 5600 - Doc ID 1에서 메트릭을 가져오며, 여기서
Sum(size) = 988이에요.
- OpenSearch는 다음 경로를 따라요:
-
초록색 화살표: 메트릭 집계가 있는 싱글 텀 쿼리 이 쿼리는
status = 200조건만으로 필터링하고 요청 지연 시간의 평균을 계산해요.- OpenSearch는 다음 경로를 따라요:
Root → 200 → * - Doc ID 5에서 메트릭을 가져오며, 여기서
Avg(latency) = 70이에요.
- OpenSearch는 다음 경로를 따라요:
-
빨간색 화살표: 메트릭 집계가 있는 싱글 텀 쿼리 이 쿼리는
port = 8443조건만으로 필터링하고 요청 크기의 합을 계산해요.- OpenSearch는 다음 경로를 따라요:
Root → * → 8443 - Doc ID 7에서 메트릭을 가져오며, 여기서
Sum(size) = 1111이에요.
- OpenSearch는 다음 경로를 따라요:
이 예시들은 OpenSearch가 star-tree에서 가장 짧은 경로를 선택하고 미리 집계된 값을 활용해서 쿼리를 효율적으로 처리하는 방식을 보여줘요.
제약 사항
star-tree 인덱스의 다음 제약 사항에 유의하세요:
- star-tree 인덱스는 업데이트와 삭제를 지원하지 않아요. star-tree 인덱스를 사용하려면 데이터가 append-only여야 해요. 자세한 내용은 star-tree 인덱스 활성화를 참조하세요.
- star-tree 인덱스는 인덱스의 star-tree 구성에 정의된 차원 필드로 필터링하고 메트릭 필드를 집계하는 집계 쿼리에만 동작해요.
- star-tree 구성을 변경하면 재인덱싱이 필요해요.
- 배열 값은 지원되지 않아요.
- 특정 쿼리와 집계만 지원돼요.
_id처럼 카디널리티가 높은 필드를 차원으로 사용하지 마세요. 저장 공간 사용량과 쿼리 지연 시간이 크게 늘어날 수 있어요.
star-tree 인덱스 활성화
star-tree 인덱싱 동작은 다음 클러스터 수준 및 인덱스 수준 설정으로 제어돼요. 인덱스 수준 설정이 클러스터 설정보다 우선해요.
| 설정 | 범위 | 기본값 | 설명 |
|---|---|---|---|
indices.composite_index.star_tree.enabled |
클러스터 | true |
클러스터 전체에서 star-tree 검색 최적화를 활성화하거나 비활성화해요. |
index.composite_index |
인덱스 | 없음 | 특정 인덱스에 대해 star-tree 인덱싱을 활성화해요. 인덱스를 생성할 때 설정해야 해요. |
index.append_only.enabled |
인덱스 | 없음 | star-tree 인덱스에 필요해요. 업데이트와 삭제를 막아요. true여야 해요. |
index.search.star_tree_index.enabled |
인덱스 | true |
인덱스에 대한 검색 쿼리에서 star-tree 인덱스 사용을 활성화하거나 비활성화해요. |
indices.composite_index.star_tree.enabled를 false로 설정하면 OpenSearch가 검색 중 star-tree 최적화를 사용하지 않지만, star-tree 인덱스 구조는 여전히 생성돼요. star-tree 구조를 완전히 제거하려면 star-tree 매핑 없이 데이터를 재인덱싱해야 해요.
{: .note}
고급 star-tree 인덱스 설정
다음 인덱스 수준 설정을 사용하면 star-tree 인덱스 동작을 세밀하게 제어할 수 있어요. 이 설정들은 정적 설정이라 인덱스를 생성할 때 구성해야 하며, 나중에 변경할 수 없어요.
| 설정 | 기본값 | 범위 | 설명 |
|---|---|---|---|
index.composite_index.star_tree.default.max_leaf_docs |
10000 |
최소: 1 |
리프 노드에 허용되는 최대 문서 수를 설정해요. 값을 낮추면 쿼리 지연 시간은 개선되지만 저장 공간 요구 사항은 커져요. |
index.composite_index.star_tree.field.default.metrics |
["value_count", "sum"] |
N/A | star-tree 집계를 위해 계산되는 기본 메트릭을 정의해요. 이 메트릭들은 집계 쿼리 속도를 높이기 위해 미리 계산돼요. |
index.composite_index.star_tree.field.max_base_metrics |
100 |
4~100 |
star-tree 필드에 구성할 수 있는 기본 메트릭의 최대 개수를 제어해요. 메트릭이 많을수록 집계 옵션이 늘어나지만 인덱스 크기는 커져요. |
index.composite_index.star_tree.field.max_dimensions |
10 |
2~10 |
star-tree 인덱스 필드에 포함될 수 있는 차원의 최대 개수를 설정해요. star-tree 인덱스 크기와 쿼리 성능에 영향을 줘요. |
index.composite_index.star_tree.field.max_date_intervals |
3 |
1~3 |
star-tree 날짜 필드에 구성할 수 있는 날짜 간격의 최대 개수를 지정해요. 시간 세분화 옵션을 제어해요. |
index.composite_index.star_tree.max_fields |
1 |
1~1 |
인덱스별 star-tree 필드의 최대 개수를 제어해요. 인덱스당 star-tree 필드는 하나만 지원돼요. |
star-tree 인덱스를 사용하는 인덱스를 만들려면 다음 요청을 보내세요:
PUT /logs
{
"settings": {
"index.composite_index": true,
"index.append_only.enabled": true
}
}
{% include copy-curl.html %}
star-tree 매핑에 사용하는 차원 및 메트릭 필드에 doc_values 파라미터가 활성화되어 있는지 확인하세요. 대부분의 필드 타입에서는 기본적으로 활성화되어 있어요. 자세한 내용은 Doc values를 참조하세요.
star-tree 사용 비활성화
기본적으로 indices.composite_index.star_tree.enabled 클러스터 설정과 index.search.star_tree_index.enabled 인덱스 설정은 모두 true로 되어 있어요. star-tree 인덱스를 사용한 검색을 비활성화하려면 이 두 설정을 모두 false로 설정하세요. 인덱스 설정이 클러스터 설정보다 우선한다는 점에 유의하세요.
매핑 예시
다음 예시는 logs 인덱스에서 집계를 미리 계산하는 star-tree 인덱스를 만드는 방법을 보여줘요. sum과 average 집계는 차원 필드 값의 모든 조합에 대해 각각 size와 latency 필드로 계산돼요. 차원은 status, 그다음 port, 마지막으로 method 순으로 정렬되며, 이 순서가 트리 구조에서 데이터가 조직되는 방식을 결정해요:
PUT /logs
{
"settings": {
"index.number_of_shards": 1,
"index.number_of_replicas": 0,
"index.composite_index": true,
"index.append_only.enabled": true
},
"mappings": {
"composite": {
"request_aggs": {
"type": "star_tree",
"config": {
"date_dimension" : {
"name": "@timestamp",
"calendar_intervals": [
"month",
"day"
]
},
"ordered_dimensions": [
{
"name": "status"
},
{
"name": "port"
},
{
"name": "method"
}
],
"metrics": [
{
"name": "size",
"stats": [
"sum"
]
},
{
"name": "latency",
"stats": [
"avg"
]
}
]
}
}
},
"properties": {
"status": {
"type": "integer"
},
"port": {
"type": "integer"
},
"size": {
"type": "integer"
},
"method" : {
"type": "keyword"
},
"latency": {
"type": "scaled_float",
"scaling_factor": 10
}
}
}
}
{% include copy.html %}
star-tree 인덱스 매핑과 파라미터에 대한 자세한 내용은 Star-tree 필드 타입을 참조하세요.
지원되는 쿼리와 애그리게이션
Star-tree 인덱스는 애그리게이션을 최적화해요. star-tree 최적화를 사용하려면 모든 쿼리에 최소 하나 이상의 지원되는 애그리게이션이 포함되어야 해요.
지원되는 쿼리
애그리게이션이 없는 쿼리는 star-tree 최적화를 사용할 수 없어요. 쿼리의 필드는 star-tree 설정의 ordered_dimensions 섹션에 존재해야 해요. 다음 쿼리가 지원돼요:
Boolean 쿼리 제약 조건
star-tree 인덱스의 Boolean 쿼리는 절 타입별로 특정 규칙을 따라요:
-
must와filter절:- 둘 다 지원되며,
filter는 스코어링에 영향을 주지 않기 때문에 같은 방식으로 처리돼요. - 서로 다른 차원에 걸쳐 동작할 수 있어요.
- 중첩된 절을 포함해 모든
must/filter절 전체에서 차원당 하나의 조건만 허용해요. - term, terms, range 쿼리를 지원해요.
- 둘 다 지원되며,
-
should절:- 같은 차원에서 동작해야 하며, 서로 다른 차원에 걸쳐 동작할 수 없어요
- term, terms, range 쿼리만 사용할 수 있어요.
-
must절 안의should절:- 필수 조건으로 동작해요.
- 외부
must와 같은 차원에서 동작할 때:should조건들의 합집합이 외부must조건과 교집합을 이뤄요. - 다른 차원에서 동작할 때: 필수 조건으로 정상적으로 처리돼요.
-
must_not절은 지원되지 않아요. -
minimum_should_match파라미터가 포함된 쿼리는 지원되지 않아요.
다음 Boolean 쿼리는 이러한 제약 조건을 따르기 때문에 지원돼요:
{
"bool": {
"must": [
{"term": {"method": "GET"}}
],
"filter": [
{"range": {"status": {"gte": 200, "lt": 300}}}
],
"should": [
{"term": {"port": 443}},
{"term": {"port": 8443}}
]
}
}
{% include copy.html %}
다음 Boolean 쿼리들은 이러한 제약 조건을 위반하기 때문에 지원되지 않아요:
{
"bool": {
"should": [
{"term": {"status": 200}},
{"term": {"method": "GET"}} // SHOULD across different dimensions
]
}
}
{
"bool": {
"must": [
{"term": {"status": 200}}
],
"must_not": [ // MUST_NOT not supported
{"term": {"method": "DELETE"}}
]
}
}
지원되는 애그리게이션
star-tree 인덱스는 다음 애그리게이션을 지원해요.
메트릭 애그리게이션
다음 메트릭 애그리게이션이 지원돼요:
star-tree 인덱스에서 애그리게이션을 검색 가능하게 사용하려면 다음 사전 조건을 충족해야 해요:
- 필드가 star-tree 설정의
metrics섹션에 있어야 해요. - 메트릭 애그리게이션 타입이
stats파라미터에 포함되어야 해요.
다음 예시는 예시 매핑을 사용해 status=500인 모든 에러 로그에 대해 size 필드 값 전체의 합계를 가져와요:
POST /logs/_search
{
"query": {
"term": {
"status": "500"
}
},
"aggs": {
"sum_size": {
"sum": {
"field": "size"
}
}
}
}
{% include copy.html %}
star-tree 인덱스를 사용하면 일치하는 모든 문서를 훑는 대신, status=500 노드를 순회하는 동안 단일 애그리게이션 문서에서 결과를 가져와요. 그 결과 쿼리 지연 시간이 낮아져요.
메트릭 애그리게이션을 포함한 date histogram
캘린더 간격에 대해 메트릭 서브 애그리게이션과 함께 date histogram을 사용할 수 있어요.
date histogram 애그리게이션을 사용하고 star-tree 인덱스에서 검색 가능하게 만들려면 다음 요구 사항을 기억해야 해요:
- star-tree 매핑 설정의 캘린더 간격은 요청의 캘린더 필드를 사용하거나, 요청 필드보다 더 낮은 단위의 필드를 사용할 수 있어요. 예를 들어, 애그리게이션이
month필드를 사용하더라도 star-tree 검색은day같은 더 낮은 단위의 필드를 계속 사용할 수 있어요. - 메트릭 서브 애그리게이션이 애그리게이션 요청에 반드시 포함되어야 해요.
다음 예시는 상태 코드가 200과 400 사이인 로그만 포함하도록 필터링하고, 애그리게이션 결과만 반환되도록 응답의 size를 0으로 설정해요. 그다음 필터링된 로그를 캘린더 월별로 애그리게이션하고 각 월에 대한 요청의 총 size를 계산해요:
POST /logs/_search
{
"size": 0,
"query": {
"range": {
"status": {
"gte": "200",
"lte": "400"
}
}
},
"aggs": {
"by_month": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "month"
},
"aggs": {
"sum_size": {
"sum": {
"field": "size"
}
}
}
}
}
}
{% include copy-curl.html %}
키워드 및 숫자 terms 애그리게이션
star-tree 인덱스 검색에서 키워드 필드와 숫자 필드 모두에 terms 애그리게이션을 사용할 수 있어요.
terms 애그리게이션과 star-tree 검색의 호환성을 위해 다음 동작을 기억해야 해요:
- terms 애그리게이션에 사용되는 필드는 star-tree 인덱스에 정의된 차원의 일부여야 해요.
- 관련 메트릭이 star-tree 설정의 일부이기만 하면 메트릭 서브 애그리게이션은 선택 사항이에요.
다음 예시는 user_id 필드를 기준으로 로그를 애그리게이션하고 각 고유 사용자별 개수를 반환해요:
POST /logs/_search
{
"size": 0,
"aggs": {
"users": {
"terms": {
"field": "user_id"
}
}
}
}
{% include copy-curl.html %}
다음 예시는 order_quantity를 기준으로 주문을 애그리게이션하고 각 수량에 대한 total_price의 평균을 계산해요:
POST /orders/_search
{
"size": 0,
"aggs": {
"quantities": {
"terms": {
"field": "order_quantity"
},
"aggs": {
"avg_total_price": {
"avg": {
"field": "total_price"
}
}
}
}
}
}
{% include copy-curl.html %}
range 애그리게이션
star-tree 인덱스 검색에서 숫자 필드에 range 애그리게이션을 사용할 수 있어요.
range 애그리게이션이 star-tree 인덱스와 효과적으로 동작하려면 다음 동작을 기억해야 해요:
- range 애그리게이션에 사용되는 필드는 star-tree 인덱스에 정의된 차원의 일부여야 해요.
- 관련 메트릭이 star-tree 설정의 일부이기만 하면, 정의된 각 범위 내에서 메트릭을 계산하도록 메트릭 서브 애그리게이션을 포함할 수 있어요.
다음 예시는 temperature 필드의 미리 정의된 범위를 기준으로 문서를 애그리게이션해요:
POST /sensors/_search
{
"size": 0,
"aggs": {
"temperature_ranges": {
"range": {
"field": "temperature",
"ranges": [
{ "to": 20 },
{ "from": 20, "to": 30 },
{ "from": 30 }
]
}
}
}
}
{% include copy-curl.html %}
다음 예시는 가격 범위별로 판매 데이터를 애그리게이션하고 각 범위 내에서 판매된 총 quantity를 계산해요:
POST /sales/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 500 },
{ "from": 500 }
]
},
"aggs": {
"total_quantity": {
"sum": {
"field": "quantity"
}
}
}
}
}
}
{% include copy-curl.html %}
중첩 애그리게이션
지원되는 여러 버킷 애그리게이션(예: terms, range)을 중첩 구조로 조합할 수 있으며, star-tree 인덱스가 이러한 중첩 애그리게이션을 최적화해 줘요. 중첩 애그리게이션에 대한 자세한 내용은 중첩 애그리게이션을 참조하세요.
multi-terms 애그리게이션
애그리게이션 필드가 star-tree 설정에서 차원으로 정의되어 있으면 star-tree 인덱스가 multi_terms 애그리게이션을 최적화해요. multi-terms 애그리게이션에 대한 자세한 내용은 multi-terms 애그리게이션을 참조하세요.