-
Notifications
You must be signed in to change notification settings - Fork 3
Enhancing the Matching Algorithm
- GaleShapely Algorithm은 N명의 남성 & N명의 여성의 선호도를 기반으로 N개의 쌍으로 엮어주는 매칭 알고리즘 입니다.
- 이를 "MoodMate" 서비스 취지에 맞게 N명의 남성 & M명의 여성의 3가지 선호도(무드, 나이 선호도, 같은 학과 선호 여부)를 기반으로 N(N<M) or M(N>M)개의 쌍으로 엮어주는 방식으로 커스텀했습니다.
시즌 1에서는 시스템이 user_id를 테이블에 저장된 순서대로 가져오기 때문에 전에 매칭된 사람이 다시 매칭되는 문제를 해결하기 위해, 두 가지 주요 개선 작업을 진행했습니다.
- 먼저 user_id를 가져온 후에 Collection 클래스의 shuffle 메서드를 활용하여 리스트를 재구성함으로써 user_id를 무작위로 섞는 방식을 도입했습니다. 이로써 매칭 시스템의 무작위성을 대폭 향상할 수 있었습니다.
- 두 번째로 이미 매칭된 커플을 관리하는 who_meet이라는 새로운 테이블을 만들어, 매칭 기록을 DB에 남기기 시작했습니다. 매칭 과정에서 who_meet 테이블을 탐색하여, 전에 매칭되었던 기록이 있는 경우 해당 커플을 선호도 리스트의 뒷순위에 배치하는 방식을 채택했습니다. 이 과정에서 매칭되었던 사람들 사이의 선호도 관리가 무의미했기에 선호도 리스트를 HashSet으로 관리하였습니다. 이를 통해 전에 매칭된 사람과 만날 확률을 0에 가깝게 만들 수 있었습니다.
시즌 2에서는 매칭 과정에서 모든 사용자가 참여할수 있도록 보장하고 버그를 수정하기 위한 다양한 기술적 개선 작업을 진행하였습니다.
출시 3일 후 사용자로부터 “3일째 매칭이 되지 않는다”는 중요한 피드백을 받았습니다. 특정 성별의 수가 압도적으로 많으면 매칭이 되지 않을 수 있다는 점은 이미 테스트를 통해 확인했던 바지만, 해당 그룹은 남녀 성비가 균등하여 3일째 매칭이 되지 않을 확률은 7%에 불과했습니다. 4일째에도 매칭이 되지 않는 상황이 발생하여 문제가 있다고 판단하였고, 여러 번의 테스트를 통해 세 가지 주요 문제를 발견했습니다.
-
먼저, 중복된 닉네임을 가진 유저들이 매칭 프로세스에 참여하지 못하는 문제를 해결하기 위해, 기존의 person.getName()을 키로 사용하던 방식을 person.getUser().getUserId()로 변경했습니다. 이를 통해 모든 사용자가 고유한 user_id로 매핑되어, 매칭 프로세스에 포함될 수 있도록 개선했습니다.
-
또한, 리스트를 shuffle 했음에도 불구하고 남녀 리스트의 순서가 고정되어 있었고, 이에 따라 매칭되지 않은 사용자가 반복적으로 매칭되지 않는 문제가 있었습니다. HashMap은 키의 해시값에 따라 데이터를 저장하기 때문에 삽입 순서와는 관계없이 항상 동일한 순서로 데이터를 처리하기에 발생하는 문제였습니다. 이를 해결하기 위해 데이터의 삽입 순서를 유지하는 LinkedHashMap으로 변경하였고, 이에 따라 매칭되지 않은 사용자가 반복적으로 제외되는 문제를 해결할 수 있었습니다.
-
마지막으로, 동일 성별 내에서 중복된 닉네임을 가진 사용자들이 매칭되지 않는 문제가 있었습니다. 그룹 내에서 닉네임을 키로 사용하는 데이터 구조의 제약으로 인해 발생한 문제였습니다. 닉네임 중복 체크와 수정 API를 분리하였고 사용자가 닉네임의 중복 여부를 쉽게 확인하고 수정할 수 있도록 개선할 수 있었습니다.
- 프로젝트가 확장됨에 따라 특정 그룹에서 한 성별의 user_match_active가 true인 사용자가 없을 경우 NullPointerException이 발생하는 문제가 있었습니다. '이 문제를 해결하기 위해 예외 처리를 추가하여 특정 그룹에서 한 성별의 user_match_active가 true인 사용자가 없을 경우에도, 매칭 프로그램이 계속해서 진행될 수 있도록 개선했습니다. 이를 통해 시스템의 안정성을 높이고, 매칭 프로세스가 원활하게 진행될 수 있도록 했습니다.
- 매칭 알고리즘 작동 중 사용자가 탈퇴하여 NullPointerException이 발생하는 문제가 있었습니다.이 상황을 방지하기 위해 match_in_progress(매칭 작업 실행 여부) 변수를 도입했습니다. 매칭 작업 시작 시, match_in_progress를 EntityManager를 이용해 영속성 컨텍스트에 있는 내용을 명시적으로 flush하여 true로 설정하고, 이를 통해 매칭 작업 중에는 회원 탈퇴를 막았습니다. 매칭 작업이 완료되면 match_in_progress를 false로 되돌려 회원 탈퇴가 다시 가능하도록 했습니다. 이 조치를 통해 시스템의 불안정성을 줄이고, 데이터의 일관성을 확보할 수 있었습니다.