이야기박스

Elasticsearch - RestHighLevelClient를 통하여 대량의 문서를 조회하기 본문

Computer & Data/Big Data

Elasticsearch - RestHighLevelClient를 통하여 대량의 문서를 조회하기

박스님 2022. 5. 18. 18:18
반응형

Elasticsearch에서 대량의 문서를 조회하려고 하였는데, 최대 10,000건 이상의 문서는 조회되지 않는 현상이 발생하였습니다. 오늘은 Elasticsearch의 Java 라이브러리를 이용하여 10,000건 이상의 로그를 조회하는 방법을 포스팅해보려고 합니다.

 

원인

ES에서의 설정 값 'index.max_result_window'(default 10,000건) 만큼의 결과만 hits으로 노출되고 있었습니다.

 

해결 방안

1. index.max_result_window 값 증가

2. Scroll API

3. Search After

 

1번은 근본적인 해결 방안이 아니기 때문에 제외하고, 나머지 2-3번 방법을 위주로 조사해보았습니다.

마침 공식 문서 가보니, Scroll API가 아닌 Search After 사용을 권장하고 있었고 이를 사용하기로 하였습니다.

We no longer recommend using the scroll API for deep pagination. If you need to preserve the index state while paging through more than 10,000 hits, use the search_after parameter with a point in time (PIT).

 

방법

SearchAfter는 "동일한 쿼리를 여러번 반복하여 조회하는 방식" 으로 요약할 수 있을 것 같습니다.

 

ES Search에서 정렬을 하고 조회를 하게 되면, hit 값에 sortValues를 반환하게 되는데, 이 값을 이용하여 가장 마지막으로 조회한 문서의 다음 값을 다시 찾게 됩니다. 

 

이 때 중요한 점은, PIT (Point In Time) 값을 함께 설정해주어 동일한 시점에 검색을 한 것과 같은 효과를 내주어야 한다는 것입니다.

 

구현

REST API의 예시는 많은데, Java 라이브러리를 활용한 예시는 많지 않았습니다. 마침 하나의 블로그를 발견하였고, 이를 참고하여 아래 코드를 작성하였습니다.

// 메모장으로 작업한 것이라 오타가 있을 수 있음.
Object[] searchAfter = null;

while (true) {
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
        .query(queryBuilder)
        .from(pageNumber * pageSize)
        .size(pageSize)
        .sort(SortBuilders.fieldSort("@timestamp").order(SortOrder.ASC))
        .trackTotalHits(true)
        .pointInTimeBuilder(new PointInTimeBuilder("storyparks-examples"))
        .timeout(new TimeValue(searchSourceBuilderTimeout, TimeUnit.SECONDS));

    if (searchAfter != null) {
        searchSourceBuilder.searchAfter(searchAfter);
    }

    SearchRequest searchRequest = new SearchRequest(indexPattern);
    searchRequest.source(searchSourceBuilder);

    SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits[] hits = searchResponse.getHits().getHits();

    if (hits.length > 0) {
        SearchHit lastHitDocument = hits[hits.length - 1];
        searchAfter = lastHitDocument.getSortValues();
    } else {
        break;
    }
}

 

기타 잡설

'track_total_hits' 옵션을 사용하면 10,000건이 넘는 로그를 조회 할 수 있을 지 알았는데, 자세히 다시 읽어보니 아닌  듯 합니다.

If true, the exact number of hits is returned at the cost of some performance. If false, the response does not include the total number of hits matching the query.

실제 로그를 반환하는 것이 아니라, 로그의 갯수만 반환하는 것으로 보입니다.

 

Reference

 

elasticsearch 에서 많은 문서를 순차 검색 하기

엘라스틱서치는 한번에 볼 수 있는 데이터의 건수가 제한적이다. 예를 들어 GET INDEX_NAME/_search { "size" :15000 } //결과 "root_cause": [ { "type": "illegal_argument_exception", "reason": "Result windo..

bistros.tistory.com

 

 

Paginate search results | Elasticsearch Guide [7.17] | Elastic

All PIT search requests add an implicit sort tiebreaker field called _shard_doc, which can also be provided explicitly. If you cannot use a PIT, we recommend that you include a tiebreaker field in your sort. This tiebreaker field should contain a unique va

www.elastic.co

 

 

 

Elasticsearch Pagination Techniques: SearchAfter, Scroll, Pagination & PIT

Elasticsearch currently provides 3 different techniques for fetching many results: Pagination, Search-After and Scroll. To learn how to...

opster.com

 

반응형