Blog

2015.01.13 - 번역 - Intro to Aggregations

drscg 2019. 1. 6. 17:09

Many people are familiar with Elasticsearch for its search functionality. And while it is excellent at search, many organizations are using Elasticsearch for an entirely different purpose: analytics.

많은 이들이 search 기능에 대해서는 Elasticsearch에 익숙하다. search에는 탁월하지만, 많은 조직에서는 전혀 다른 목적인 analytic(분석)을 위해 Elasticsearch를 사용하고 있다.

Beneath the surface of Elasticsearch is a powerful analytics engine, waiting to be unleashed on your data. This article series will show you a developer-centric approach to using aggregations, the analytical functionality in Elasticsearch, that can help you to analyze your data, build custom dashboards, and reap the benefits of near real-time responses.

Elasticsearch 아래에는 강력한 analytic 엔진이 있어, data가 노출되기를 기다리고 있다. 이 게시물 시리즈에서는 data를 analytic하고, 사용자 정의 dashboard를 만들고, 거의 실시간에 가까은 응답의 이점을 얻는데 도움이 되는, Elasticsearch의 analytic 기능인 aggregation을 사용에 대한 개발자 중심의 접근 방식을 보여줄 것이다.

Search & Analytics: Two Sides of the Same Coin

When searching for a document, you have a goal in mind. For instance, “Find all transactions for UserXYZ.” You don’t know which documents are related to the query, but you know that a collection of documents will match the query.

document를 검색할 경우, 목표를 생각해야 한다. 예를 들어, UserXYZ의 모든 transactions 찾기.”  어떤 document가 query와 관련되어 있는지는 알지 못하지만, query와 일치하는 document 집합은 알고 있다.

Search is all about retrieving a subset of documents from the entire dataset. In contrast, analytic workloads don’t care about individual documents. A dashboard won’t show individual transactions, but rather the aggregate summary of those transactions. When building analytics, you roll up your data into useful summaries like, “What was the total revenue from the transactions by UserXYZ?" Search is concerned with retrieving documents, and analytics is busy calculating summaries about those documents.

search는 전체 data 집합에서 document의 하위 집합을 가져오는 것이다. 반면에 analytic은 개별 document는 고려하지 않는다. dashboard는 개별 transaction이 아닌 이들 transaction의 종합적인 개요를 보여준다. analytic을 할 경우, UserXYZ의 모든 transactions으로 인한 총 수익은 얼마인가?"  같은 유용한 요약을 수집(roll up)한다. search는 document를 가져오는 것과 관련이 있으며, analytic은 이들 document에 대한 개요를 계산하는데 매달린다.

Because aggregations operate over the same Lucene indices that power search, they gain the near real-time nature of Lucene data. This means that reports generated by aggregations will update as soon as the data changes, rather than waiting for the next nightly batch cron-job to finish in other systems.

aggregation은 강력한 search를 수행하는 동일한 Lucene index를 통해 동작하므로, Lucene data의 거의 실시간 특성을 가질 수 있다. 즉, aggregation에 의해 생성되는 report는, 다른 system에서 다음날 밤에 cron 작업을 통한 일괄 처리가 끝나기를 기다리지 않고, data가 변경되자마자 update된다. 

Getting Started with Aggregations

Since this is a developer-focused series, we suggest you follow along at home, so that you can play with the data and the various code examples that we show. For this article, we are going to use the New York City Traffic Incident dataset. We used this dataset a while ago to demonstrate Kibana and Logstash for non-developers.

이 게시물은 개발자 중심의 시리즈이므로, data와 다양한 code 예제를 실행할 수 있도록 편하게 따라오기 바란다. 이 게시물을 위해 뉴욕시의 교통 사고 data를 사용할 것이다. 이 data를 사용하여 얼마 전에 개발자를 위하여 Kibana와 Logstash를 시연하였다.

This series of blogs will utilize a range of aggregation features, some of which have been introduced in later versions of Elasticsearch. To follow the entire series from start to finish, we recommend using Elasticsearch version 1.4.2. But this introductory blog only deals with the basics, so any version >= 1.0 will work.

이 게시물 시리지는 range aggregation 기능을 활용할 예정이먀, 일부는 이후 버전의 Elasticsearch에서 소개되었다. 전체 시리즈를 처음부터 끝까지 따라오려면, Elasticsearch 1.4.2 를 사용하는 것이 좋다. 그러나, 이 소개 게시물은 기본적인 것만을 다루기 때문에, 1.0 이상이면 동작할 것이다.

To follow along, you'll need to restore a Snapshot into your local cluster. The snapshot is about 200MB, and it may take some time depending on your connection (NOTE: the snapshot URL only works through the API, it won't work in your browser):

따라하려며느 snapshot을 cluster에 restore해야 한다. snapshot은 약 200MB 정도이고, 연결 상태에 따라 약간의 시간이 걸릴 수 있다. (NOTE: snapshot의 URL은 API를 통해서만 동작하며, browser에서는 동작하지 않을 것이다.)

// Register the NYC Traffic Repository
PUT /_snapshot/demo_nyc_accidents
{
  "type": "url",
  "settings": {
    "url": "http://download.elasticsearch.org/demos/nycopendata/snapshot/"
  }
}
// (Optional) Inspect the repository to view available snapshots
GET /_snapshot/demo_nyc_accidents/_all
// Restore the snapshot into your cluster
POST /_snapshot/demo_nyc_accidents/demo_nyc_accidents/_restore
// Watch the download progress.
GET /nyc_visionzero/_recovery

Once your cluster has finished restoring the Snapshot, let’s perform a simple search to see what the data holds:

snapshot을 cluster에 restore했다면, data가 가지고 있는 것을 보기위해 간단한 search를 수행해 보자.

GET /nyc_visionzero/_search
{
  "_shards": {...},
  "hits": {
   "total": 332871,
   "max_score": 1,
   "hits": [
     {
      "_index": "nyc_visionzero",
      "_type": "logs",
      "_id": "97vKYDDLSZuDmj-B2RLzXg",
      "_score": 1,
      "_source": {
        "message": [
         "04/02/2014,23:15,QUEENS,11377,40.7372519,-73.9179831,\"(40.7372519, -73.9179831)\",48 STREET            ,50 AVENUE            ,,0,0,0,0,0,0,0,0,Unspecified,,,,,316762"
        ],
        "@version": "1",
        "@timestamp": "2014-04-03T06:15:00.000Z",
        "host": "localhost",
        "date": "04/02/2014",
        "time": "23:15",
        "borough": "QUEENS",
        "zip_code": "11377",
        "latitude": "40.7372519",
        "longitude": "-73.9179831",
        "location": "(40.7372519, -73.9179831)",
        "on_street_name": "48 STREET",
        "cross_street_name": "50 AVENUE",
        "off_street_name": null,
        "number_of_persons_injured": 0,
        "number_of_persons_killed": 0,
        "number_of_pedestrians_injured": 0,
        "number_of_pedestrians_killed": 0,
        "number_of_cyclist_injured": 0,
        "number_of_cyclist_killed": 0,
        "number_of_motorist_injured": 0,
        "number_of_motorist_killed": 0,
        "unique_key": "316762",
        "coords": [
         -73.9179831,
         40.7372519
        ],
        "contributing_factor_vehicle": "Unspecified"
      }
     },
     ...
Read Less

Each document represents a single traffic “incident” in NYC. These incidents contain a variety of metadata, including the time, the street name, the latitude and longitude, the borough, the statistics about injuries, and a summary of the contributing factors. There are 300,000+ documents; plenty to play with.

각 document는 NYC의 단일 교통 사고를 나타낸다. 이들 사고는 시간, 거리 이름, 위도, 경도, 자치구(borough), 부상에 대한 통계, 원인에 대한 요약 등의 다양한 metadata를 가지고 있다. 30만건 이상의 document가 있다.

Let’s start building a few simple analytics. In Elasticsearch, all analytics are built using aggregations. Aggregations are constructed similar to queries, via a JSON-based DSL. The aggregation is appended to a search request, and both the search and aggregation are executed simultaneously.

간단한 analytic을 몇 가지 해 보자. Elasticsearch에서, 모든 analytic은 aggregation을 사용하여 만들어진다. aggregation은 query와 유사하게 JSON 기반의 DSL로 구성된다. aggregation은 search request에 추가되며, search와 aggregation은 동시에 실행된다.

Here is a simple aggregation:

다음은 간단한 aggregation이다.

GET /nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "all_boroughs": {
   "terms": {
    "field": "borough"
   }
  }
 }
}

Several things to note in this example:

이 예제에서 주목할 점은 다음과 같다.

  • It is being executed against the _search endpoint. Aggregations are just another feature of search, and use the same API endpoint.
    _search로 실행된다. aggregation은 search의 또다른 기능일 뿐이다.
  • Aggregations are specified under the “aggs” parameter. You can still specify a “query” for normal search if you also want to execute a search query.
    aggregation은 “aggs” 매개변수 아래에 지정된다. search query도 실행하려면, 일반 search에 "query"를 지정할 수 있다.
  • We are executing the search with a count search_type. This omits the fetch phase in search, and is a performance trick if you don’t care about the search results (just the aggregation results)
    search_type count를 이용하여, search를 실행하고 있다. 이렇게 하면 search에서 fetch phase가 생략되며, search 결과에 신경을 쓰지 않고 aggregation 결과에만 집중하여, 성능에 도움이 된다.

So, what is this aggregation doing? It's building a list of all the boroughs in NYC, based on the boroughs included in the documents in the dataset. Here is the response:

그렇다면, 이 aggregation은 무엇을 하고 있나? data 집합에서 document에 포함된 borough를 기준으로, NYC의 모든 borough의 목록을 만들고 있다. response는 다음과 같다.

{
  "took": 11,
  "hits": {
   "total": 332871,
   "max_score": 0,
   "hits": []
  },
  "aggregations": {
   "all_boroughs": {
     "buckets": [
      {
        "key": "BROOKLYN",
        "doc_count": 86549
      },
      {
        "key": "MANHATTAN",
        "doc_count": 76122
      },
      {
        "key": "QUEENS",
        "doc_count": 73000
      },
      {
        "key": "BRONX",
        "doc_count": 36239
      },
      {
        "key": "STATEN ISLAND",
        "doc_count": 15763
      }
     ]
   }
  }
}

Notice that the aggregation results are named “all_boroughs”, which was defined in the aggregation.

aggregation 결과가 "all_boroughs"라 이름 붙여진 것에 주목하자. 이것은 aggregation에서 정의되었다.

As you can see, there are five boroughs in NYC. Under each borough is a document count: Brooklyn had 86,000 traffic incidents, while Staten Island only had 15,000. Congrats, you ran your first aggregation!

보시다시피, NYC에는 5개의 자치구가 있다. 각 borough 아래에 document 수가 있다. Brooklyn은 86,000 건의 교통사고가 있었고, Staten Island는 15,000건만 있었다. 축하한다. 여러분의 첫번째 aggregation을 실행하였다.

Bucketing Based on Criteria

The “all_boroughs” aggregation we ran was an example of a bucket aggregation. Bucketing aggregations define a criteria. If documents match that criteria, they are added to the bucket. Documents can be added to multiple buckets, or to no buckets at all. When the aggregation finishes, you are left with a collection of documents matching various criteria.

우리가 실행한 “all_boroughs” aggregation은 bucket aggregation의 한 예이다. bucket aggregation은 기준을 정의한다. document가 기준에 일치하면, bucket에 추가된다. document가 여러 bucket에 추가되거나 어떤 bucket에도 추가되지 않을 수 있다. aggregation이 끝나면, 다양한 기준에 일치하는 document의 집합이 나타난다.

In the example above, we used a Terms Bucket. It's called a Terms Bucket because this aggregation dynamically builds buckets based on the terms in your data. There were five boroughs in our data, so we got five corresponding buckets. There are also many other bucketing aggregations at your disposal. For example, you could bucket by time using a date_histogram. This will generate one bucket per month (giving you effectively a line-graph over time):

위의 예에서, terms bucket을 사용했다. 이 aggregation은 data의 terms를 기반으로 동적으로 aggregation을 만들기 때문에 terms bucket이라 불린다. data에는 5개의 borough가 있기 때문에, 대응하는 5개의 bucket을 볼 수 있다. 또한 다른 많은 bucket aggregation이 있다. 예를 들자면, date_histogram을 사용하여, 시간별 bucket을 만들 수 있다. 이를 이용하여 월별로 하나의 bucket을 생성할 수 있다. (시간에 따른 효율적인 선 그래프를 제공한다)

GET nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "months": {
   "date_histogram": {
    "field": "@timestamp",
    "interval": "month"
   }
  }
 }
}

Or you could bucket by how many cyclists were injured in each incident, using a histogram bucket:

또는, histogram bucket을 사용하여, 각 사고에서 부상당한 자전거를 타는 사람의 수를 얻을 수 있다.

GET nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "injuries": {
   "histogram": {
    "field": "number_of_cyclist_injured",
    "interval": 1
   }
  }
 }
}

You could even bucket documents based on the criteria of missing a field, using the missing bucket. This will collect all documents that don’t have a value for that particular field:

누락된 bucket을 사용하여, 누락된 field의 기준에 따라 document를 얻을 수 있다. 이렇게 하면, 특정 field의 값이 없는 모든 document를 수집할 것이다.

GET nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "missing_borough": {
   "missing": {
    "field": "borough"
   }
  }
 }
}

There are many bucketing aggregations available. Skim the reference documentation at some point to familiarize yourself with the various buckets.

활용할 수 있는 많은 bucket aggregation이 있다. 다양한 bucket을 익히도록 하자.

Metrics: More Than Just Doc Counts

You may have noticed something interesting about the bucket aggregation responses: they only list document counts. Buckets simply collect documents based on a criteria, which means the only statistic they possess is a document count.

bucket aggregation response에서 흥미로운 점을 발견했을 것이다. document 수만 나열하고 있다. bucket은 단순히 기준에 따라 document를 수집한다. 즉, 가지고 있는 유일한 통계는 document의 갯수이다.

But what if you want to calculate a value based on fields in the document, like the average price or the total revenue? These operations are performed by the second type of Aggregation in Elasticsearch called metrics.

그렇다면, 평균 가격이나 총 수익처럼, document의 field에 따라 값을 계산하려면 어떻게 해야 하나? 이러한 작업은 metric이라는 Elasticsearch의 2번째 유형의 aggregation으로 수행할 수 있다.

Metrics are simple mathematical operations, like min, max, avg, sum, percentiles etc. Metrics extract values out of the documents to use for the calculation.

metric은 최소, 최대, 평균, 합계, 백분위 같은 간단한 수학 연산이다. metric은 계산에 사용할 document에서 값을 추출한다.

Metrics can be used to calculate a simple number. For example, we can calculate the total number of cyclists injured in NYC:

metric은 간단한 숫자를 계산하는데 사용될 수 있다. 예를 들면, NYC에서 부상당한 자전거를 타는 사람의 총 수를 계산할 수 있다.

GET /nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "cyclist_injuries": {
   "sum" : {
    "field": "number_of_cyclist_injured"
   }
  }
 }
}

Which returns a result of over 7,000 injuries:

이는 부상자 수 약 7,000을 return한다.

{
  "took": 8,
  "aggregations": {
   "cyclist_injuries": {
     "value": 7129
   }
  }
}

Naming aggregations

If you look back at all the examples so far —buckets and metrics — you'll see that all aggregations must be named. This is important because it allows you to use several aggregations simultaneously. For instance, we could specify a bucket and a metric:

지금까지의 예를 모두(bucket과 metric) 보면, 모든 aggregation은 이름을 지정해야 한다는 것을 알 수 있다. 이는 동시에 여러 개의 aggregation을 사용할 수 있기 때문에 중요하다. 예를 들어, 특정 bucket과 metric을 지정할 수 있다.

GET /nyc_visionzero/_search?search_type=count
{
 "aggs" : {
  "all_boroughs": {
   "terms": {
    "field": "borough"
   }
  },
  "cyclist_injuries": {
   "sum" : {
    "field": "number_of_cyclist_injured"
   }
  }
 }
}

Because we gave each aggregation its own name, the responses that comes back from Elasticsearch will have two named sections with the respective data. Furthermore, these two separate aggregations will be executed simultaneously in a single pass over the data. By merging multiple aggregations into a single API call, you can build many reports with just one pass over your data.

각 aggregation에 각각의 이름을 지정했기 때문에. Elasticsearch에서 반환되는 response는 각 data가 포함된 2개의 명명된 section이 있다. 또한, 이들 2개의 개별 aggregation은 data를 한 번에 처리하며, 동시에 실행된다. 여러 개의 aggregation을 단일 API 호출로 병합하면, data를 한번만 처리하면서 많은 report를 만들 수 있다.

Conclusion

In this blog, we learned that aggregations serve a purpose different than search, but operate on the same near-realtime Lucene indices under the covers. We explored how to use buckets and metrics, the building blocks of the aggregation DSL. Next week we'll learn how to use sub-aggregations to create sophisticated, multi-level reports. Stay tuned!

이 게시물에서, aggregation이 search와 다른 목적을 가지고 있지만, 동일한 거의 실시간에 가까운 Lucene index에서 동작한다는 것을 알 수 있다. aggregation DSL의 구성 요소인 bucket과 metric을 사용하는 방법을 탐구했다. 다음 주에, 하위 aggregation을 사용하여 정교하고 다양한 수준의 report를 작성하는 방법을 배울 것이다.

원문 : Intro to Aggregations

참조 : 2015.01.22 - 번역 - Intro to Aggregations pt. 2: Sub-Aggregations