[ElasticSearch] Scroll API
elasticsearch에서 기본적인 search API는 한 페이지를 리턴하고나면 search context
가 소멸된다. search API에서 from
, to
값을 이용해 pagination을 구현한 것은 별개의 쿼리가 매번 수행된 것으로 RDBMS로 치면 cursor가 소멸된 것과 같다.
대량의 데이터를 조회하기 위해서는 다른 방식을 사용해야하는데, Elasticsearch에서 RDBMS의 cursor와 같은 기능을 하는게 Scroll API 이다.
사용 방법
curl을 이용해 간단히 scroll API
를 사용해보면,
먼저 기본적인 search 쿼리에 scroll argument만 추가해서 쿼리하면 된다. scroll 값이 추가되게 되면 elasticsearch는 앞으로 지정한 시간만큼은 지금 수행한 쿼리의 search context를 유지시켜준다.
issue-v0.1.3
인덱스에 저장된 모든 Issue Number 값을 조회한다고 했을 때 다음과 같이 기본적인 match_all
쿼리에 scroll=10m
파라미터만 추가해서 요청한다.
curl -XPOST \
-H 'Content-Type: application/json' \
localhost:9200/issue-v0.1.3/_search?scroll=10m -d'
{
_source:[Issue Number],
size: 100,
query: {
match_all : {}
}
}
'
그 결과 다음과 같이 원래 Search API 에서 예상됐던 조회 결과와 함께 _scroll_id
라는 값도 전달받을수가 있는데 이 id 가 앞으로 지정한 시간 (여기에서는 10m) 동안 요청한 쿼리의 search context 를 가리킨다.
{_scroll_id:DnF1ZXJ5VGhlbkZldGNoAgAAAAAAAGLvFlQ2ZldFT3NvUzhha1ZrMm5RZjlITHcAAAAAAABi8BZUNmZXRU9zb1M4YWtWazJuUWY5SEx3,took:16,timed_out:false,_shards:{total:2,successful:2,skipped:0,failed:0},hits:{total:187456,max_score:1.0,hits:[{_index:issue-v0.1.3,_type:doc,_id:131544,_score:1.0,_source:{Issue Number:131544}},{_index:issue-v0.1.3,_type:doc,_id:184522,_score:1.0,_source:{Issue Number:184522}},...,{_index:issue-v0.1.3,_type:doc,_id:8953,_score:1.0,_source:{Issue Number:8953}},{_index:issue-v0.1.3,_type:doc,_id:8955,_score:1.0,_source:{Issue Number:8955}}]}}
위 쿼리에서 "size": 100
으로 100 건 씩 fetch 하도록 설정했기 때문에 앞선 결과에서는 100건만 확인할 수 있었다. 이제부터는 첫 요청에서 전달받은 scroll_id
값만 elasticsearch에 전달해주면 아직 전달되지 않은 데이터들을 100건씩 이어서 fetch 받을 수 있다.
curl -XPOST \
-H 'Content-Type: application/json' \
localhost:9200/_search/scroll -d'
{
scroll : 10m,
scroll_id : DnF1ZXJ5VGhlbkZldGNoAgAAAAAAAGLvFlQ2ZldFT3NvUzhha1ZrMm5RZjlITHcAAAAAAABi8BZUNmZXRU9zb1M4YWtWazJuUWY5SEx3
}
'
기본적으로 search context는 지정한 시간이 지나면 소멸되는데, 전체 데이터 fetch가 생각보다 빨리 끝나는 경우가 있을 수 있으므로 다음과 같이 명시적으로 해당 context를 제거해줄 수 있다. search context가 유지되는 동안은 elasticsearch 서버에서 메모리를 점유하고 있기 때문에 명시적으로 제거해주는 것이 좋다.
curl -XDELETE \
-H 'Content-Type: application/json' \
localhost:9200/_search/scroll -d'
{
scroll_id : DnF1ZXJ5VGhlbkZldGNoAgAAAAAAAGLvFlQ2ZldFT3NvUzhha1ZrMm5RZjlITHcAAAAAAABi8BZUNmZXRU9zb1M4YWtWazJuUWY5SEx3
}
'
Python Sample
search API를 먼저 호출할 때 scroll 속성을 추가해주고, 이어서 나머지 부분을 조회할 때에는 Elasticsearch.scoll 메소드를 이용한다. 사용 방법은 앞선 curl 의 방법과 같다.
from elasticsearch import Elasticsearch
_KEEP_ALIVE_LIMIT='30s'
body = {
_source:[Issue Number],
query : {
match_all:{}
}
}
es_client = Elasticsearch([localhost:9200],timeout=300)
response = es_client.search(
index = 'issue-v0.1.3',
doc_type = 'doc',
scroll = _KEEP_ALIVE_LIMIT,
size = 100,
body = body
)
sid = response['_scroll_id']
fetched = len(response['hits']['hits'])
nums = []
for i in range(fetched):
nums.append(int(response['hits']['hits'][i]['_source']['Issue Number']))
while(fetched>0):
response = es_client.scroll(scroll_id=sid, scroll=_KEEP_ALIVE_LIMIT)
fetched = len(response['hits']['hits'])
for i in range(fetched):
nums.append(int(response['hits']['hits'][i]['_source']['Issue Number']))
print(nums)