개발관련/MongoDB 2015. 11. 20. 13:49

자 이번엔 이전 쿼리에서 평균을 내어 보자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
db.users.aggregate([
//stage 별로 나뉘며 앞에서 처리 된걸 가지고 다음 stage로 전달
    //stage 1
    {
        $match : {
            "index" :{
                $gte: 10000
            }
        }
    },
//stage2
    {
       $group:{
           "_id" :  "$eyeColor"
           "sum" : {
               $sum : 1
           }
       }
       
    },
//stage3
    {
       $group:{
           "_id" : "$_id",
           "avg" : {
               $avg : "$sum"
           }
       }
       
    }
    
]);   
 
cs


어라.. 먼가 바뀌었다. 위에 $group의 값을 보면 "$eyeColor"가 존재한다. 이 말은 users의 field에 eyeColor 라는넘을 사용하고 싶으면 위의 예시 처럼 사용하면 된다. 마지막 $group에 또 "$sum"이라는 넘이 나온다. 이 "$sum"이 앞서 있던 stage의 key였던 sum이 $sum으로 변경된 것이다. 


결론은 collection의 field 명 -> "$필드명" 이전 statge key 값 -> 다음 stage의 "$key" 로 사용 할 수 있다. 


근데 결과가 이전에 봤던거랑 같다. 이유는 $avg의 평균을 내면 그 값이 나오므로 ... 그럼 진짜 평균을 내보자. "각 eyeColor의 전체나이와 전체 나이의 평균" 을 내어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
db.users.aggregate([
//stage 별로 나뉘며 앞에서 처리 된걸 가지고 다음 stage로 전달
    //stage 1
    {
        $group : {
            "_id" : "$eyeColor" ,
            "ageSum" : {
                $sum : "$age" 
            },
            "ageCount" : {
                $sum : 1
            }
        }
    },
//stage2
    {
        $project : {
            //"_id" : 1,
            "ageAVG" : {
                $divide : ["$ageSum" ,"$ageCount"]
            }
            
        }
    }
    
]);   
cs


또 새로운게 등장 $project 이넘은 없는 필드를 만들거나 기존 필드를 안보이고 싶을때 사용 한다고 공식사이트에 명시 되있다. 위의 예제를 보면 각 stage별로 값들을 전달한 것들을 알 수있다. 


이걸로 aggregation은 끗.... 

posted by 제스트
:
개발관련/MongoDB 2015. 11. 20. 13:39

aggregation은 '집합' 이란 뜻이다. 고로, 특정 데이터의 통계를 뽑을 때 많이 쓰인다. mapreduce는 통계의 추이를 뽑고 싶을 때 사용되며 aggregation은 양이 적고, 휘발성인 통계를 뽑을 때 사용하면 좋다. 


사용법은 공식 싸이트 https://docs.mongodb.org/manual/reference/operator/aggregation/ 이넘을 참고하자. 또는 http://hongtaey.tistory.com/57 이 분 역시 나름 정리를 잘하신듯.. 보인다. 


그럼 한번 해보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use dbname
db.users.find();

//result 
/* 1 */
{
    "_id" : "564c3240e5aa2a5f7c7bd7f5",
    "index" : 0,
    "isActive" : false,
    "age" : 30,
    "eyeColor" : "green",
    "name" : "Rodgers Grant",
    "gender" : "male",
    "company" : "VERTON",
    "email" : "rodgersgrant@verton.com"
}
........................생략........................
cs

먼저 aggregation을 할 db로 변경 후 결과를 보자. 위의 결과는 users의 collections의 결과이다. 
그럼 eyeColor가 'green' 사람을 찾아보자. 

1
2
3
4
5
6
7
8
9
//aggregation
db.users.aggregate(
//stage 별로 나뉘며 앞에서 처리 된걸 가지고 다음 stage로 전달
    [{
       $match : {
           "eyeColor" :"green"
       } 
    }]
);
cs


aggregation이라는 함수로 내부에 array를 가지며 이를 다시 object 형태를 가진다. 여기서 중요한 것은 각 object의 순서 마다 stage 라 칭하며 , pipeline 형태로 다음 state로 전달하게 된다. 


위의 결과는 다음과 같다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "result" : [ 
        {
            "_id" : "564d1acb42b552b7a4e93ff4",
            "index" : 19347,
            "isActive" : true,
            "age" : 30,
            "eyeColor" : "green",
            "name" : "Spencer Brady",
            "gender" : "male",
            "company" : "KIDSTOCK",
            "email" : "spencerbrady@kidstock.com"
        }, 
        {
            "_id" : "564c3240e5aa2a5f7c7bd7f5",
            "index" : 0,
            "isActive" : false,
            "age" : 30,
            "eyeColor" : "green",
            "name" : "Rodgers Grant",
            "gender" : "male",
            "company" : "VERTON",
            "email" : "rodgersgrant@verton.com"
        }
............................생략..............................................
cs


와 잘나온다. 그리고 쉽다!!!!! 흠.. 그럼 stage라고 하는넘을 해보자. 


이제 위의 결과를 가지고 응용하자. "눈이 녹색이고, 나이가 30보다 많은 사람"를 찾아보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
db.users.aggregate([
//stage 별로 나뉘며 앞에서 처리 된걸 가지고 다음 stage로 전달
    //stage 1
    {
       $match : {
           "eyeColor" :"green"
       } 
    },
    //stage 2
    {
        $match :{
            "age" : { $gt : 30
            }
        }
    }
]);    
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 "result" : [ 
        {
            "_id" : "564d1acb42b552b7a4e93ff4",
            "index" : 19347,
            "isActive" : true,
            "age" : 30,
            "eyeColor" : "green",
            "name" : "Spencer Brady",
            "gender" : "male",
            "company" : "KIDSTOCK",
            "email" : "spencerbrady@kidstock.com"
        }, 
        {
            "_id" : "564c3240e5aa2a5f7c7bd7f5",
            "index" : 0,
            "isActive" : false,
            "age" : 30,
            "eyeColor" : "green",
            "name" : "Rodgers Grant",
            "gender" : "male",
            "company" : "VERTON",
            "email" : "rodgersgrant@verton.com"
        }, 
..........................생략..................................
cs

잘나온다... 흠. 근데 먼가 예제로서는 부족하다... stage라는 넘을 잘 모르겠다. 

쿼리를 좀 바꿔보자. $match 말고 $group도 사용해보자. "index가 10000 이상이며, eyeColor 별 사람은 몇명인지"를 찾아보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
db.users.aggregate([
//stage 별로 나뉘며 앞에서 처리 된걸 가지고 다음 stage로 전달
    //stage 1
    {
        $match : {
            "index" :{
                $gte: 10000
            }
        }
    },
    {
      
        
       $group:{
           "_id" :  "$eyeColor"
           "sum" : {
               $sum : 1
           }
       }
       
    }
    
]);   
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 1 */
{
    "result" : [ 
        {
            "_id" : "brown",
            "sum" : 3296.0000000000000000
        }, 
        {
            "_id" : "blue",
            "sum" : 3362.0000000000000000
        }, 
        {
            "_id" : "green",
            "sum" : 3342.0000000000000000
        }
    ],
    "ok" : 1.0000000000000000,
    "$gleStats" : {
        "lastOpTime" : Timestamp(144800611421),
        "electionId" : ObjectId("564d825928cf905edab537fb")
    }
}
cs

흠 $sum이라는 함수를 써서 각 숫자의 카운트를 계산후 나온 결과다. 여기서 중요한 것은 $group은 필히 _id 라는 group의 id가 필히 존재해야 한다. 예상대로 전체 10000명 중에 값이 group별로 묶여서 나왔다. 그런데 아직도 stage를 설명 하기엔 무언가 부족하다. 

나머진 다음 페이지에서. 


posted by 제스트
:
개발관련/MongoDB 2015. 11. 20. 13:20

저번 글까지는  단순히 cluster 환경 구성을 하는 것이었다.. 이제 데이터를 넣어보자. 


먼저 필자는 다음과 같은 json 구조로 데이터를 10000건을 만들었다. 


1
2
3
4
5
6
7
8
9
10
11
{
    "_id" : "564c3240e5aa2a5f7c7bd7f5",
    "index" : 0,
    "isActive" : false,
    "age" : 30,
    "eyeColor" : "green",
    "name" : "Rodgers Grant",
    "gender" : "male",
    "company" : "VERTON",
    "email" : "rodgersgrant@verton.com"
}
cs


linux 커널에서 다음과 같은 명령으로 데이터를 넣는다. 

1
2
 ./bin/mongoimport -h 192.168.0.105:45005 -d dbname -c collectionName --file ${path}/users.json
 
cs



그런후... 샤드의 상태를 확인해보자. 

1
2
 
sh.status();
cs

아마도, 1개의 샤드에만 들어있을 것이다. 


분명히 2개의 샤드에 분리 되야 하는데.... =_=; 

그럼 chunk의 size를 확인한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
use config
db.settings.find();
 
//result
{
    "_id" : "chunksize",
    "value" : 64.0000000000000000
}
 
/* 2 */
{
    "_id" : "balancer",
    "stopped" : false
}
cs

use config  이 넘은 cluster server의 내부 db 이다. cluster만 존재하며, 설정 정보들이 들어있다. 

db.settings.fing()를 하면 위의 결과 처럼 나올 것이다. 기본 mongodb의 chunk size는 64M 인것이다. 10000건의 데이터는 3M도 안된다. =_=; 그러므로 샤딩은 당연히 안될것이다. 그럼 한번 줄여보자. 

1
db.settings.save( { _id:"chunksize", value: 1 } );
cs

다시 find로 검색해보면 1M로 바뀌어 있을 것이다. 그럼 sh.status()로 확인해보자.
여전히 샤딩은 안될 것이다. 흠.... 왜 샤딩이 안되지... 자 10000건을 다시 한번 넣어보자. 전체 data양은 20000만건... !!!! 

확인 ... sh.status();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("564aff51f77bed76dca6ba70")
}
  shards:
    {  "_id" : "elastic",  "host" : "elastic/192.168.0.105:45001,192.168.0.105:45002,192.168.0.105:45003" }
    {  "_id" : "shard0000",  "host" : "192.168.0.105:55001" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "latis",  "partitioned" : true,  "primary" : "elastic" }
        latis.users
            shard key: { "index" : 1 }
            chunks:
                shard0000    4
                elastic    5
            { "index" : { $minKey : 1 } } -->> { "index" : 1 } on : shard0000 Timestamp(50001
            { "index" : 1 } -->> { "index" : 4369 } on : shard0000 Timestamp(30000
            { "index" : 4369 } -->> { "index" : 6554 } on : elastic Timestamp(40001
            { "index" : 6554 } -->> { "index" : 8739 } on : elastic Timestamp(10004
            { "index" : 8739 } -->> { "index" : 10923 } on : elastic Timestamp(30002
            { "index" : 10923 } -->> { "index" : 14000 } on : elastic Timestamp(30003
            { "index" : 14000 } -->> { "index" : 16184 } on : shard0000 Timestamp(40002
            { "index" : 16184 } -->> { "index" : 19000 } on : shard0000 Timestamp(40003
            { "index" : 19000 } -->> { "index" : { $maxKey : 1 } } on : elastic Timestamp(50000
    {  "_id" : "users",  "partitioned" : true,  "primary" : "elastic" }
    {  "_id" : "db",  "partitioned" : false,  "primary" : "elastic" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "elastic" }
 
 
cs


오오오오... 잘된다. 다음은 aggregation 및 mapreduce로.... 

posted by 제스트
: