-
[Uber Engineering 블로그 리뷰 & 번역 - Food Discovery with Uber Eats: Building a Query Understanding Engine]Recommender System/논문 및 블로그 리뷰 2021. 5. 13. 16:30
본 포스팅은 Uber Engineering 블로그에 게재되어 있는 Uber Eats와 관련된 Article 들을 읽어보면서 주관적 해석을 약간 덧붙인 번역 포스팅이다. 원문과 내용이 크게 다르지는 않으니, 영어가 편한 분들은 원문의 글을 읽는 것을 추천한다.
https://eng.uber.com/uber-eats-query-understanding/
뭘 먹을지 선택하는 것은 Food Delivery 경험에서 가장 중요한 요소이다. 주문하는 장소를 기반으로 한다면, 그 선택의 폭은 작게는 수백여 개에서 수천여 개에 이를 수 있다. 그리고 선택의 요소는 엄청나게 다양할 것이다. 예를 들어 현재 시간이 몇 시인지, 평소에 좋아하던 메뉴는 무엇인지, 지금 날씨는 어떤 지 등의 요소가 있을 수 있다.
자연스럽게 이러한 문제는 Search & Recommendation의 문제 해결방법으로 접근하게 된다. Uber Eats의 블로그 포스팅에서는, 검색 질의부터 그 결과를 보여주는 과정, 이러한 Discovery 문제를 Knowledge Graph 기반으로 접근하여 해결했다고 한다. (본 포스팅에서 이야기하는 Knowledge Graph는 데이터간의 meta 정보를 잘 join할 수 있도록 구성했다는 의미에 더 가깝다. 즉, 레스토랑 테이블의 Id와 카테고리 테이블의 id가 잘 매핑되도록 디자인 했다는 것이다)
1. Understanding Intent
배달 앱을 킬 때, "난 오늘 마라탕 시켜야지" 라는 명확한 의도를 가지고 있는 유저도 있지만, 반대로 '뭐먹지빌런'의 성향을 띠는 유저들도 분명 있을 것이다. 이런 사람들의 의도를 잘 파악하는 것이 바로 Food Discovery의 핵심이라고 할 수 있다. 뭐먹지빌런에 해당하는 유저 역시도, 중식을 선호하는지 일식을 선호하는지 등에 대한 어느정도의 선호도는 분명 존재할 것이라는 가정이 필요하다.
그러나 이런 상황도 생각해볼 수 있다. "난 오늘 초밥을 먹어야겠어" 라는 의도로 앱을 킨 유저의 마음이 변심하여 돈가스를 시킬 수도 있는 노릇이다. 이 경우, 유저는 초밥을 검색했지만 실제로는 '초밥과 유사한 어떠한 일식 종류'를 찾고 있었을지도 모른다. 검색/추천 모델은 이러한 숨겨진 의도를 파악해야 한다.
대부분의 유저는 검색기록을 통해 자신의 의도에 숨겨진 힌트를 남겨놓는다. 이 힌트를 Query Understanding의 관점으로 사용하여, 유저의 의도를 파악하는 모델을 만드는 것이 중요하다.
2. Building a food knowledge graph
가장 일반적으로 유저의 의도를 파악할 수 있는 방법은 검색 질의어를 NLP로 처리한 뒤, 텍스트 매칭을 통해 결과를 보여주는 것이다. 하지만 이는 유저의 검색어와 의도가 명확한 경우에만 잘 동작한다. 그러나 만약 유저의 의도나 검색어가 불분명하다면? 이를테면 "매콤한 음식" 이라고 검색하는 경우를 생각해보자. 이런 경우에 적용해볼 수 있는 방법은 Knowledge Graph 와 같은 기술이다. 잘 알려진 예로는 지식그래프 기반 검색을 하는 구글을 들 수 있다.
우버잇츠에서는 food-related querie에 초점을 맞춘 knowledge base를 구축했다. Food 도메인에서는 레스토랑, 카테고리, 메뉴 등의 이질적인 여러개의 축을 가진 Entity를 다루어야 하기 때문에, 이를 Graph의 형태로 표현했다고 한다. 그래프는 여러 개의 축을 가진 복잡한 데이터를 직관적으로 표현하기 가장 적합한 형태이기 때문이다.
food 도메인에 맞는 knowledge base를 구축하는 과정을 도식화하면 위와 같다. 그림에서 정의한 바대로, 여러 소스에서 수집되는 데이터를 잘 정의된 형태의 그래프로 변환하는 작업이 수반된다. 그 중에서 Ingest는 데이터의 중복을 제거하고 그래프를 추상화하여 connection을 맺어주는 역할을 한다. 예를 들어 레스토랑 id의 중복 여부 등을 검사하는 등의 일을 한 뒤 그래프 형태로 만들어 merge한 뒤, low-latency를 보장하는 queryable한 데이터로 변환하는 것이다.
그리고 이를 활용하기 위해서는 결국 그래프를 잘 구조화하는 것이 중요해지는데, 질 좋은 데이터를 만들어내기 위해 레스토랑과 카테고리, 그리고 특정 요리와 지역의 연관성 등을 잘 고려해야 한다. 그리고 이를 통해 만약 그래프 데이터셋이 잘 구축되어 진다면, "아시안요리"라고 검색했을 때 한식/중식/일식 등이 잘 추론되어 나올 것이다.
이제 서비스 관점에서 조금 더 구체적으로 생각해보자. 만약 레스토랑의 메타정보(카테고리의 구조도)를 잘 활용하여 아래와 같은 연결관계를 가진 그래프를 구축했다고 할 때, "udon"를 검색하면 "soba", "sushi", "noodle"이 연관으로 나오게 하는 것이 주요한 목표이다.
이 목표 외에도 그래프 기반의 문제 접근 방식은 한가지의 문제를 더 해결한다. 바로 "zero result problem"으로, 등록되지 않은 레스토랑을 검색한다거나 (이를테면 아직 쿠팡이츠에는 입점되지 않은 배떡을 검색한다던지) 배달 불가능한 지역에 있는 레스토랑을 검색하는 상황에서 발생한다. 이 때, 단순히 not found 결과를 반환하는 것이 아니라 그래프의 교차 도메인 특성을 이용하여 유저의 검색 지역에서 유사한 레스토랑을 결과로 반환해주는 역할을 기대할 수 있다. 왜냐하면 그래프 정보에 단순히 메뉴와 카테고리를 집어넣는 것이 아니라, 레스토랑을 같이 넣어 지역정보를 포함시킬 수 있기 때문이다.
3. Learning from data
일반적으로 검색/추천 시스템에서는 개별 entity를 latent vector의 형태로 임베딩한다. GloVe, Word2Vec, MF의 latent vector가 대표적인 예이다. 이렇게 표현하는 것은 entity 사이의 의미론적 유사도를 벡터 사이의 거리로 표현하는 것이 가능하기 때문이다. Uber Eats 에서는 이와 유사하게 query2vec 모델을 디자인하였고 그 구조는 아래와 같다.
만약 하나의 레스토랑에서 주문하기 위해 2개의 검색이 필요했다면, 그 자체를 하나의 word(GloVe, Word2Vec 에서의 word 개념)로 인식시키는 context의 개념을 나타낸다. 그리고 이를 이용해 PMI(pointwise mutual information) Matrix를 구성할 수 있다. 좌우당간에 한 레스토랑을 주문하기 위한 검색어의 co-occurrence 정보로 entity 임베딩을 했다는 소리이다.
4. Query expansion
그렇다면 앞선 장에서 말했던 "zero result problem"을 해결하기 위해서는 어떤 전략을 취하고 있을까? 이번 장에서는 검색 질의와 일치하는 것이 없을 때 QE(Query Expansion)를 통해 검색 경험을 향상시키는 것에 대해 설명하고 있다.
QE는 보통 검색엔진 분야에서 recall을 향상시키고 커버리지를 높이기 위해 가장 일반적으로 사용하는 방식이다. 그 중에서도 특히 다음의 두 상황에 적합하다. 첫 번째는 유저의 검색이 굉장히 애매한 경우. 그리고 두 번째는 검색에 대한 퀄리티 있는 결과가 부족한 경우이다. 만약 "탄탄면"을 검색한 유저가 있다고 할 때, 그 유저는 매콤한 중국음식을 만드는 레스토랑을 찾고 있거나 혹은 다른 사천요리를 파는 레스토랑을(심지어 탄탄면이 메뉴에 없을지라도) 찾고 있을 공산이 크다.
QE는 원래 질의로부터 해당 질의와 유사한 질의들을 찾는 작업들이 포함된다. 그래서 만약 검색어 A가 들어왔으면 3장에서 임베딩한 데이터를 기반으로 유사한 질의들(검색어 B, 검색어 C)을 과정에 포함시키게 된다. 문제는 검색어가 매우 많다는 것인데, 때문에 vector similarity search에 과부하가 발생할 확률이 높다. 이런 경우 Nearest Neighbor Search 혹은 또 다른 몇 가지의 fast/approximate 방법을 사용하는 것이 일반적이다.
위의 그림은 QE를 통해 "zero result problem"을 해결하는 과정을 나타낸 것이다. 만약 어떤 유저가 "탄탄면"을 검색했을 때 그 결과가 하나도 없다면, not found를 반환하는 대신 탄탄면과 유사한 검색어(이를테면 "중국음식", "사천음식" 등)로 확장하여, 확장된 각 검색어로 다시 한 번 검색 질의를 시도한다. 그리고 모집된 결과들을 결합하여 랭킹 모델(이 있다면)에 맞게끔 정렬한 뒤 결과를 최종적으로 반환하게 된다.
5. Achieving the best of both worlds
이제 고려해야 하는 것이 바로 Learning-to-rank 모델링이다. representation learning을 통해 entity간의 존재적 유사성(?)을 얻어내는 것이 가능해졌고 이를 통해 not found 문제를 해결할 수 있는 QE까지 확장이 가능해졌지만, 여전히 discovery에는 많은 변수들이 존재한다. 이를테면 임베딩 벡터간의 유사도는 높지만 실제 유저가 받아들이기는 전혀 생뚱맞은 결과들이 있을 수 있다(본문에서는 Halal을 예로 들었는데, 저게 무슨 사회문화적 의미를 가진 메뉴인지 잘 모르겠어서 제대로 이해는 못했다).
그리고 또 하나의 문제는 cold-start 문제이다. 검색/추천 시스템은 기본적으로 co-occurence로 탐색을 보완하는 형태로 디자인 되었기 때문에 필연적으로 cold-start 문제를 겪게 된다. 그래서 이 두 가지 문제를 해결할 수 있는 다양한 learning-to-rank 모델을 고안해야 한다. 어떻게 하자는 건지 본문에서는 언급하지 않았지만, content-based한 피쳐를 만들어서 학습하는 learning-to-rank 모델이 될 수도 있겠고, 예외 상황을 표현하는 피쳐를 집어넣은 learning-to-rank 모델이 될 수도 있겠다(exceptional case를 학습시키는 wide and deep 같은 구조의 모델).
'Recommender System > 논문 및 블로그 리뷰' 카테고리의 다른 글
댓글