본문 바로가기
WIKI 기술 지식 베이스

Analyze your data

원문 보기 위키 갱신

출처: 문서

본문

데이터 분석하기

이전 튜토리얼에서 만든 students 인덱스에는 문서가 세 개뿐이라서 응답의 각 결과를 직접 살펴볼 수 있었어요. 실제 환경의 인덱스는 수천 개의 문서를 담을 수 있어서 이 방식은 비현실적이에요. 이 튜토리얼에서는 약 13,000개의 문서를 담고 있는 Sample flight data 데이터셋을 탐색, 필터링, 정렬해 보고, 집계(aggregation)를 사용해 데이터를 요약하는 방법도 알아봐요.

샘플 데이터 추가하기

이 튜토리얼은 OpenSearch Dashboards에서 제공하는 샘플 데이터셋을 사용하기 때문에 실행 중인 OpenSearch Dashboards 인스턴스가 필요해요. Installation quickstart를 따라 했다면 설치에 OpenSearch Dashboards가 이미 포함되어 있을 거예요.

Sample flight data 데이터셋을 추가하려면 다음 단계를 따르세요:

  1. 웹 브라우저에서 http://localhost:5601을 여세요. 이 주소는 보안 없이 설정한 클러스터의 주소예요. 클러스터를 보안을 활성화해 설정했다면, https://localhost:5601을 열고 설정한 비밀번호로 admin 계정에 로그인하세요.
  2. OpenSearch Dashboards 홈 페이지에서 Add sample data를 선택하세요.
  3. Sample flight data 패널에서 Add data를 선택하세요.

데이터셋을 추가하면 opensearch_dashboards_sample_data_flights라는 이름의 인덱스가 생성돼요. 각 문서는 한 항공편을 나타내며, 운항사, 출발지와 도착지, 티켓 가격, 거리, 지연 정보를 기록하고 있어요.

OpenSearch Dashboards는 데이터셋을 추가할 때 문서 ID와 timestamp 값을 생성하기 때문에, 이 값들은 이 튜토리얼의 값과 다를 수 있어요. 다른 모든 필드 값은 고정된 데이터셋에서 오기 때문에 동일해요.

데이터 탐색하기

인덱스를 쿼리하기 전에 그 안에 무엇이 들어 있는지 먼저 확인하세요. 인덱스의 문서 수를 세려면 다음 요청을 보내세요:

GET /opensearch_dashboards_sample_data_flights/_count

{% include copy-curl.html %}

OpenSearch가 문서 개수를 반환해요:

{
  "count": 13059,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  }
}

필드 타입을 보려면 매핑을 요청하세요:

GET /opensearch_dashboards_sample_data_flights/_mapping

{% include copy-curl.html %}

응답에는 27개의 필드가 나열돼요. 이 튜토리얼의 예제에서는 다음 필드들을 사용해요.

필드 타입 설명
Carrier keyword 항공편을 운항하는 항공사
OriginCityName keyword 항공편이 출발하는 도시
DestCityName keyword 항공편이 도착하는 도시
DestCountry keyword 목적지의 두 자리 국가 코드
AvgTicketPrice float 평균 티켓 가격(달러)
FlightDelayMin integer 출발 지연 시간(분)
Cancelled boolean 항공편의 취소 여부
timestamp date 출발 날짜와 시간

이 인덱스의 모든 문자열 필드는 keyword로 매핑되어 있어서, 문자열 검색은 모두 정확히 일치하는 방식으로 이뤄져요. 분석된 text 필드에 대한 전문 검색은 Search your data를 참고하세요.

문서가 어떻게 생겼는지 보려면 결과를 하나만 반환하는 검색을 실행해 보세요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 1
}

{% include copy-curl.html %}

응답에는 항공편 하나가 담겨 있어요. 이 항공편은 프랑크푸르트에서 시드니로 갔고 지연되지 않았기 때문에 FlightDelayMin은 0이고 FlightDelay는 false예요:

"hits": [
  {
    "_index": "opensearch_dashboards_sample_data_flights",
    "_id": "3_6eY6ABLgrkzSeVlh5V",
    "_score": 1,
    "_source": {
      "FlightNum": "9HY9SWR",
      "DestCountry": "AU",
      "OriginWeather": "Sunny",
      "OriginCityName": "Frankfurt am Main",
      "AvgTicketPrice": 841.2656419677076,
      "DistanceMiles": 10247.856675613455,
      "FlightDelay": false,
      "DestWeather": "Rain",
      "Dest": "Sydney Kingsford Smith International Airport",
      "FlightDelayType": "No Delay",
      "OriginCountry": "DE",
      "dayOfWeek": 0,
      "DistanceKilometers": 16492.32665375846,
      "timestamp": "2026-08-24T00:00:00",
      "DestLocation": {
        "lat": "-33.94609833",
        "lon": "151.177002"
      },
      "DestAirportID": "SYD",
      "Carrier": "OpenSearch Dashboards Airlines",
      "Cancelled": false,
      "FlightTimeMin": 1030.7704158599038,
      "Origin": "Frankfurt am Main Airport",
      "OriginLocation": {
        "lat": "50.033333",
        "lon": "8.570556"
      },
      "DestRegion": "SE-BD",
      "OriginAirportID": "FRA",
      "OriginRegion": "DE-HE",
      "DestCityName": "Sydney",
      "FlightTimeHour": 17.179506930998397,
      "FlightDelayMin": 0
    }
  }
]

결과 필터링하기

다음 예제들은 size를 0으로 설정하는데, 이렇게 하면 OpenSearch가 문서 자체를 반환하지 않고 일치하는 문서의 개수만 반환해요. 어떤 문서가 일치하는지가 아니라 몇 개가 일치하는지 알고 싶을 때 사용하세요.

정확한 값 일치시키기

특정 운항사가 운항하는 항공편 수를 세려면 term 쿼리를 사용하세요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "query": {
    "term": {
      "Carrier": "OpenSearch-Air"
    }
  }
}

{% include copy-curl.html %}

OpenSearch는 일치하는 항공편 수를 hits.total.value에 보여줘요:

{
  "took": 13,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3220,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}

값의 범위 일치시키기

1시간 이상 지연된 항공편 수를 세려면 FlightDelayMin에 range 쿼리를 사용하세요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "query": {
    "range": {
      "FlightDelayMin": {
        "gte": 60
      }
    }
  }
}

{% include copy-curl.html %}

응답에는 2,867개의 항공편이 일치한다고 나와요:

{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2867,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}

조건 조합하기

실제 질문은 여러 조건을 조합하는 경우가 많아요. 한 운항사의 항공편 중 1시간 이상 지연되었고 취소되지 않은 항공편 수를 세려면 bool 쿼리를 사용하세요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "term": { "Carrier": "OpenSearch-Air" } },
        { "range": { "FlightDelayMin": { "gte": 60 } } }
      ],
      "must_not": [
        { "term": { "Cancelled": true } }
      ]
    }
  }
}

{% include copy-curl.html %}

응답에는 625개의 항공편이 일치한다고 나와요:

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 625,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}

filter 절은 모두 일치해야 하고, must_not 절에 일치하는 문서는 제외돼요. 자세한 내용은 Boolean queries를 참고하세요.

결과 정렬하고 필드 선택하기

기본적으로 OpenSearch는 점수가 가장 높은 10개의 문서와 각 문서의 전체 소스를 반환해요. 앞선 쿼리들은 필터만 사용했기 때문에 모든 문서의 점수가 같았고, 따라서 순서는 임의적이었어요. 순서를 직접 정하고 응답 크기를 줄이려면 sort, size, _source를 추가하세요.

다음 요청은 호주로 가는 항공편을 찾아서 가장 비싼 두 개를 반환하고, 각 문서에서 네 개의 필드만 포함해요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 2,
  "_source": ["Carrier", "OriginCityName", "DestCityName", "AvgTicketPrice"],
  "query": {
    "term": {
      "DestCountry": "AU"
    }
  },
  "sort": [
    { "AvgTicketPrice": "desc" }
  ]
}

{% include copy-curl.html %}

OpenSearch가 티켓 가격이 가장 높은 두 항공편을 반환해요:

{
  "took": 58,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 416,
      "relation": "eq"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "opensearch_dashboards_sample_data_flights",
        "_id": "wf6eY6ABLgrkzSeVlyX-",
        "_score": null,
        "_source": {
          "OriginCityName": "Paris",
          "AvgTicketPrice": 1197.6326773063201,
          "Carrier": "OpenSearch-Air",
          "DestCityName": "Sydney"
        },
        "sort": [
          1197.6327
        ]
      },
      {
        "_index": "opensearch_dashboards_sample_data_flights",
        "_id": "A_6eY6ABLgrkzSeVolFS",
        "_score": null,
        "_source": {
          "OriginCityName": "Billings",
          "AvgTicketPrice": 1191.012703382442,
          "Carrier": "Logstash Airways",
          "DestCityName": "Brisbane"
        },
        "sort": [
          1191.0127
        ]
      }
    ]
  }
}

hits.total.value 필드는 일치하는 항공편이 416개라고 알려주고, size가 응답을 그중 2개로 제한해요. 각 hit에는 OpenSearch가 정렬에 사용한 값이 담긴 sort 배열이 들어 있고, 필드로 정렬하면 관련성 순위가 대체되기 때문에 _score는 null이에요.

집계를 사용해 데이터 요약하기

지금까지의 쿼리는 문서를 반환하거나 개수를 세었어요. _집계(aggregation)_는 많은 문서를 하나의 결과로 요약하는 기능으로, 가장 자주 지연되는 운항사가 어디인지 같이 개별 문서에는 담겨 있지 않은 질문에 답할 때 사용해요.

그룹별 문서 개수 세기

terms 집계는 필드 값을 기준으로 문서를 그룹화하고 각 그룹의 개수를 세요. 다음 요청은 운항사별로 운항하는 항공편 수를 세요. size를 0으로 설정하면 13,059개의 일치하는 문서가 응답에 포함되지 않아서 요약 결과만 남아요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "flights_per_carrier": {
      "terms": {
        "field": "Carrier"
      }
    }
  }
}

{% include copy-curl.html %}

OpenSearch는 운항사별로 버킷을 하나씩, 문서 개수를 기준으로 정렬해서 반환해요:

{
  "took": 6,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "flights_per_carrier": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Logstash Airways",
          "doc_count": 3331
        },
        {
          "key": "BeatsWest",
          "doc_count": 3274
        },
        {
          "key": "OpenSearch Dashboards Airlines",
          "doc_count": 3234
        },
        {
          "key": "OpenSearch-Air",
          "doc_count": 3220
        }
      ]
    }
  }
}

hits.total.value 필드는 relation이 gte인 상태로 10000을 보여주는데, 일치 개수가 10,000에 도달하면 OpenSearch가 정확한 총계 추적을 멈추기 때문이에요. 근사치인 것은 총 히트 개수뿐이에요. 집계에는 여전히 일치하는 모든 문서가 포함되므로, 버킷 개수를 모두 더하면 13,059개 항공편 전체와 일치해요.

그룹별 지표 계산하기

집계를 다른 집계 안에 중첩하면 버킷마다 지표를 계산할 수 있어요. 다음 요청은 각 운항사 내에서 FlightDelayMin의 평균을 구하는 avg 집계를 추가해요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "flights_per_carrier": {
      "terms": {
        "field": "Carrier"
      },
      "aggs": {
        "average_delay": {
          "avg": {
            "field": "FlightDelayMin"
          }
        }
      }
    }
  }
}

{% include copy-curl.html %}

이제 각 버킷에는 해당 운항사의 평균 지연 시간이 담겨 있어요. Logstash Airways의 평균 지연이 약 50분으로 가장 길어요:

{
  "took": 2,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "flights_per_carrier": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Logstash Airways",
          "doc_count": 3331,
          "average_delay": {
            "value": 49.55268688081657
          }
        },
        {
          "key": "BeatsWest",
          "doc_count": 3274,
          "average_delay": {
            "value": 45.957544288332315
          }
        },
        {
          "key": "OpenSearch Dashboards Airlines",
          "doc_count": 3234,
          "average_delay": {
            "value": 46.368274582560296
          }
        },
        {
          "key": "OpenSearch-Air",
          "doc_count": 3220,
          "average_delay": {
            "value": 47.41304347826087
          }
        }
      ]
    }
  }
}

시간별로 문서 그룹화하기

date_histogram 집계는 문서를 시간 간격별로 그룹화하는 기능으로, 시간의 흐름에 따른 데이터를 차트로 나타낼 때 사용해요. 다음 요청은 주별 항공편 수를 세요:

GET /opensearch_dashboards_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "flights_over_time": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "week"
      }
    }
  }
}

{% include copy-curl.html %}

OpenSearch는 주별로 버킷을 하나씩 반환하고, 각 버킷에는 간격의 시작 시점이 담긴 key_as_string 필드가 들어 있어요. OpenSearch Dashboards가 샘플 데이터를 추가할 때 timestamp 값을 생성하기 때문에, 간격은 샘플 데이터를 추가한 날짜부터 시작돼요:

{
  "took": 17,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "flights_over_time": {
      "buckets": [
        {
          "key_as_string": "2026-08-24T00:00:00.000Z",
          "key": 1787529600000,
          "doc_count": 2202
        },
        {
          "key_as_string": "2026-08-31T00:00:00.000Z",
          "key": 1788134400000,
          "doc_count": 2177
        },
        {
          "key_as_string": "2026-09-07T00:00:00.000Z",
          "key": 1788739200000,
          "doc_count": 2142
        },
        {
          "key_as_string": "2026-09-14T00:00:00.000Z",
          "key": 1789344000000,
          "doc_count": 2187
        },
        {
          "key_as_string": "2026-09-21T00:00:00.000Z",
          "key": 1789948800000,
          "doc_count": 2188
        },
        {
          "key_as_string": "2026-09-28T00:00:00.000Z",
          "key": 1790553600000,
          "doc_count": 2163
        }
      ]
    }
  }
}

사용할 수 있는 집계에 대해 자세히 알아보려면 Aggregations를 참고하세요.

데이터 시각화하기

OpenSearch Dashboards에서 데이터를 시각적으로 탐색하려면 Create an index pattern부터 시작하는 OpenSearch Dashboards 시작하기 문서를 따르세요.

각 항공편은 출발 공항과 도착 공항의 좌표를 OriginLocation과 DestLocation 필드에 기록하기 때문에, 항공편을 지도에 표시할 수 있어요. 자세한 내용은 Maps application을 참고하세요.

다음 단계

더 알아보기 (Learn more)