2.X/4. Aggregations

4-09-1. significant_terms Demo

drscg 2017. 9. 23. 22:44

Because the significant_terms aggregation works by analyzing statistics, you need to have a certain threshold of data for it to become effective. That means we won’t be able to index a small amount of example data for the demo.

significant_terms aggregation은 통계의 분석에 의해 동작하기 때문에, 효율성을 위해, 데이터의 특정 임계 값이 필요하다. 즉, 데모를 하려면, 적은 양의 데이터로는 불가능하다.

Instead, we prepared a dataset that contains about 80,000 documents and saved it as a snapshot in our public demo repository. To "restore" this dataset into your cluster:

대신, 약 80,000개의 document를 포함하고 있는 데이터 집합을 준비했고, 그것은 공개된 데모 저장소에 snapshot으로 저장되어 있다. cluster에 이 데이터 집합을 "restore" 하기 위해

  1. Add the following setting to your elasticsearch.yml configuration file to whitelist the Elastic demo repository:

    Elastic demo repository가 whitelist가 되도록, 아래 설정을 elasticsearch.yml 설정 파일에 추가하자.

    repositories.url.allowed_urls: ["http://download.elastic.co/*"]
  2. Restart Elasticsearch.

    Elasticsearch를 다시 시작한다.

  3. Run the following snapshot commands. (For more information about using snapshots, see Backing Up Your Cluster.)

    다음 snapshot 명령어를 실행하자. snapshot에 대한 더 많은 정보는 Backing Up Your Cluster를 참조하자.

    PUT /_snapshot/sigterms 
    {
        "type": "url",
        "settings": {
            "url": "http://download.elastic.co/definitiveguide/sigterms_demo/"
        }
    }
    
    GET /_snapshot/sigterms/_all 
    
    POST /_snapshot/sigterms/snapshot/_restore 
    
    GET /mlmovies,mlratings/_recovery 

demo snapshot을 가리키고 있는 읽기 전용 URL 저장소를 등록한다.

(선택) 이용할 수 있는 snapshot에 대해 자세히 알기 위해, 저장소를 확인한다.

restore 프로세스를 시작한다. 이 작업은 cluster에 2개의 index(mlmoviesmlratings)를 내려받을 것이다.

(선택) recovery API를 이용하여, restore 프로세스를 확인한다.

Note

The dataset is around 50 MB and may take some time to download.

이 데이터 집합은 약 50MB정도이다. 내려 받는데 약간의 시간이 소요될 수 있다.

In this demo, we are going to look at movie ratings by users of MovieLens. At MovieLens, users make movie recommendations so other users can find new movies to watch. For this demo, we are going to recommend movies by using significant_terms based on an input movie.

이 데모에서, MovieLens 사용자들의 영화 순위를 살펴보려 한다. MovieLens에서는, 다른 사용자들이 볼 새로운 영화를 찾을 수 있도록, 사용자들이 영화를 추천할 수 있다. 이 데모에서, 입력한 영화를 바탕으로, significant_terms 를 사용하여, 영화를 추천하려 한다.

Let’s take a look at some sample data, to get a feel for what we are working with. There are two indices in this dataset, mlmovies and mlratings. Let’s look at mlmovies first:

무엇을 하려는지 알기 위해, 예제 데이터의 일부를 살펴보자. 이 데이터 집합에는 mlmoviesmlratings 라는, 2개의 index가 있다. 먼저, mlmovies 를 살펴보자.

GET mlmovies/_search 

{
   "took": 4,
   "timed_out": false,
   "_shards": {...},
   "hits": {
      "total": 10681,
      "max_score": 1,
      "hits": [
         {
            "_index": "mlmovies",
            "_type": "mlmovie",
            "_id": "2",
            "_score": 1,
            "_source": {
               "offset": 2,
               "bytes": 34,
               "title": "Jumanji (1995)"
            }
         },
         ....

예제 document를 무작위로 보기 위해, query 없이 검색을 실행하자.

Each document in mlmovies represents a single movie. The two important pieces of data are the _idof the movie and the title of the movie. You can ignore offset and bytes; they are artifacts of the process used to extract this data from the original CSV files. There are 10,681 movies in this dataset.

mlmovies 의 각 document는 하나의 영화를 나타낸다. 데이터에서 중요한 2 가지는, 영화의 _id 와 title이다. offset 과 byte 는 무시할 수 있다. 그것들은 원래의 csv 파일에서, 이 데이터를 뽑아내기 위해 사용된 프로세스의 산물이다. 이 데이터 집합에는 10,681 개의 영화가 있다.

Now let us look at mlratings:

이제, mlratings 를 살펴보자.

GET mlratings/_search

{
   "took": 3,
   "timed_out": false,
   "_shards": {...},
   "hits": {
      "total": 69796,
      "max_score": 1,
      "hits": [
         {
            "_index": "mlratings",
            "_type": "mlrating",
            "_id": "00IC-2jDQFiQkpD6vhbFYA",
            "_score": 1,
            "_source": {
               "offset": 1,
               "bytes": 108,
               "movie": [122,185,231,292,
                  316,329,355,356,362,364,370,377,420,
                  466,480,520,539,586,588,589,594,616
               ],
               "user": 1
            }
         },
         ...

Here we can see the recommendations of individual users. Each document represents a single user, denoted by the user ID field. The movie field holds a list of movies that this user watched and recommended.

여기에서, 개별 사용자의 추천을 볼 수 있다. 각 document는, user ID field에 의해 구분되는데, 단일 사용자를 나타낸다. movie field는 이 사용자가 보고 추천한 영화의 목록이다.

Recommending Based on Popularityedit

The first strategy we could take is trying to recommend movies based on popularity. Given a particular movie, we find all users who recommended that movie. Then we aggregate all their recommendations and take the top five most popular.

첫 번째 전략은, 인기를 기준으로, 영화를 추천하려 한다. 특정 영화에 대해, 해당 영화를 추천한 모든 사용자를 찾는다. 그리고, 그들의 추천 모두를 aggregation하고, 가장 인기 있는 상위 5 개를 가져온다.

We can express that easily with a terms aggregation and some filtering. Let us look at Talladega Nights, a comedy about NASCAR racing starring Will Ferrell. Ideally, our recommender should find other comedies in a similar style (and more than likely also starring Will Ferrell).

terms aggregation과 약간의 filtering으로 쉽게 표현할 수 있다. Will Ferrell 이 주연한, NASCAR(The National Association for Stock Car Auto Racing, 전미 스톡 자동차 경주 협회)에 대한 코미디, Talladega Nights 를 살펴 보자. 이상적으로는, 추천인은 비슷한 스타일의 다른 코미디를 (그리고, Will Ferrell 이 주연한 더 많은 영화를) 찾아야 한다.

First we need to find the Talladega Nights ID:

먼저, Talladega Nights 의 ID를 찾아야 한다.

GET mlmovies/_search
{
  "query": {
    "match": {
      "title": "Talladega Nights"
    }
  }
}

    ...
    "hits": [
     {
        "_index": "mlmovies",
        "_type": "mlmovie",
        "_id": "46970", 
        "_score": 3.658795,
        "_source": {
           "offset": 9575,
           "bytes": 74,
           "title": "Talladega Nights: The Ballad of Ricky Bobby (2006)"
        }
     },
    ...

Talladega Nights 의 ID는 46970 이다.

Armed with the ID, we can now filter the ratings and apply our terms aggregation to find the most popular movies from people who also like Talladega Nights:

ID를 찾았으면, 순위를 filtering하고, Talladega Nights 처럼, 사람들에게 가장 인기 있는 동영상을 찾기 위해, terms aggregation을 적용할 수 있다.

GET mlratings/_search
{
  "size" : 0, 
  "query": {
    "filtered": {
      "filter": {
        "term": {
          "movie": 46970 
        }
      }
    }
  },
  "aggs": {
    "most_popular": {
      "terms": {
        "field": "movie", 
        "size": 6
      }
    }
  }
}

이번에는 mlratings 에 query를 실행한다. 그리고 aggregation 결과에만 관심이 있기 때문에, size를 0 으로 지정한다.

Talladega Nights 에 해당하는 ID를 filter에 적용한다.

마지막으로, terms bucket을 사용해, 가장 인기 있는 영화를 찾는다.

We perform the search on the mlratings index, and apply a filter for the ID of Talladega Nights. Since aggregations operate on query scope, this will effectively filter the aggregation results to only the users who recommended Talladega Nights. Finally, we execute terms aggregation to bucket the most popular movies. We are requesting the top six results, since it is likely that Talladega Nightsitself will be returned as a hit (and we do not want to recommend the same movie).

mlratings index에 검색을 실행하고, Talladega Nights 의 ID를 filter에 적용한다. aggregation은 query 범위에서 연산하므로, 이것은 실질적으로, Talladega Nights 를 추천한 사용자로만, aggregation 결과를 filtering할 것이다. 마지막으로, 가장 인기 있는 영화 bucket으로, terms aggregation을 실행한다. Talladega Nights 자체도 hit 중의 하나로 반환될 것으로 보여, (그리고, 동일한 영화를 추천하는 것을 원하지 않기 때문에) 상위 6 개의 결과를 request하고 있다.

The results come back like so:

결과는 아래처럼 반환된다.

{
...
   "aggregations": {
      "most_popular": {
         "buckets": [
            {
               "key": 46970,
               "key_as_string": "46970",
               "doc_count": 271
            },
            {
               "key": 2571,
               "key_as_string": "2571",
               "doc_count": 197
            },
            {
               "key": 318,
               "key_as_string": "318",
               "doc_count": 196
            },
            {
               "key": 296,
               "key_as_string": "296",
               "doc_count": 183
            },
            {
               "key": 2959,
               "key_as_string": "2959",
               "doc_count": 183
            },
            {
               "key": 260,
               "key_as_string": "260",
               "doc_count": 90
            }
         ]
      }
   }
...

We need to correlate these back to their original titles, which can be done with a simple filtered query:

간단한 filtered query를 사용하여, 이 결과를 그들의 원래 제목으로 바꿀 수 있다.

GET mlmovies/_search
{
  "query": {
    "filtered": {
      "filter": {
        "ids": {
          "values": [2571,318,296,2959,260]
        }
      }
    }
  }
}

And finally, we end up with the following list:

그래서 마침내, 다음과 같은 목록을 얻을 수 있다.

  1. Matrix, The
  2. Shawshank Redemption
  3. Pulp Fiction
  4. Fight Club
  5. Star Wars Episode IV: A New Hope

OK—well that is certainly a good list! I like all of those movies. But that is the problem: most everyone likes that list. Those movies are universally well-liked, which means they are popular on everyones recommendations. The list is basically a recommendation of popular movies, not recommendations related to Talladega Nights.

자. 확실히 괜찮은 목록이다. 저 영화 모두를 좋아한다. 하지만, 모든 사람들이 저 목록을 좋아할지는, 실제로 알 수 없다. 저 영화들은 보편적으로 많은 사랑을 받는다. 즉, 저 영화들은 모든 이들이 추천할 정도로 인기가 있다. 이 목록은 Talladega Nights 와 관련된 추천이 아닌, 인기 있는 영화의 추천이다.

This is easily verified by running the aggregation again, but without the filter on Talladega Nights. This will give a top-five most popular movie list:

이것은 Talladega Nights 에 대한 filter 없이, 다시 aggregation을 실행해 보면, 쉽게 확인할 수 있다. 이것은 가장 인기 있는 상위 5 개의 영화 목록이다.

GET mlratings/_search
{
  "size" : 0,
  "aggs": {
    "most_popular": {
      "terms": {
        "field": "movie",
        "size": 5
      }
    }
  }
}

This returns a list that is very similar:

반환된 목록은 위의 결과와 아주 유사하다.

  1. Shawshank Redemption
  2. Silence of the Lambs, The
  3. Pulp Fiction
  4. Forrest Gump
  5. Star Wars Episode IV: A New Hope

Clearly, just checking the most popular movies is not sufficient to build a good, discriminating recommender.

확실히, 단지 가장 인기 있는 영화를 확인하는 것은, 좋은, 실력 있는 추천인을 만들기에는 충분하지 않다.

Recommending Based on Statisticsedit

Now that the scene is set, let us try using significant_termssignificant_terms will analyze the group of people who enjoy Talladega Nights (the foreground group) and determine what movies are most popular. It will then construct a list of popular films for everyone (the background group) and compare the two.

이제 무대가 마련되었으니, significant_terms 를 사용해 보자. significant_terms 는 Talladega Nights를 좋아하는 사람들의 그룹(foreground 그룹)을 분석하고, 가장 인기 있는 영화가 무엇인지를 결정한다. 그리고 나서, 모든 이에게 인기 있는 영화의 목록(background 그룹)을 만들고, 그 둘을 비교한다.

The statistical anomalies will be the movies that are over-represented in the foreground compared to the background. Theoretically, this should be a list of comedies, since people who enjoy Will Ferrell comedies will recommend them at a higher rate than the background population of people.

통계적 이상은, background 에 비해, foreground 에 너무 많이 나타나는 영화일 것이다. 이론적으로, Will Ferrell의 코미디를 즐기는 사람들은, background에서 좋아하는 사람들보다 더 높은 비율로, 그 영화를 추천할 것이기 때문에, 이것은 코미디 목록이 될 것이다.

Let us give it a shot:

한 번 해 보자.

GET mlratings/_search
{
  "size" : 0,
  "query": {
    "filtered": {
      "filter": {
        "term": {
          "movie": 46970
        }
      }
    }
  },
  "aggs": {
    "most_sig": {
      "significant_terms": { 
        "field": "movie",
        "size": 6
      }
    }
  }
}

설정은 거의 동일하다. terms 대신에 siginificant_terms 를 사용했을 뿐이다.

As you can see, the query is nearly the same. We filter for users who liked Talladega Nights; this forms the foreground group. By default, significant_terms will use the entire index as the background, so we do not need to do anything special.

보다시피, query는 거의 동일하다. Talladega Nights 를 좋아하는 사용자를 filtering했다. 이것은 foreground 그룹을 형성한다. 기본적으로, significant_terms 는 background 로 전체 index를 사용한다. 때문에, 특별히 더 해야 할 것은 없다.

The results come back as a list of buckets similar to terms, but with some extra metadata:

결과는 terms 와 유사한, bucket의 목록으로 반환된다. 그러나 몇 개의 추가 metadata가 있다.

...
   "aggregations": {
      "most_sig": {
         "doc_count": 271, 
         "buckets": [
            {
               "key": 46970,
               "key_as_string": "46970",
               "doc_count": 271,
               "score": 256.549815498155,
               "bg_count": 271
            },
            {
               "key": 52245, 
               "key_as_string": "52245",
               "doc_count": 59, 
               "score": 17.66462367106966,
               "bg_count": 185 
            },
            {
               "key": 8641,
               "key_as_string": "8641",
               "doc_count": 107,
               "score": 13.884387742677438,
               "bg_count": 762
            },
            {
               "key": 58156,
               "key_as_string": "58156",
               "doc_count": 17,
               "score": 9.746428133759462,
               "bg_count": 28
            },
            {
               "key": 52973,
               "key_as_string": "52973",
               "doc_count": 95,
               "score": 9.65770100311672,
               "bg_count": 857
            },
            {
               "key": 35836,
               "key_as_string": "35836",
               "doc_count": 128,
               "score": 9.199001116457955,
               "bg_count": 1610
            }
         ]
 ...

최 상위 단계의 doc_count 는 foreground 그룹의 document 수를 나타낸다.

각 bucket은 aggregation된 key(예: 영화 ID)를 나열한다.

해당 bucket의 doc_count

그리고 background 수, 전체 background 에서 이 값이 나타나는 비율을 보여준다.

You can see that the first bucket we get back is Talladega Nights. It is found in all 271 documents, which is not surprising. Let us look at the next bucket: key 52245.

첫 번째 bucket이 Talladega Nights 임을 알 수 있다. 놀랄 필요도 없이, 모두 271 개의 document가 발견되었다. 다음 bucket(key: 52245)를 보자.

This ID corresponds to Blades of Glory, a comedy about male figure skating that also stars Will Ferrell. We can see that it was recommended 59 times by the people who also liked Talladega Nights. This means that 21% of the foreground group recommended Blades of Glory (59 / 271 = 0.2177).

이 ID는 Blades of Glory 에 해당한다. 남자 피겨 스케이팅에 대한 코미디로, Will Ferrell이 주연했다.Talladega Nights 를 좋아하는 사람들이 59 회나 추천한 것을 알 수 있다. 즉, foreground 그룹의 21%(59 / 271 = 0.2177)가 Blades of Glory 를 추천했다.

In contrast, Blades of Glory was recommended only 185 times in the entire dataset, which equates to a mere 0.26% (185 / 69796 = 0.00265). Blades of Glory is therefore a statistical anomaly: it is uncommonly common in the group of people who like Talladega Nights. We just found a good recommendation!

대조적으로, Blades of Glory 는 전체 데이터 집합에서 불과 0.26%(185 / 69796 = 0.00265)에 해당하는, 185 회만 추천되었다. 따라서, Blades of Glory 는 통계적 이상이다. Talladega Nights 를 좋아하는 사람들의 그룹에서 드물게 흔한 경우이다. 단지 적당한 추천 영화를 발견했을 뿐이다.

If we look at the entire list, they are all comedies that would fit as good recommendations (many of which also star Will Ferrell):

전체 목록을 보면, 그것은 모두, 추천하기에 좋은, 딱 맞는 (Will Ferrel이 주연한)코미디이다.

  1. Blades of Glory
  2. Anchorman: The Legend of Ron Burgundy
  3. Semi-Pro
  4. Knocked Up
  5. 40-Year-Old Virgin, The

This is just one example of the power of significant_terms. Once you start usingsignificant_terms, you find many situations where you do not want the most popular—you want the most uncommonly common. This simple aggregation can uncover some surprisingly sophisticated trends in your data.

이것은 significant_terms 의 위력을 보여주는 한 가지 예제에 불과하다. significant_terms 를 사용하기 시작하면, 가장 드물게 흔한 것을 원하지만, 가장 인기가 있는 것이 아닌, 많은 상황에 직면할 것이다. 이 간단한 aggregation은 데이터에서 놀라울 정도로 복잡한 어떤 추세를 발견할 수 있다.


'2.X > 4. Aggregations' 카테고리의 다른 글

4-08-2. Calculating Percentiles  (0) 2017.09.23
4-09. Significant Terms  (0) 2017.09.23
4-10. Doc Values and Fielddata  (0) 2017.09.23
4-10-1. Doc Values  (0) 2017.09.23
4-10-2. Deep Dive on Doc Values  (0) 2017.09.23