주소정제 서비스 내재화 - 5화 ( 어질어질한 변화구들 )

복합건물 (아파트, 다세대 주택) 주소정제 정복

주소정제 내재화 전체 과정
주소정제 내재화 전체 과정
(그림: 컬리, © 2023. Kurly. All rights reserved.)

앞서 4화에서 단독건물을 어떻게 처리했는지에 대한 내용을 설명했습니다. 중간에 전라북도특별자치도, 부천시의 대규모 변경이 있었지만 미리 잘 대응을 한 결과 무탈하게 지나갔던 사건도 소개했습니다.

단독건물을 대부분 커버했음에도 여전히 40% 정도의 트래픽은 외부업체 api를 호출할 수 밖에 없는 이유를 알아냈고, 결국 트래픽을 잡기위해서는 복합건물을 해결해야 만족스러운 결과를 가져올수 있음을 깨닫게 되었는데요.

이번 5화에서는 24년 1월부터 3월까지 약 2개월간 진행된 복합건물을 정복 과정을 소개합니다.




복합건물이 단일건물보다 어려운 이유

건물 타입별 지도
건물 타입별 지도
(그림: 컬리, © 2023. Kurly. All rights reserved.)

위 이미지는 어느 복합건물(아파트)의 예시가 나옵니다.

만약 우리가 이 아파트의 208동 1111호에 배달을 간다고 생각해볼게요.

  • 경기도 수원시 영통구 삼성로 11 라는 기본주소를 Tmap에 입력.
  • 일단 아파트 정문까지 도착
  • 상세주소에서 208동을 확인하고 단지안내도를 보고 208동 찾아가기
  • 엘레베이터를 타고 11층 도착, 1111호 초인종 눌러서(예시임 울집 아님) 배달이요~

기본주소만으로 찾아갈 수 있는 단독건물에 비해 복합건물은 고객의 상세주소에 있는 상세 동 정보를 알아야 찾을 수 있습니다.

kurly mall 주소정제 팝업
kurly mall 주소정제 팝업
(그림: 컬리, © 2023. Kurly. All rights reserved.)

컬리몰 배송지 입력창을 보면 상세주소를 너무도 자유롭게 적을 수 있도록 UX가 되어있습니다.

모든 고객분들께서 '208동 5101호 이준환' 이라고 써주면 너무 좋겠죠? (대부분은 이렇게 적어주십니다.)

그런데 어떤 고객분들은 아래 형태로 써주시기도 합니다.

  • '208 5101'
  • '208-5101'
  • '2085101'
  • '이백팔동 오천백일호'
  • '2.0.8동 5.0.0.1호'
  • 2o8-5oo1호 (실제 사례, 0을 알파벳으로 적으심, 태환님이 장난치시는 줄 알았음)

위와 같은 형태의 입력들 모두 컬리UX 자체가 자유로운 타이핑이 가능하기 때문에 충분히 발생가능성이 있습니다.

고객분들께서 필수 정보(동, 호수)를 누락하시지만 않는다면 위 케이스는 고객분들의 잘못이라고 보긴 어렵겠죠?




복합건물의 경우 반드시 정확한 상세'동' 을 찾아야할까?

배송관점에서 생각했을 때 안심이 되는 부분이 있습니다.

'경기도 수원시 영통구 삼성로 11 (래미안 영통마크원 2단지)' 주소를 예로 설명할게요.

208동을 결국 찾지못해서 201동의 건물과 위경도를 응답하면 어떻게 될까요?

208동, 201동 두 건물의 응답 차이는 위도, 경도, 건물관리번호 3개 밖에 없습니다.

컬리몰 주소정제 이후 과정
컬리몰 주소정제 이후 과정
(그림: 컬리, © 2023. Kurly. All rights reserved.)

앞서 1장에서 컬리에서 정확한 주소정제가 필요한 이유는 배송권역을 알아내기 위해 필요하고, 이 배송권역을 통해 생산센터와 배송 담당자가 달라진다고 했습니다.

다만 이런 복합건물 내에서 권역이 달라지는 경우는 굉장히 드뭅니다.

결국 같은 단지내에 다른 건물의 위경도를 응답했을때의 문제는 2가지로 보입니다.

  1. 컬리배송앱에 배송위치가 엉뚱해서 새벽에 배송기사님이 자칫 고생하신다.

  2. 배송팀에서 배송불가지역을 Polygon 형태로 제공해 주시는데, 배송불가 판단에 miss가 발생 할 가능성이 있다. (컬리 샛별 불가 지역임에도 컬리배송으로 안내하여 오배송 가능성이 있다)

그리고, 어차피 외부업체 api 호출 결과에서도 OMS팀이 변화구라고 말하는 일부 상세주소 케이스에서는 상세동 추출하지 못하여 특정 1개의 동을 응답하는 경우가 빈번히 발생하고 있습니다.

그래서 OMS의 복합건물 주소정제 목표는 외부업체 호출 결과보다 낫거나 최소한 같도록 정제하자!




복합건물 정제 결과에 '정확도 레벨'의 개념을 도입

복합건물은 고객이 입력한 상세주소와 행안부 건물 DB에 있는 상세 건물명 2가지 데이터를 통해 정확한 건물을 찾는 과정입니다.

주소정제 로직을 좀더 효율적으로 패치하고 결과를 분석을 위해서는 각 주소정제 결과에 대한 레벨링을 해 놓는 것이 각종 케이스들을 관리하는데 효율적일 것이라 판단했습니다.

OMS 주소정제에서는 주소정제 결과의 레벨에 Enum 정의는 아래와 같습니다.

        public enum RefineAddressAccuracyLevel {
            EXACT("기본주소와 동일한 단지에 동 정보 및 위경도 추출"),
            HIGH("기본주소와 다른 옆 단지의 동 정보 및 위경도 추출"),
            MODERATE("정확한 상세 건물 조회 불필요 (대형병원, 대학교 등)"),
            MEDIUM("행안부 건물DB 데이터 오류 의심"),
            LOW("기본주소가 변경되거나, 철거된 건물 가능성 (직접 확인 필요)"),
            BAD("고객 상세주소 오류 의심"),
            NONE("서버에러등으로 정제 동작 실패");
        }

주소정제 정확도 레벨을 도입하면서 정제 과정에서 발생하는 이슈들을 좀더 체계적으로 관리할수 있는 장점이 있었습니다.




복합건물 주소정제의 각 정확도 레벨의 의미와 이를 판단하는 과정

아래 전체적인 판단 flow 를 보면서 설명하겠습니다.

주소정제 정확도 레벨
주소정제 정확도 레벨
(그림: 컬리, © 2023. Kurly. All rights reserved.)

위 flow에 등장하는 정제 정확도 레벨 순서대로 아래 설명합니다.



👉 LOW 레벨 (기본 주소 조회부터 실패!)

상세주소를 보기도 전에, 기본주소에서 부터 조회가 안되는 케이스를 말합니다.

  • ex) 과거에 컬리몰에 등록된 배송지이며, 현재 건물이 재건축되어 철거상태
  • ex) 동탄 2신도시의 특정 도로명이 일괄변경(동탄대로 -> 동탄역로) 되어 고객이 직접 배송지 변경을 해줘야하는 상태

두 예시의 원인은 이미 입력된 고객님의 배송지 정보가 최신화된 행안부 건물DB 데이터와 불일치 하기 때문에 발생합니다.

그래서 개발 단계에서는 LOW 레벨은 무조건 익셉션을 발생시켜 외부업체 호출을 통해서 정상 응답을 하도록 처리를 했습니다.

이러한 LOW레벨은 향후 OMS에서 건물 변경이력 DB를 관리하여 해결을 하였고, 현재는 최신화 되지않은 과거의 요청 주소도 직접 최신의 주소로 정제를 제공하고 있습니다.

그리고 이 레벨은 내재화 여정의 가장 마지막에 작업을 하였습니다. (그래서 다음화까지 보셔야함)



👉 BAD 레벨 (고객님! 동 정보를 안적어 주셨어요!)

고객 입력 상세주소에 문제가 있을 확률이 높은 케이스

  • ex) 서울특별시 강남구 압구정로29길 57 (현대아파트14차) 주소를 입력했으나, 상세주소에는 상세 동정보 없이 '1102호 이준환' 이렇게 호수 이름만 적은케이스

놀랍게도 이 케이스 엄청 많습니다.

BAD 레벨은 하루평균 100건 정도 (추출을 못했을뿐, 이중 진짜 안적은 케이스는 훨씬 적긴함) 발생합니다.

고객이 상세 동 정보를 누락한 이유이기 때문에 100% 고객과실 배송이 실패가 발생합니다. 이런 주문들을 그대로 센터로 처리하게 되면 컬리 배송 효율 측면에서는 최악이겠죠?

이런 주문들은 애초에 센터 생산조차 할 필요가 없습니다.

이를 위해 OMS 에서는 결제완료 주문을 받는 즉시 이를 감지하여 slack에 전파하고, 관련 고객상담팀을 통해 고객안내를 통해 직접 취소후 재주문을 유도했습니다.

BAD 레벨 즉각 감지
BAD 레벨 즉각 감지
(그림: 컬리, © 2023. Kurly. All rights reserved.)

만약 컬리몰 배송지 입력 UX를 다른 배달앱들의 UX처럼 고객이 직접 위치 조정을 통해 정확한 동을 자동으로 추출하도록 향후 변경이 된다면, 이 케이스도 없어지지 않을까 생각됩니다.



👉 HIGH 레벨 (진짜 기본주소는 옆 단지네?)

OMS 주소정제의 '꽃'🌸 이라 불리우는 기능

고객 입력한 기본주소 단지에 상세 동을 찾을수 없을때 혹시 근처 다른 단지에 그 동이 있는거 아냐? 컨셉으로 정확한 기본주소를 역추적 정제한 케이스를 말합니다.

  • '서울특별시 강남구 압구정로29길 57 (현대아파트14차) 208동 1111호 주소의 요청

  • 현대아파트14차 단지에는 203, 204, 205, 206 동 4개만 존재 (208동은 없어ㅠㅠ)

  • 바로 옆 단지인 현대아파트13차(서울특별시 강남구 압구정로29길 23)에 208동이 존재하는 것을 확인 후 기본주소를 현대아파트13차 주소로 정제

왜 발생하죠?

압구정동의 수많은 현대 아파트단지
압구정동의 수많은 현대 아파트단지
(그림: 컬리, © 2023. Kurly. All rights reserved.)

왼쪽의 이미지처럼 기본주소 선택 팝업들은 대부분 기본주소를 전부 입력하지 않아도 관련된 주소가 쫘르륵 나오게됩니다.

위 지도의 압구정 현대아파트는 실제 행정구역상 현대아파트1차, 2차 … 8차로 각각 명확히 구분이 되어있으나, 선택 팝업창은 그렇지 않죠.

때문에 기본주소를 잘못 선택하는 케이스가 종종 존재합니다.

현재 컬리몰의 결제 완료 주문수 기준으로 HIGH 레벨은 일 평균 150건씩 매일 발생합니다.

건수가 별로 없는데? 오버엔지니어링이 아닐까?

이 케이스의 가장 큰 문제는 높은 확률로 배송실패로 이어진다는 점입니다.

컬리는 새벽배송이고 새벽에 배송기사분이 현대아파트1차 를 찾아갔더니… 어라 40동이 없네?

배송기사분은 아침 7~8시 배송완료가 고객과의 약속이기에 다시 다른 건물로 찾아가지 않는 경우가 많습니다.

그래서 실제로 HIGH 레벨 정제가 되기 전에는 거의 대부분 배송실패로 이어지는 것을 배송결과를 통해 확인을 하였습니다.

그래서 OMS 주소정제에서는 다른 외부 주소정제 시스템에는 존재하지 않는 전례없는 기능을 추가했습니다


HIGH 레벨 정제를 위한 준비물

위 Flow 를 꼼꼼히 보셨다면 2번 연관주소 건물 리스트 조회를 왜 하는건지 궁금하셨을 겁니다.

연관주소 건물 리스트 조회를 하는 이유는 딱 1가지 HIGH 레벨을 판단하기 위함입니다.

전제는 아래와 같습니다.

  1. 고객이 상세동을 잘못 입력할 확률은 낮다. (만약 있다면 오타다)
  2. 만약에 상세동을 잘못 입력하신 것이 맞더라도, 그 케이스는 어차피 고객 과실로 배송실패다.
  3. 고객이 직접 입력한 상세동과 고객이 선택한 기본주소 건물을 기준으로 주변건물들중 같은 상세동인 것을 찾아보자.
  4. 단, 유일하게 1개 찾을때만 허용하자. (찾은게 2개 이상이라면, 어느 단지의 동인지 모호하기 때문에 도박을 할 순 없음)

주변 탐색 로직에 시행착오를 간략히 설명드립니다. (한마디로 삽질과정)

  1. 고객 선택한 기본주소와 동일한 우편번호안에있는 범위에서 찾아보자. ( 실패, 우편번호는 범위가 너무 넓고, 우편번호마다 영역이 천차만별)
  2. 고객 선택한 기본주소와 동일한 전체 도로명 코드 (충혼로224번길 -> 충원로) 범위에서 찾아보자. ( 실패, 우편번호보다는 낫다. 하지만 여전히 범위가 넓다.)
  3. 고객 선택한 기본주소 기준 반경을 조절해서 찾아보자. ( 보류, 한 반경 200~300미터 쯤 걸어놓으면 보수적으로 잘찾는 것도 같음)
  4. (이걸로 채택) 건물관리번호 앞 14자리를 활용해서 찾아보자.

4번 건물관리번호 앞 14자리와 단지 이름 토큰 ('현대아파트' -> '현대')을 like검색으로 연관 건물을 찾는것이 현재까지 나온 가장 안전한 알고리즘으로 판단되었습니다.

참고로 건물관리번호25자는 아래와 같은 특징이 있습니다.

  • 건물관리번호 (법정동코드(10) + 산여부(1) + 지번본번(4) + 지번부번(4) + 시스템번호(6) + pnu코드(19) + 시스템번호(6))
  • 전라북도가 전북특별자치도로 바뀌든 법정동 코드가 바뀌든 이런 변경과는 무관하게 건물관리번호는 항상 최초와 동일하며, 중복은 있을 수 없음. ( 항상 동일한 특징, 행안부 직원에게 크로스 체크만 200번 한 것 같음)
  • 건물관리번호 앞 14자리가 적절하다는 기술적 근거는 솔직히 없음 ( 13자리, 15자리등 여러 검증을 해봤지만 14자리가 제일 보수적이면서 중요한건 쁘락치가 없었음)

그래서 연관주소 건물 리스트기본주소 건물 리스트와 함께 정확한 고객 주소에 건물을 찾기위한 기본 재료라고 할 수 있습니다.



👉 MODERATE 레벨 (상세 건물을 정확히 찾으면 땡큐, 못찾아도 본전)

대학교, 대학 병원 등 고객입력 상세주소가 건물DB 상세주소와 매칭될 가능성이 애매한 복합건물입니다.

  • ex) 남자기숙사 이준환, 남제관 이준환 처럼 건물을 특정할 수 있는 방법이 다양함

이 케이스는 주소에 포함된 여러 건물 중 하나를 응답합니다..



👉 EXACT 레벨 (군더더기 없이 잘 찾은 케이스)

더 설명이 필요없는 단독건물, 복합건물 모두 정확한 건물을 잘 찾은 매우 이상적인 케이스입니다.

방금 조회해보니 25년 1월 14일 기준 전체 주문대비 99.2% 가 EXACT 레벨로 정제되고 있네요.



👉 MEDIUM 레벨 (상세 동을 도저히 못찾겠다. 일단 대표 건물 하나로 응답하자)

OMS 주소정제에서 모든 개발 과정을 합쳐도 MEDIUM 레벨을 건수를 줄이는 시간이 더 많았을 겁니다.

바로 아래와 같은 케이스들 때문입니다.

  • ex) 행안부에는 '208동', 고객입력은 '이백팔동' 한글로 입력
  • ex) 행안부에는 '208동', 고객입력은 '2.0.8동' . 으로 숫자 구분
  • ex) 행안부에는 '208동', 고객입력은 '2o8' 숫자 0을 알파벳 o 로 입력

팀 내에서는 이런 케이스를 고객분들이 던지는 변화구라고 표현합니다.

행안부 건물 DB도 완벽하지않음

행안부 건물 DB에도 상세 동이 전부 비어있는 경우도 있고, 같은 동 이름인 208동이 3개 존재하는 경우도 있습니다.

다행인건 MEDIUM 레벨은 배송실패로 이어지는 비율이 거의 없다

일단 배송할 건물의 단지까지는 배송기사분이 잘 찾아가시고 이후 배송앱의 찍혀있는 핀을 무시하고 상세주소를 확인하신후 정상적으로 배송완료가 됩니다.

그럼 뭐가 문제일까?

  • 정확한 위경도를 주지 못해서 정확한 건물 위치에 핀을 찍지 못한다. (오배송 간혹 존재)
  • 배송 불가지역 Polygon에 간발의 차이로 빗나갈 때가 간혹 존재 ( 샛별 배송불가 지역임에도 배송 시도)

위 2가지 이유로 절대 무시해서는 안되는 레벨입니다.

그래서 '2o8동'이나 '2.0.8동'같은 이런 낙차 큰 변화구를 제외하고는 지속적으로 버전 패치를 통해 MEDIUM 레벨을 줄여나가고 있습니다.

아래 테스트 코드는 거의 대부분 MEDIUM 레벨을 잡기위해 추가되었습니다. (혈압 주의)

이 테스트 코드들은 새로운 패치 버전의 기준이 되어, 패치 버전이 기존 코드에 어떤 상세주소 패턴에 영향을 주는지 쉽게 판단할 수 있었습니다.

고객입력 상세주소로 건물 추출 테스트코드
고객입력 상세주소로 건물 추출 테스트코드
(그림: 컬리, © 2023. Kurly. All rights reserved.)

MEDIUM 레벨은 결제완료 주문건수 기준 하루 평균 300~400건 정도 발생합니다.



👉 NONE 레벨 (이번 패치 버전에 버그가 있는 것 같아!)

위 케이스들이 아닌 알수없는 이유로 주소정제에 실패한 케이스

이 케이스는 사실상 원인 불명으로 외부업체 호출한 케이스를 캐치하기위해 생성한 레벨입니다.

여러 패치 버전을 카나리 -> 전체 배포 의 반복이었는데요. 절대 발생해서는 안되는 레벨입니다.

에러로그로 캐치하면 되지않니? (뭐 그래도 되죠)

(프로젝트가 완료된 지금은 미발생)




고객이 입력한 상세주소에서 상세 동을 추출 방법

1. 전 처리 로직없이, 행안부 건물DB의 건물명 그대로 고객 입력 상세 건물 이름과 매칭되는 건물이 단 1개만 존재하는지 확인 -> 있으면 그 값을 신뢰

  • '1002호 102동' 처럼 동호수 순서가 바뀌어서 입력한 케이스
  • 상세 주소가 진짜 특정 가게이름이나 어린이집 이름인경우 '드림디포 1층'
  • 위와 같은 케이스들이 대부분 걸러집니다.
  • MODERATE 레벨의 주소들이 이 과정에서 정확한 동을 찾아내기도 합니다..

2. (1번 실패 시) 행안부 건물DB 상세동 이름과 고객요청 상세주소 2개 모두 전 처리 로직 실행

3. 전 처리된 행안부 건물 DB와 매칭되는 상세 동이 단 1개만 존재하는지 확인

행안부 건물 DB 건물이름, 고객 상세주소 전 처리 과정
행안부 건물 DB 건물이름, 고객 상세주소 전 처리 과정
(그림: 컬리, © 2023. Kurly. All rights reserved.)

행안부 건물데이터는 각 지차체에서 직접 관리하고 행안부는 종합하여 제공하는 형태임을 행안부 직원을 통해 (또) 확인을 하였습니다.

진짜 확실히 지역 특징이 있긴하더라고요. 부천쪽에 어느 지역은 굳이 아파트명을 괄호로 붙여서 '(푸르지오) 103동' 이렇게 과잉 친절을 해주시는 경우도 있고, '103' 과 같이 알맹이만 적는 동네도 있습니다.

그래서 고객 입력 상세주소와 마찬가지로 행안부 건물 DB의 건물이름 또한 비교하기 좋게 전 처리 과정이 필요합니다.

전 처리 과정을 통해 한번 추출해볼게요.

  • 고객 상세주소에서 추출 된 상세 동 후보 : 5, 504
  • 행안부 건물 DB의 건물이름 : 501, 502, 503, 504, 505, 506 …

일치하는 상세동은 단 1개 '504동'을 추출할 수 있겠네요.




행안부 건물 이름을 전 처리하는 과정에서 알파벳과 한글동을 전부 숫자로 변환하는 이유

MEDIUM 레벨로 정제되는 요청에 약 5% 정도의 비율로 같은 건물에 거주하시는 고객들마다 A동, 가동 으로 섞여서 입력이 되는 복합건물(특히 빌라) 정제 요청이 많았습니다.

고객은 A동을 입력했지만, 실제로 로드뷰로 찾아가 보면 '가동'으로 건물에 표시되어 되있습니다. 어떤 이유에서인지 실제로 A,B와 가,나 동을 혼용된 케이스로 인해 추출이 실패하는 경우가 많았어요.

그래서 이런 케이스를 행안부 건물 이름, 상세주소에 동 후보군 양쪽 모두 통일된 값으로 처리하기 위한 아이디어입니다.




복합건물을 정복의 숨은 공신

OMS 백오피스의 행안부 건물 관리 페이지가 없었다면, 아마 굉장히 힘든 과정이었을 것 같습니다.

OMS 백오피스의 행안부 건물DB 관리 페이지
OMS 백오피스의 행안부 건물DB 관리 페이지
(그림: 컬리, © 2023. Kurly. All rights reserved.)

이 페이지는 건물 DB를 생성한 직후 부터 느껴지는 경험들을 기반으로 기능들이 계속 패치되어 현재는 없어서는 안될 중요한 툴이 되었습니다.

주요기능을 소개합니다.

  • 기본주소, 건물관리번호, 출고요청번호 3가지로 입력으로 건물 조회가 가능
  • 특정 건물에 주소와 각종 건물 DB의 정보를 조회 및 수정 가능
  • 클릭 한 건물 주변에 원하는 반경을 입력하여 주변에 존재하는 모든 건물들 조회 (빨간색 핀, 같은 단지 건물은 검정색 핀)
  • 드래그로 아주 쉽게 건물 위치 조정 가능
  • 조회 된 건물들의 위경도 일괄 변경
  • 변경히스토리 조회 및 직접 추가 기능
  • 비개발자 염태환님 조차 직접 CS대응에 관여하게 만듬 (개인적으로 가장 의미있다고 판단)
  • 특정 건물로 주소정제 된 모든 요청 캐시의 상세주소 조회가 가능하고, 필요시 일괄 삭제 기능

MEDIUM 레벨은 행안부 건물 DB 이름의 문제가 굉장히 많았는데, 건물이름을 일괄로 변경할 수 있어서 OMS의 건물 DB 데이터를 빠른시간에 완벽한 데이터로 만들 수 있었다고 생각합니다.

또한 OMS 주소정제의 꽃🌸 이라 불리우는 HIGH 레벨의 아이디어를 이 백오피스를 통해 얻게되었습니다. 주변 건물들의 속성을 너무도 효율적으로 확인이 가능했기에 HIGH 레벨을 구현하는데 가장 적합해 보이는 단서를 찾을 수 있었습니다.

여튼 킹정한다




마지막화 내용 미리보기

복합건물을 정복 후 운영환경에서 외부업체 호출 건수는 눈으로 세아릴 수 있는 수준으로 줄어들었습니다.

비용으로 환산하면 기본료를 포함하여 한달에 약 35만원의 비용이었는데요.

이때부터

  • 박수석 그룹장님은 "이거 언제 마무리되요?" (솔직히 50번은 들은 것 같음)

  • 염태환 PM은 "한달에 33만원 정도면… 그래도 계약은 유지하는게 낫지않아요?" (그룹장님보단 그래도 좀 나은편. 한 20번정도?)

부류st 질문들을 귀에 자주 때렸던 기억이 납니다.

그래서 마지막화는 위 두 인물의 질문들에 대한 prove it! 그리고 그간 개발 과정에 대한 회고입니다.

6화 엔드게임 보러가기