1. 개요
Elasticsearch는 기본적으로 'shard' 라는 개념으로 구성되어 있다. 이 'shard'라는것은 저장공간을
논리적으로 나눈 단위이다. document가 색인될때, 이 shard에 저장되는데, 이때 내부적인 routing 동작을 통해 각 shard에 분산 저장된다. 즉 유입되는 document들이 각 shard로 퍼지는 것이다.
이런경우, search 동작시에 성능상의 이슈를 불러올 수 있다. 왜냐하면 document를 검색할때에 모든 shard를 다 뒤질 것이기 때문이다. shard의 갯수가 많다면, 그리고 각 shard의 크기가 크다면, 검색은 상당한 시간이 걸릴 것이다.
2. Route
Elasticsearch에서는 이러한 검색 성능 튜닝 방법중의 하나로 'routing'이라는 기능을 제공한다. 이 방식은
routing 기준이 되는 field를 정하고, 그 기준 field의 값에 따라서 하나의 shard로 document를 색인하는 것이다.
3. 예제를 통해 살펴보자
아주 생각하기 쉬운 예를 들어 보겠다. 누구나 학창시절, 학기 초 반배정의 두근두근함을 기억할 것이다. 내가 몇반이 되었을까, 내가 원하는 친구랑 같은 반일까 하는... 기억들 말이다.
뭐 이건 잡설이고..
학생 10명이 있다고 하자, 그중 5명은 'A' 반으로, 3명은 'B' 반으로 그리고 2명은 'C' 반으로 배정을 받았다. 새학기 등교 첫날, 학생들은 각자 배정받은 반의 교실로 입실하여 수업준비를 할 것이다.
이 간단한 예시에서 학생은 'document', 반은 routing 기준이 되는 field, 교실은 'shard'에 비유할 수 있을 것이다.
직접 예제를 수행해 보자.
일단 아래와 같은 bulk 데이터를 준비하자
{"index": {"_index": "school", "_type": "students", "_id": 1}}
{"class": "A", "name": "albert"}
{"index": {"_index": "school", "_type": "students", "_id": 2}}
{"class": "A", "name": "david"}
{"index": {"_index": "school", "_type": "students", "_id": 3}}
{"class": "A", "name": "brown"}
{"index": {"_index": "school", "_type": "students", "_id": 4}}
{"class": "A", "name": "jimmy"}
{"index": {"_index": "school", "_type": "students", "_id": 5}}
{"class": "A", "name": "jennifer"}
{"index": {"_index": "school", "_type": "students", "_id": 6}}
{"class": "B", "name": "hong"}
{"index": {"_index": "school", "_type": "students", "_id": 7}}
{"class": "B", "name": "kim"}
{"index": {"_index": "school", "_type": "students", "_id": 8}}
{"class": "B", "name": "john"}
{"index": {"_index": "school", "_type": "students", "_id": 9}}
{"class": "C", "name": "tomas"}
{"index": {"_index": "school", "_type": "students", "_id": 10}}
{"class": "C", "name": "jamie"}
10명의 학생들에대한 간단한 정보다. 위에 예를 들었던 대로 5명은 A, 3명은 B, 2명은 C 클래스로 배정을 했다.
이제 위의 bulk 데이터를 인덱싱할 인덱스를 만들어야 하겠다. 아래와 같이 인덱스를 생성하자.
$ curl -XPUT 'localhost:9200/school?pretty' -d '{
"mappings": {
"students": {
"_routing": {
"required": true,
"path": "class"
},
"properties": {
"class": {
"type": "string",
"index": "not_analyzed"
},
"name": {
"type": "string"
}
}
}
}
}'
주목해야 할 것은 바로 '_routing' 설정이다. required 와 path 두가지 설정을 가지는데, 여기서 'path' 설정에 들어가는 값이 routing 기준이 되는 field 인 것이다.
그 밑에 'properties' 로 각 필드에 대한 설정을 하는데, 여기서 중요한 것은 'path' 설정에 들어간 field의 store 속성은 반드시 'true'로 해야하고 index 속성은 'not_analyzed'로 해야 한다는 것이다. 위의 예시에서 store는 기본값이 true이므로 생략하였고, index 속성은 'not_analyzed'로 설정하였다.
이제 아래의 curl을 이용하여 bulk 데이터를 색인해 보자.
curl -XPUT 'localhost:9200/_bulk?pretty' --data-binary @data.json
참고로 @파일이름 와 같은 형식으로 bulk 데이터 파일을 지정한다. data.json파일은 위의 10명의 학생 정보에 대한 bulk 데이터 파일이다.
일단 아래와 같이 school indice에 10개의 shard가 있다고 가정하자.
기준값 (class) 별로 routing이 잘 되었을까? shard를 하나씩 클릭해봄으로 확인 할 수 있다.
각각 0번, 8번, 9번 shard에 2개, 5개, 3개의 document가 색인 된 것을 볼 수 있다.
조회는 아래와같이 _search api 사용시 query string으로 routing 파라메터를 주어 조회 할 수 있다.
$ curl -XGET 'localhost:9200/school/students/_search?pretty&routing=B'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [ {
"_index" : "school",
"_type" : "students",
"_id" : "6",
"_score" : 1.0,
"_source":{"class": "B", "name": "hong"}
}, {
"_index" : "school",
"_type" : "students",
"_id" : "7",
"_score" : 1.0,
"_source":{"class": "B", "name": "kim"}
}, {
"_index" : "school",
"_type" : "students",
"_id" : "8",
"_score" : 1.0,
"_source":{"class": "B", "name": "john"}
} ]
}
}
routing파라메터 값을 'B'로 주었고, 그에따라
search api는 모든 shard를 검색하는것이 아니라 class : B 로 routing된 shard만 검색하여 결과를 보내준다.
이러한 routing을 통해서, 특정 데이터를 검색할때 성능을 향상 시킬 수 있는 것이다.