Elastic search 모든 데이터 가져오기

2021. 11. 14. 21:05Programming/JAVA

Elastic search의 경우 각각의 shard에서 데이터들을 저장하고 있고, 검색 시 각 shard 들로부터 데이터를 모은 후 정렬해서 결과를 뿌려주는 방식으로 검색이 제공된다.

 

이렇게 모은 후 정렬해서 결과를 뿌려주기 때문에 더 큰 사이즈 혹은 더 많은 사이즈의 요청 시 해당 결과를 못 주는 경우가 있다.

 

다시 간단히 설명하자면, 내가 만약 10000개의 데이터를 Elastic search에 요청하게 되면, 각 shard에서는 10000개씩 데이터를 가져오게 되고, 10000개씩 모든 데이터(예를 들어 shard가 5개라면 50000개)를 정렬 후에 10000를 추린 후 결과를 주게된다.

 

결과적으로 from, size 등을 통해 es에서 모든 데이터를 가져오려고 시도하게 되면, 10000건 이전까지는 정상적으로 동작이 되나, from + size의 값이 10000건을 넘어서게 되면 에러가 발생된다. (해당하는 쿼리의 데이터를 가져온 후, from, size를 적용시키기 때문에 10000건 이상부터는 에러가 발생하게 된다.)

 

기본적으로 elastic search에서의 max_result_window는 10000개가 default로 되어 있으며, 이 값을 더 늘리게 되면 더 많은 값을 가져올 수는 있으나, es의 성능 혹은 메모리 문제를 야기 시킬 수 있다.

 

es에서는 모든 데이터를 가져올 수 있는 방법을 제공하고 있는데, 첫 번째는 scroll api이다.

 

2019.08.08 - [Programming/python] - [ELASTIC SEARCH] full scan 하기

 

하지만 해당 api는 search after api가 등장함에 따라 deplecate 되었다. 

간략하게 방법만을 설명하자면, scroll이라는 pos를 가져온 후, 해당 pos를 파라미터로 계속 보냄으로써 다음 size의 결과값을 계속 받아 올 수가 있다.

유의할 사항으로는 memory 유지 시간이 존재하며, 해당 시간 동안 유입이 없는 경우 pos는 사라지게 된다.

(아마도 위의 memory 방법이 es에 안좋은 역할을 제공할 수 있을것 같아서 deplecate 된것 같다.)

 

두번째 방법은 search after api이다. 현재 해당 api만을 공식적으로 es에서 제공하고 있으며 그 사용법은 아래와 같다.

 

{
	"sort": [{"_id": {"order": "asc"}}], 
 	"size": 10000, 
 	"query" : {"match_all": {}}
}

 

처음 쿼리를 날릴 때 위와 같은 조건으로 es에 쿼리를 날린다. 나같은 경우에는 id를 asc로 소팅하고, 모든 결과를 가져오도록 구성 했다. 위와 같이 쿼리를 날리게 되면 아래와 같은 결과 응답을 받을 수가 있다.

 

...
"sort" : ["C1nAGX0BslarR2j583eR"]
...

 

해당 sort 필드의 값을 받은 후 다음번 쿼리 요청 시 아래와 같이 search_after 필드에 sort필드의 값을 넣어 준다. 이렇게 되면 해당 sort 값 이후부터 값을 가지고 오게 되며, 결과적으로 이전 값에 이어서 계속 값을 가져올 수가 있다.

 

{
	"sort": [{"_id": {"order": "asc"}}], 
 	"size": 10000, 
 	"query" : {"match_all": {}},
    "search_after" : ["C1nAGX0BslarR2j583eR"]
}

 

한 가지 팁을 말하자면, 매 번 쿼리 시마다 해당 필드에 대한 sorting을 진행하기 때문에 되도록 integer를 sorting 값으로 사용하는게 성능 상 더 좋을 수 있다.