Elasticsearch Parent-child 모델링에서 Index Rolling 테스트
들어가기 전에
Parent-child 모델링은 부모 문서와 자식 문서를 관계를 맺어서 저장하는 방식입니다.
Parent-child 모델링에서 Index Rolling 적용이 가능할까 ?
라는 생각을 문득 하게 되어 실험을 해보려고 합니다.
다른 비정규화 방식이면 가능할 것 같지만, Parent-child 모델링은 부모 문서와 자식 문서를 관계를 맺어서 저장하는 방식이기 때문에 Index Rolling 적용이 가능할지 궁금합니다.
그 이유는 하나의 인덱스에 문서의 수가 많아지면, 인덱스의 크기가 커지게 되고, 검색 성능이 저하될 수 있어 Index Rolling 적용이 가능한지 테스트를 해봅니다.
셋팅
- Elasticsearch 7.17.18
- master x3
- Kibana 7.17.18
시나리오
- 회원은 202403 인덱스에 저장한다. (2024년 03월에 가입 했다고 가정)
- 회원 접속 정보는 202404 인덱스에 저장한다. (2024년 04월에 접속 했다고 가정)
- 202403 인덱스와 202404 인덱스를 멀티테넌시 검색으로 조회가 되는지 확인한다.
실험
- Parent-child 모델링을 적용한 인덱스를 생성합니다. 여기서는 회원과 회원 접속 정보를 Parent-child 모델링으로 구성합니다.
PUT member-202403
{
"settings": {
"refresh_interval": "5s",
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"site_code": {
"type": "keyword"
},
"member_code": {
"type": "keyword"
},
"connected_at": {
"type": "date"
},
"join_fields": {
"type": "join",
"relations": {
"member": "connections"
}
}
}
}
}
number_of_shards
는 현재 노드 수인 3개로 설정하였습니다.number_of_replicas
는 1로 설정하였습니다.
그렇다면 샤드는 총 6개가 생성됩니다. (3개의 primary shard, 3개의 replica shard)
- 회원 정보를 색인합니다.
PUT member-202403/_doc/member_aa?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"join_fields": "member"
}
- 회원 접속 정보를 색인합니다.
PUT member-202404/_doc/member_aa-2024-04-04?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"connected_at": "2024-04-04",
"join_fields": {
"name": "connections",
"parent": "member_aa"
}
}
- 조회 테스트
GET member-2024*/_search?routing=site_a
{
"query": {
"has_child": {
"type": "connections",
"query": {
"match_all": {}
}
}
}
}
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
멀티테넌시와 routing_id
를 이용하여 인덱스를 조회하였습니다.
인덱스가 다르면 routing_id
를 지정해도 다른 샤드에 저장되기 때문에 조회가 되지 않습니다.
member
인덱스를 생성 후 테스트를 해보면 정상적으로 조회가 됩니다.
PUT member/_doc/member_aa?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"join_fields": "member"
}
PUT member/_doc/member_aa-2024-04-04?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"connected_at": "2024-04-04",
"join_fields": {
"name": "connections",
"parent": "member_aa"
}
}
GET member/_search?routing=site_a
{
"query": {
"has_child": {
"type": "connections",
"query": {
"match_all": {}
}
}
}
}
결론
Parent-child 모델링은 Index Rolling 적용이 불가능한 것 같습니다. 부모와 자식이 동일한 샤드에 있어야 한다는 제약으로 routing_id
를 지정해도, 다른 인덱스에 있다면 다른 샤드에 저장되기 때문에 조회가 되지 않습니다.
그렇다면
샤드가 1개인 경우에는 성공할까 ? 라는 생각이 들었습니다.
PUT member-202503
{
"settings": {
"refresh_interval": "5s",
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"site_code": {
"type": "keyword"
},
"member_code": {
"type": "keyword"
},
"connected_at": {
"type": "date"
},
"join_fields": {
"type": "join",
"relations": {
"member": "connections"
}
}
}
}
}
PUT member-202504
{
"settings": {
"refresh_interval": "5s",
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"site_code": {
"type": "keyword"
},
"member_code": {
"type": "keyword"
},
"connected_at": {
"type": "date"
},
"join_fields": {
"type": "join",
"relations": {
"member": "connections"
}
}
}
}
}
미래의 시점으로 인덱스를 생성하였습니다.
생성 후 보니 member-202503
인덱스는 master2
노드에, member-202504
인덱스는 master3
노드에 저장되었습니다.
그렇다면 member-202505
인덱스의 Primary Shard 를 master2
로 옮긴 다음 다시 테스트를 해보겠습니다.
Elasticsearch 의 reroute API 를 이용하여 Shard 를 이동시킬 수 있습니다.
POST /_cluster/reroute
{
"commands": [
{
"move": {
"index": "member-202504", "shard": 0,
"from_node": "master3", "to_node": "master2"
}
}
]
}
그 후 확인해보면 master2
로 이동 된 것을 확인했습니다.
이제 두개의 인덱스 모두 같은 노드의 0번째 Primary 샤드에 저장되었으니 데이터 색인 후 조회가 되는지 확인해보겠습니다.
PUT member-202503/_doc/member_aa?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"join_fields": "member"
}
PUT member-202504/_doc/member_aa-2025-04-04?routing=site_a
{
"site_code": "site_a",
"member_code": "member_aa",
"connected_at": "2025-04-04",
"join_fields": {
"name": "connections",
"parent": "member_aa"
}
}
GET member-2025*/_search?routing=site_a
{
"query": {
"has_child": {
"type": "connections",
"query": {
"match_all": {}
}
}
}
}
{
"took" : 6,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
그래도 조회가 되지 않습니다.
마지막 결론
Parent-child 모델링은 같은 인덱스와 같은 샤드에 저장되어야 조회가 가능합니다.