엘라스틱 서치 개발 회고(1)

Caesars·2021년 8월 3일
1

Elasticsearch

목록 보기
2/4

오랬동안 엘라스틱 서치를 활용해 진행했던 프로젝트를 끝내며 그간의 개발 과정을 돌이켜보았습니다.

프로젝트 소개

여러 세그먼트의 조건을 만족하는 유저 Count를 노출. 간단하다.
예를 들어 A(모바일로 접속), B(방문 횟수 5이상), C(주문 회수 0) 라는 조건이 있다고 하면
A + B + C 조건을 모두 만족하는 유저 Count를 노출시키면 됩니다. 물론 조건값이 달라질 수 있고 다른 조건이 추가될 수도 있습니다.
세그먼트 조건을 쿼리로 변환하여 count를 계산하도록 만들었다.

A B C 를 만족하는 3에 해당하는 유저만 구하면 된다.

왜 Elasticsearch를 사용했나

부하가 심한 쿼리를 기존 운영 DB에서 사용할 수는 없고 별도의 검색 엔진을 찾던중
방대한 양의 데이터를 신속하게 검색이 가능하다고 해서 엘라스틱서치로 결정.
이것저것 생각만 하기보다 일단 시작해보기로 했습니다.

데이터 삽입, 삭제

삽입

RestHighLevelClient에서 제공하는 bulkInsert api와 delete api를 사용하여 삽입 및 삭제 실행.

String serviceKey = initTerminate.get().getServiceKey();
String date = LocalDateTime.now().format(Constants.DATE_TIME_FORMATTER_YYYYMMDD_WITH_DOT);
String indexName = USER_DATA + serviceKey + "-" + date;

ObjectMapper mapper = new ObjectMapper();
BulkRequest request = new BulkRequest();
request.timeout(TimeValue.timeValueMinutes(2));

for (ESUserData data : items) {
	String jsonString = mapper.writeValueAsString(data);
	request.add(new IndexRequest(indexName).source(jsonString, XContentType.JSON));
}

BulkResponse response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);

for (BulkItemResponse bulkItemResponse : response) {
	if (bulkItemResponse.isFailed()) {
		logger.info(bulkItemResponse.getFailure().getMessage());
		break;
	}
}
  • Index를 생성하는 코드가 따로 없는데 인덱스 템플릿을 미리 생성해두었기 때문입니다. 위 코드의 Index Name과 템플릿의 Index patterns에 부합되기에 설정값을 그대로 사용할 수 있습니다. 다만 Index를 생성하는데는 시간이 조금 걸리니 미리 해두시는게 좋습니다.

조회

elasticsearch에서 제공하는 XcontentBuilder 를 사용하여 쿼리 생성. XcontentBuilder 클래스는 json hierarchy를 쉽게 만들어 낼 수 있도록 elasticsearch library에서 제공.
조회는 모듈에 대한 의존성이 더 낮고 API 의 body를 직접 제어할 수 있는 Low level REST Client 사용

Request request = new Request("GET", "//인덱스명" + "/_search");
request.setEntity(new NStringEntity(Strings.toString(xContentBuilder), ContentType.APPLICATION_JSON));

restClient.performRequestAsync(request, new ResponseListener() {

    @Override
    public void onSuccess(Response response) {

        try {
            String responseBody = EntityUtils.toString(response.getEntity());
            JSONArray jsonArray = JsonPath.read(responseBody, "$.aggregations.userIds.buckets");
            List<ESUserAggBucket> bucketList = new ObjectMapper().readValue(jsonArray.toJSONString(), new TypeReference<List<ESUserAggBucket>>() {});

            latch.countDown();
        } catch (Exception e) {
            latch.countDown();
        }
    }

    @Override
    public void onFailure(Exception e) {
        latch.countDown();
    }
});
  • UD를 제외한 간단한 CR과정입니다. 엘라스틱서치는 검색이 훨씬 방대하기 때문에 xContentBuilder 를 구현하는 과정은 다음 장에서 설명하겠습니다.
profile
잊기전에 저장

0개의 댓글