모바일 환경의 진화는 IT서비스 전반에 비약적인 발전을 가져왔다. 특히 ‘검색’이라는 단순한 기능을 다양하게 활용할 수 있도록 큰 밑거름이 됐다. 우리가 기억하는 초기 검색 서비스는 사전과 전화번호 찾기 등 인덱스 기반으로 저장된 내용을 찾아주는 것이 대부분이었다. 이후 적용 범위를 쇼핑, 사진, 문서, 음악, 위치 심지어 동영상까지 넓혀갔다. 이제는 단순히 특정 기능이나 서비스를 위함이 아닌 시스템 전체를 위한 기반 기술로서 자리를 잡아가고 있다. 최근 이러한 검색 니즈의 변화에 맞춰 다양한 형태의 프로그램이나 프레임워크들이 개발되고 있다. 대표적으로 솔라(Solr)와 엘라스틱서치(Elasticsearch, 이하 ES)가 있다. 이들은 개발자들에게 검색엔진을 구축하기 위한 서비스, 검색의 본질적인 목표, 이를 활용한 서비스 구축을 위한 다양한 컴포넌트를 제공해준다. 루씬(Lucene)을 기반으로 구성된 오픈소스이지만 장단점이 명확하게 존재하는지라 무엇이 더 좋다고 언급하지는 않겠다. 모바일 홈쇼핑 포털 앱 ‘홈쇼핑모아’는 서비스 초기부터 ES를 이용해 쇼핑 검색을 제공하고 있다. 엔진의 변화 또는 서비스의 변화에 발맞춰 시너지를 내고 있다. 성능과 품질이라는 경계선에서 필요한 최적화 포인트와 사소하지만 큰 영향을 줬던 에피소드들을 공유하고자 한다.  

홈쇼핑모아를 위한 Elasticsearch

홈쇼핑모아는 현재 1억 건에 육박하는 상품 데이터를 기반으로 쇼핑 상품과 방송 상품 검색 기능을 사용자에게 제공하고 있다.(각각 제공중이다.) 또한 ELK기반의 내부 로그 검색도 겸비하고 있다. 먼저 사용자에게 제공하는 상품 검색 기능에 관한 얘기를 해볼까 한다. 홈쇼핑모아는 현재 ES 2.x 버전 기반으로 서비스를 제공하고 있다. 간단히 ES 구축 내용을 엿보자면 상품 검색은 클러스터(Cluster) 1개로 운용하고 있다. 내부적으로는 데이터 5개, 검색 2개해서 총 7개 노드로 구성돼있고, 각 노드는 n개의 프라이머리(Primary), 레플리카(Replica) 샤드를 공존하도록 했다. 또한, 언급된 노드들은 AWS의 EC2 인스턴스를 하나씩 할당해 사용한다. 01.jpg <그림1>홈쇼핑모아의 엘라스틱서치 구축내용 ES는 내부적으로 색인(Index)과 문서 타입(Document Type)을 제공한다. 관계형 데이터베이스(RDB)의 데이터베이스(Database)와 테이블(Table) 정도로 생각하면 이해하기 쉬울 것이다. 이를 활용해 홈쇼핑모아는 각 쇼핑사를 문서 타입으로 분류하고 쇼핑 상품과 방송 상품을 색인으로 구분하고 있다.

쇼핑 상품 방송 상품

홈쇼핑 (T커머스 포함) 총 9건 GS홈쇼핑, CJ오쇼핑, 롯데홈쇼핑, 현대홈쇼핑, NS홈쇼핑, 홈앤쇼핑, 신세계TV쇼핑, 공영홈쇼핑, K쇼핑 총 14건 GS홈쇼핑, GS마이샵, CJ오쇼핑, CJ오쇼핑플러스, 롯데홈쇼핑, 현대홈쇼핑, 현대홈쇼핑플러스샵, NS홈쇼핑, 홈앤쇼핑, 신세계TV쇼핑, 공영홈쇼핑, K쇼핑, W쇼핑, 쇼핑엔티

전문쇼핑몰 총 3건 롯데닷컴, 신세계몰, 하이마트

오픈마켓 총 3건 11번가, 옥션, G마켓

<표1>홈쇼핑모아의 검색 범위 상품 검색은 현재 쇼핑 상품 15개, 방송 상품 14개에서 약 1억건의 상품 데이터를 기반으로 서비스를 제공하고 있다. 홈쇼핑모아와 정식제휴 관계인 해당 쇼핑사들은 매일 업데이트된 EP(Electronic Paper: 이하 EP)를 제공해준다. 이를 통해 상품 업데이트 프로세스는 ES에 색인/삭제/갱신을 통해 최신의 쇼핑 데이터를 유지 시켜준다. ES를 단순히 스토리지로 사용하는 것이 아닌, 검색 트랜잭션을 발생시키는 플랫폼으로 활용해야 하는 전제로 많은 챌린지가 따라온다. 
ES는 기본적으로 높은 빈도의 데이터 변화에 만족할만한 성능을 제시해주지 못한다. 그래서 적절한 데이터 업데이트 모델과 그에 알맞은 인덱싱 관련 기능(Function)들을 잘 활용해야 한다. 홈쇼핑모아는 사용자 트래픽이 급격히 줄어드는 새벽 시간을 이용해 ‘bulk_api’로 상품 데이터를 관리 한다. 단순히 ‘bulk_api’를 사용하는 것만으로 짧은 시간안에 데이터 1억건 모두 업데이트하지 못한다. 업데이트가 유효한 필드와 유효한 상품을 먼저 분류하는 작업을 선행하는 것이 중요하다. 굳이 변화가 필요 없는 필드나 상품에 대해 불필요한 트랜잭션을 만들어내지 않도록 했다. ![02.jpg](https://boilerbuzzni.files.wordpress.com/2017/04/02.jpg) <그림2>홈쇼핑모아의 EP업데이트 구조 랭킹, 동의어 등 내부에서 행해지는 주요 컴포넌트들은 ES에 전달되는 질의(Query)를 어떻게 구성하느냐에 따라 결과가 크게 달라진다. 적절한 필터 사용과 검색어에 대한 해당 상품의 스코어를 결정해주는 스크립트 사용이 대표적인 예다.특정 쇼핑사의 상품만을 원하거나 특정 카테고리의 상품들이 대상인 경우(명확히 검색 범주를 제한해줘야 하는 경우), 해당 필드를 사용한 필터를 통해 검색 범위 제한을 주고 있다. \----------검색 범주를 제한하는 경우 filter_query = [ {‘tem’: {‘cate1’:’디지털’}}, ] query_DSL[‘filter’][‘bool’][‘must’].append(filter_query) * * * 반대로 느슨한 필터를 적용하고자 할 때는 부스트(boost)나 스크립트로 자체 가중치(weight) 값을 설정함으로써 필터를 랭킹으로 투영시킬 수 있다. 특정 상품의 구매 전환율이 높거나 낮을 때, 검색어에 투영된 카테고리 정보로 랭킹 제한을 두고자 할 때 사용하고 있다. \-----------스크립트로 가중치 값을 설정하는 경우 if(conversion_score != 0{ weight_multi = conversion_score if(weight_multi > max_weight) { weight_multi = max_weight; } return_score = return_score * weight_multi; } \-----------부스트로 가중치 값을 설정하는 경우 “query”: { “match”: { “name”: {‘query’: brand_query, ‘boost’: brand_weight} } } * * *   # 성능과 품질의 줄다리기 홈쇼핑모아는 전용 랭킹 시스템을 구축해 사용하고 있다. 홈쇼핑모아 랭킹 시스템을 자세히 설명할 수는 없지만, 기본적인 ES의 궁합과 최적화 이슈를 살펴보자. 홈쇼핑모아 랭킹 시스템은 상품 데이터의 다양한 수치 필드들을 가지고 실시간으로 해당 상품의 스코어를 계산해 정렬해준다. 이렇게 홈쇼핑모아의 랭킹이 만들어진다. \------------------- 홈쇼핑모아의 랭킹 시스템 rank: 1, ncate3_id: 305, goods_type: “ep”, group_id: 0, goods_id: “24301357”, brand: “LG”, clickct: 672, _score: 18132.078, name_simple: “[17년출시] LG디오스 매직스페이스 5도어 냉장고 866L[F878S31 퓨어]”, ncate2_id: 1783, is_ad: 1, qclkct: 2028, price: 2160000, ncate4: “”, ncate3: “냉장고”, ncate2: “주방가전”, ncate1: “디지털/가전”, * * * 하지만 아무리 좋은 랭킹 알고리즘이라 할지라도 서비스에 적용되어 사용자에게 짧은 시간 안에 결과를 보여주지 못하면, 실시간이라는 큰 특성이 있는 검색으로 가치를 인정받기는 힘들다.