안녕하세요. 번개장터 주식회사에서 엔지니어로 일하는 이명휘입니다. 저번 포스팅에 이어서 두번째 포스팅을 게시하게 되었습니다. 이번 포스팅에서는 번개장터의 새로운 추천시스템에 대한 상세한 개발 흐름을 공유하고자 합니다. 단순 기술에 대한 자랑이 아닌 모두와 사례를 공유하는 것을 목표로하기 때문에 어려운 수식의 첨가 보다는 가독성을 높이기 위한 글을 구성하였습니다.

1. 개발을 위한 환경

  • 어느정도 큰 규모의 프로젝트를 시작하기에 앞서, 쾌적한 개발환경을 만드는 것은 매우 중요한 일이라 생각합니다. 다양한 사례에 기반한 리서칭을 통해서 알맞는 개발언어와 통합개발환경을 구축해야 추후 맞이하는 부작용을 최소화 할 수 있기 때문입니다.
  • 번개장터는 Python을 적극적으로 활용하는 기업입니다. 번개장터를 구성하는 중요 구성요소 중 하나인 Web App Framework(Django, Flask)부터, 최근 활발하게 도입하고 있는 AWS의 Labmda 함수까지 모두 Python을 기반으로 구성되어 있습니다. 이미 해당언어에 대해서는 개발자 모두가 어느정도의 지식을 가지고 있었기에 우선적으로 PySpark를 고려하였습니다.
  • 하지만 Scala와 Python으로 구성된 Spark의 속도비교 사례 및 PySpark 레퍼런스에 대한 부실함은 Scala로 이동하게 되는 계기가 되었습니다[1]. 또한, 개발을 진행하면서 수많은 수행착오를 겪을 것이 사전에 예상 되었기에, 노트북에 대한 지원 및 성능도 중요한 척도가 되었습니다. 이미 Scala에 기반한 Spark는 Zeppelin이라는 걸출한 노트북과 완벽하게 연계되고 있었기에 더욱 매력적으로 다가왔습니다[2]. 이러한 이유로 우리 번개장터는 Scala를 활용하게 되었으며, 다소 러닝커브가 있는 언어이기에 더욱 신중하게 개발에 임했습니다.

Spark와 최적의 궁합을 자랑하는 Apache Zeppelin

2. 클러스터 구성

  • 클러스터구성은 앞서 말씀드린바와 같이 AWS의 EMR(Elastic MapReduce)를 활용하였습니다. 그 이유는 다음과 같습니다.
  • 번개장터가 AWS를 활발히 사용하는 가장 큰 이유중 하나는 관리형 서비스를 지향하기 때문입니다. 이미 많은 스타트업과 중소규모의 IT기업들은 이러한 이유로 클라우드 서비스를 활용하고 있습니다. 그 중 EMR은 HDFS(Hadoop File System)에 기반한 클러스터를 매우 손쉽게 활용 할 수 있습니다.
  • 두번째 이유는 위와 비슷한 맥락입니다. 분산형으로 구성된 노드들을 손쉽게 스케일링(Resizing)이 가능합니다. 단 몇번의 클릭으로 AWS 인스턴스의 수를 변화시킬 수 있습니다. 또한, 마스터를 제외한 노드들은 Spot 인스턴스를 지원하고 있기에 더욱 합리적인 활용을 가능케 합니다. 더욱이 클러스터의 효율적인 관리를 위한 리소스매니저(Yarn) 및 모니터링도구(Gangila) 등 여러 관리 패키지들을 손쉽게 설치 & 활용할 수 있는 장점이 있습니다.
  • 이번 추천시스템에 대한 클러스터의 주요 구성은 Spark - Mllib - Yarn - Zookeeper로 되어있습니다. 아래 그림과 같이 ETL(Extract-Transform-Load)이라고 불리는 형태를 따랐으며, 데이터베이스는 RedShift가 아닌 ElasticSearch를 활용했습니다.일반적인 형태의 ETL 프로세스를 활용(출처: Amazon)

3. 명시적 VS 암묵적

  • 우선, 개발상세에 대해 설명하기에 앞서 협업필터링(Collaborative Filtering)을 개발하기 전에 고려해야 할 이론에 대해서 설명하고 지나가야 할 것 같습니다. 성능이 좋은 추천시스템을 구현하기 위해서는 명시적 점수(Explicit Rating) 및 암묵적 피드백(Implicit Feedback)에 대한 선택을 해야합니다[3].
  • 명시적점수에 대해서 먼저 간단히 설명드리면, 후기 평점과 같이 이미 만들어진 점수 범위 안에서 사용자가 직접적으로 점수척도에 관여하는 것입니다. 명시적점수는 객관적으로 척도를 판단하기 어려운 변수를 가지고 있습니다. 예를들어, 유저가 만족하다고 생각하는 물품에 대해서는 높은 점수를 매기지만 마음에 들지 않으면 아예 점수를 매기지 않을 수도 있습니다 (데이터의 빈약도). 또한, 사용자마다 점수에 대한 각자의 기준이 있기 때문에 이에 대한 문제가 대두되기도 합니다 (bias).
  • 반대로, 암묵적 피드백은 구매여부 / 조회여부처럼 명시적으로 표현할 수 없는 데이터들을 말합니다. 예를들어 설명드리면, 로그데이터에 기반한 물품 클릭수가 될 수 있습니다. 데이터수집이 쉬울뿐만 아니라, 추천시스템의 스코어링을 위해 어렵지 않게 관여(가중치 부여)할 수 있다는 장점이 있습니다. 명시적점수의 편향문제가 있기 때문에 대부분의 추천시스템에서는 암묵적 피드백을 활용하는 추세이기도 합니다.
  • 이에따라 암묵적 피드백을 활용하기로 하였으며, 로그데이터 기반으로 이를 구성하였습니다. 번개장터의 대부분의 로그는 S3에 json형태로 저장되어 있습니다. 이 중 물품에 대한 클릭데이터를 주 목표로 이용하였습니다.

4. Item-to-Item 추천

  • 새로운 추천시스템은 물품 상세페이지에 대한 연관상품을 추천하는데 그 목적이 있습니다. 일반적인 협업필터링 방식은 자신과 비슷한 성향을 가진 유저가 본 상품을 추천하기 때문에 item-to-item 추천방식과는 거리가 있습니다.
  • Spark에서 지원하는 ALS를 활용하면서 item-to-item방식을 구현해야 했었기 때문에, 코사인 유사도(Cosine Similarity)를 바탕으로 물품간 잠재요인(Latent Factor)을 비교하기로 하였습니다[5-6]. 코사인 유사도는 벡터간의 유사도를 측정하는 고전적이면서도 효과적인 방법입니다. 이외에도 두 객체간의 피어슨 상관관계(Peason Corrleation) 및 유클리드 거리법(Euclidean Distance) 등이 있지만, 가장 효과적이며 쉬운 방법이기 때문에 코사인 유사도를 이용하였습니다.
  • 대략적인 코드의 흐름은 다음과 같습니다.
    1. S3에 저장된 로그데이터를 추출
    2. 데이터 전처리를 통한 정제
    3. Spark ALS활용 & 학습(Rating 객체 변환등)
    4. 코사인 유사도를 이용한 잠재요인 비교
    5. 데이터베이스에 삽입
    6. 1~5까지 배치작업
    7. 추천성능 측정(AUC)
  • 크게 5가지의 흐름으로 코드가 구성되어 있으며, 데이터 정제 및 데이터베이스 I/O에서 성능 이슈가 발목을 잡는 경우가 많았기 때문에 이를 해결하기 위해서 많은 MapReduce 튜닝을 거쳤습니다. 또한, Spark 기계학습 라이브러리는 매우 섬세하지만, 대용량의 데이터를 처리하는데 있어서 드라이버 메모리에 대한 성능 이슈가 빈번하게 발생하였기에 이를 최적화 하기 위한 노력도 있었습니다.

5. 결과

  • 추천은 매우 만족스러운 결과를 나타냈습니다. 하이퍼파라미터 튜닝 후, 대략적인 AUC(Area Under Curve)는 0.88정도였으며, 휴리스틱한 안목으로 보았을 때도 괜찮을 결과를 얻었습니다.
  • 하지만, 배포를 진행하였을 때에는 가끔 카테고리 성격에 맞지않는 추천상품이 나왔기 때문에, 이를 정제하는 작업이 추가적으로 진행되었습니다. 이를 위해서 추천물품에 대한 카테고리 경계조건을 부여함으로써 더욱 높은 신뢰도의 추천결과를 기대하게 되었습니다.
  • 현재 번개장터는 A/B테스트에 대한 방대한 시스템이 구축되어 있지 않기 때문에, 성과분석을 위해서 클릭수에 기반한 로그데이터를 분석하는 방법을 활용했습니다. 통계는 전체 물품 중 20%정도의 표본을 추출하여 테스트를 진행했으며, 노출당 클릭수(CTR)를 기준으로 성과를 측정하였습니다. 결과는 아래와 같습니다.

신규 추천시스템의 CTR과 기존 시스템의 CTR을 비교

  • 한달동안 A/B 테스트를 진행한 결과 기존 시스템에 비해 신규 추천시스템이 대략 15%정도의 증가율을 보였습니다. 우리 번개장터가 추천시스템 개발초기에 의도했던 CTR 수치향상 목적을 어느정도 달성했다고 생각합니다.

기존 시스템의 CTR 대비 신규 추천시스템의 CTR 증감율

6. 추천시스템 최적화

  • 다음 포스팅에서는 추천시스템을 개발하면서 발목을 잡았던 부분 및 하이퍼파라미터 튜닝에 대한 부분을 공유하며, 이를 해결하기 위한 방법을 나눠보고자 합니다.

7. 인용

  • [1] Scala vs. Python for Apache Spark (2016). https://www.dezyre.com/article/scala-vs-python-for-apache-spark/213.
  • [2] Wilson, B., Palamuttam, R., Whitehall, K., Mattmann, C., Goodman, A., Boustani, M., … & Ramirez, P. (2016, December). SciSpark: highly interactive in-memory science data analytics. In Big Data (Big Data), 2016 IEEE International Conference on (pp. 2964-2973). IEEE.
  • [3] 추천 시스템을 위한 데이터 준비 (PR시리즈.2) (2013). https://bahnsville.tistory.com/895.
  • [4] 코사인유사도 https://ko.wikipedia.org/wiki/코사인유사도.
  • [5] Pilászy, I., Zibriczky, D., & Tikk, D. (2010, September). Fast als-based matrix factorization for explicit and implicit feedback datasets. In Proceedings of the fourth ACM conference on Recommender systems (pp. 71-78). ACM.




글쓴이 - 이명휘 : 번개장터 주식회사 엔지니어(컴퓨터공학 학사 / 건축공학 석사)
머신러닝에 기반한 최적화 및 신재생에너지에 대한 연구를 했습니다.
흥미로운 논문에 대한 리뷰를 취미로 합니다.
Web : developeco.com
ResearchGate : bit.ly/2HF9M9x
Github : /Myeonghwi