월요일, 8월 08, 2016

Web Project: KUSM


1. Introduction
KUSM은 Korea University Sports Matching Service에서 약자로 따온 이름이다. 말그대로 고려대학교 학생들이 손쉽게 스포츠경기에 대한 상호작용을 하도록 돕는 웹서비스이다.

사실 실질적으로 매치를 해주는 기능은 없다. 단, 한 마디로 이 서비스를 요약하자면,
"고려대학교 녹지운동장 예약현황에 대한 정보 제공 + 커뮤니티 서비스 (SNS)" 이다.

기본적으로 c9.io라는 IDE와 Ruby on Rails라는 프레임웍 위에서 작업을 하였으며, Devise, Nokogiri, Fullcalendar 등의 gem 사용 및 여러 데이터베이스 모델링 기법들을 적용해보았다.

2. 문제 인식
다음 사진은 실제 고려대학교에서 운영중인 학교시설 예약 사이트이다.


이렇게 하나의 큰 달력(?)이 뜨고 예약불가/예약완료/훈련 등의 상태를 표현해준다. 그런데, 이렇게 표현을 할 경우 누가 언제 예약을 했는지 한눈에 알아보기가 힘들다.
설상가상으로, 예약완료라는 푸른 부분을 클릭하면 다음과 같은 팝업이 뜬다.


승인/승인거부로 나뉘는 것은, 같은 타임슬롯에 대해 여러 팀이 예약 신청을 했을 경우 예약에 성공한 팀과 실패한 팀을 나눈 것이다. 따라서 사실상 승인거부상태인 데이터는 거의 필요가 없는 데이터이다.

그리고 한 가지 더 주목할 점은, 바로 모임명이다. 체육시설을 사용하는 주체들은 대부분 동아리 단위이다. 그런데, 고려대학교의 시설 예약 시스템에서는 다음과 같은 제약사항이 존재하기 때문에 하나의 동아리에서, 예를 들어 로스쿨축구부라는 동아리에서 여러 타임슬롯에 최대한 많이 예약을 하고 싶을 경우, 여러 명의 회원들을 동원해서 각기 다른 명칭의 모임명(ex. 로스쿨축구부1, 로스쿨축구부2, 로스쿨축구부짱, 로스쿨축구부최고, ...)을 사용해야 하는 것이다. 이는 현실적으로 동아리라는 체계와 괴리가 생기는 부분이다.


만약, 로스쿨축구부의 동아리장이 특정 달에 예약성공한 모든 타임슬롯을 찾아보고자 한다면, 일일이 각기 다른 명칭과 예약신청인으로 등록된 예약정보를 확인해야 한다.

3. 문제 해결
이러한 불편함들을 해소하기 위해 승인완료된 예약정보를 한 눈에 정리해서 볼 수 있도록 간편하게 구성하였다. 로그인을 하였을 때 메인페이지의 모습이다.


웹 크롤링 구현, 게시판 시스템 구현
Nokogiri를 통해 실제 고려대학교 예약 사이트로부터 데이터를 크롤링해서 다음 예약 일정에 대해서 공지사항으로 알려주고, 오늘의 일정들을 쭉 나열해준다.
각각의 타임슬롯을 클릭하면 슬라이드처럼 내려오면서 나타나는 관련된 게시글들을 볼 수 있으며, 게시글을 작성할 수도 있다. 이때 카테고리로, 팀 또는 용병 둘 중 한 가지를 선택할 수 있으며, 해당 타임슬롯에 잡힌 팀에 용병으로 축구경기를 뛰고 싶다거나, 예약은 당장 잡아놨는데 야구경기를 할 다른 동아리 팀이 필요하거나 할 때 활용할 수 있도록 하였다. 그리고, 작성된 게시글들은 가장 최근에 작성된 게시글을 선두로 정렬되어 우측에 표현되도록 하였다. 타임슬롯이 아니라 게시글만 따로 모아서 보고싶다면, 상단의 게시판 탭을 사용하면 된다. 각 게시물에 또한 댓글을 작성할 수 있게 해두어서 커뮤니케이션 측면을 좀 더 강화했다.
1:N, M:N 등 DB간의 관계를 다채롭게 정의해둔 결과물이다.

검색기능 구현
중앙에는 검색바를 제공해서 원하는 자료를 찾아볼 수 있으며, Datepicker를 통해 달력의 날짜를 클릭하면 해당 날짜의 예약현황을 불러오는 기능도 구현해두었다.

문자열 그룹핑 알고리즘 구현
그리고 자세히 보면, 예약현황 리스트에 예약팀, 소속팀이라는 두 개의 팀 정보가 있는데, 여기서 예약팀이 바로 앞서 봤던 모임명에 해당한다.
문제인식 단계에서 하나의 동아리라는 주체가 여러 개의 모임명으로 분해됨에 따른 괴리를 최소화하기 위해서 서버단에서 내부적으로 알고리즘을 돌려서 모임명의 문자열이 비슷한 것들끼리 그룹화를 하였다. 즉, 실제 동아리 이름을 추측해내는 것이다.

이 알고리즘을 구현하는데 있어서 Jaccard Index 등 여러 개념들을 살펴보았는데, 개발 시간이 제한되어 있었을 뿐만 아니라, 그다지 어려운 개념은 필요할 것 같지 않아서 그냥 데이터셋에 오버핏(?)된 방법을 사용하였다.

대부분 모임명의 이름을 자신의 동아리이름ㅇㅇ123 이런식으로 짓기 때문에, 생각보다 간단하게 로직을 구성하였다. 우선 미래에 데이터의 수가 많아질 것을 대비해서, 실제 동아리명에 영향을 주지 않는 것들 (숫자와 특수문자, 혹은 "FC"같은 단어들)를 제거한 뒤 알파벳을 모두 소문자로 만들었다. 그러면 벌써부터 겹치는 데이터가 발생하게 된다. (ex. "축구부#1", "축구부^2" => "축구부")
따라서 이 데이터들을 Unique 조건을 만족하는 Relation으로 만들어버리면 데이터의 수가 대략 60~70% 정도로 줄게 된다.
이 유니크한 문자열들을 쭉 정렬하면, 직관적으로 비슷한 모임명끼리 뭉치게 된다. Linear하게 검사를 해서, 바로 옆에 위치한 문자열들끼리 유사성 검사를 진행한다.
만약 서로 공유하는 문자가 연속적으로 2개 이상 나타나면, 해당 공유된 문자열을 "후보"라는 자료구조에 저장해둔다.
과정을 마친 뒤 "후보"를 살펴보면 거의 대부분은 실제 동아리 이름이 나타나는 것을 확인할 수 있다. 이 중 육안으로 동아리 이름이 확실하게 아닌 것들은 제거하고, 수정사항이 있으면 약간의 수정을 한다.
최종적으로 정제된 "후보" 자료구조를 서버에 전달해주면, "후보"에 저장된 동아리명과 유사한 이름을 가진 모임이 자동으로 해당 동아리에 소속되도록 업데이트된다.

이러한 과정을 통해서, '내 정보' 페이지로 가면 회원가입을 할 때 입력해두었던 소속팀의 예약현황을 한 눈에 알아볼 수 있다.


동아리 회원 중 누가 예약 성공을 많이 했는지, 많이 못했는지 등을 보고 꾸지람(?)을 하기에도 안성맞춤이다.

기타
이외에도, Devise를 통한 회원 계정 관리 체계를 구성하고, Fullcalendar를 통해 주간/월간 일정을 한 눈에 알아볼 수 있도록 좀 더 시각적인 효과를 주었다.


4. Source Code
전체 코드는 Github에 올려두었다. 버전관리, 협업용으로 사용한 것이 아니라 단순 파일 업로드용으로 사용한 것이기 때문에 다소 커밋이 지저분하고 브랜치의 사용이 아주 정직(?)하다.
https://github.com/arkainoh/KUSM

댓글 1개: