[ELASTIC SEARCH] full scan 하기

2019. 8. 8. 15:33Programming/python

elastic의 index table을 full scan 하려고 아래와 같이 코드를 작성해서 호출했다.

 

ES_URL ="http://127.0.0.1/index-table/type/_search"
headers = {'Content-Type': 'application/json; charset=utf-8'}
data = {"from": 0, "size": 100 }
res = requests.post(ES_URL, data=json.dumps(data), headers=headers).content
total = res['total']
index = 0
size = 100
for i in range(0, total, size):
data['from'] = index
res = json.loads(requests.post(ES_URL, data=json.dumps(data), headers=headers).content)
index = index + size
view raw get_es.py hosted with ❤ by GitHub

 

처음에 total size를 가져온 후 from의 window size를 옮겨가며 전체 데이터를 가져오는 방식이다.

그런데 위와 같이 작업 할 경우 아래와 같은 에러메시지가 나타나게 된다.

 

Limit of total fields 10000 in index has been exceeded.

 

해당 index에서의 최대 결과 윈도우는 기본으로 10000으로 설정되어 있으며( index.max_result_window) 해당 값을 넘어갈 시에 위와 같은 메시지가 발생한다.

 

내가 아무리 from을 13000, size를 100으로 줬다고 하더라도 es 내부에서는 전체 13100개를 가져온 후 0~13000개는 버리는 로직을 취하게 되고 결국에는 13100개를 가져오는 것과 동일한 작업을 하게 되는 것이다.

 

위의 코드로 실행하면 결국에는 10000개 이상의 결과는 가져올 수가 없게 된다. 또한 index.max_result_window 설정 값을 늘린다고 하더라도 성능 문제를 피할 수가 없다.

(만약 index.max_result_window를 50000을 주게 되면, 각각의 shard에서 50000개씩을 가져와서 sorting을 진행한 후 최종 50000개만을 가져오게 된다. 즉 각 shard에서 불필요한 50000개를 추가로 가져오게 되면 성능 문제를 야기시킬 수가 있다.)

 

 

 

해결 방법으로는 scroll이라는 기능을 통해 elastic search full scan을 진행 할 수가 있다.

 

ES_URL="http://127.0.0.1/index-table/type/_search/?scroll=1m"
SCROLL_URL="http://127.0.0.1/_search/scroll"
headers = {'Content-Type': 'application/json; charset=utf-8'}
data = {"size": 100}
res = json.loads(requests.get(ES_URL, data=json.dumps(data), headers=headers).content)
scroll_data = {"scroll":"1m", "scroll_id" : res['_scroll_id']}
while(len(res) > 0):
res = json.loads(requests.get(SCROLL_URL, data=json.dumps(scroll_data), headers=headers).content)
view raw scroll_es.py hosted with ❤ by GitHub

_search 뒤에 scroll=1m이라고 주면 해당 scroll id를 1분 동안 유지하겠다는 의미가 된다. 

그럼 우리는 이제 이 scroll id가 유지되는 동안 계속해서 data를 100개 단위로 가져올 수가 있다.

while 루프를 돌면서, 데이터가 존재하지 않을 때까지 해당 scroll id의 값을 계속적으로 호출하면 full scan 기능을 구현할 수가 있다.