← 기술 블로그

결정성 매칭 엔진 설계: 퍼지 매칭을 버린 이유

Phase: 3 — 매칭 시리즈: 공공데이터 레시피 대응 스토리: 운영 블로그 10화, 운영 블로그 11화

이 글의 배경이 되는 이야기는 10화: 이 성분이 저 성분이랑 같은 건가요11화: 700만 번의 대조 작업에서 읽을 수 있습니다.

이 글을 읽으면 알 수 있는 것


문제: 98만 건의 원재료를 4만 3천 개의 사전과 연결하라

식품 원재료 데이터를 표준 사전과 연결하는 것이 매칭 엔진의 목적입니다.

제조사가 “정백당”이라고 적었으면, 사전의 “설탕” 항목과 연결해야 합니다. “식물성 유지”와 “식물성유지”가 같다는 것도 알아야 합니다.

문제는 이 작업을 98만 건에 대해 해야 한다는 것이었습니다. 사람이 하나하나 확인할 수는 없으니, 자동화가 필요했습니다.


갈림길: 유사도 vs 결정성

자동 매칭을 설계할 때 크게 두 가지 접근이 있습니다.

방식동작장점리스크
유사도 기반 (퍼지 매칭)이름 간 유사도를 계산하여 가장 높은 것과 연결사전에 없는 변형도 유연하게 잡음”고추냉이”가 “고추”와 연결될 수 있음
단계별 결정성 매칭정확 일치 → 이명 일치 → 괄호 제거 → 부분 포함 순으로 시도각 단계의 결과가 재현 가능어디에도 안 걸리면 미매칭

유사도 기반 매칭은 직관적입니다. 두 문자열이 얼마나 비슷한지 점수를 매기고, 가장 높은 것과 연결하면 됩니다.

하지만 식품 원재료에서는 치명적인 문제가 있었습니다.


유사도가 위험한 이유

“고추냉이”와 “고추”는 글자의 절반 이상이 겹칩니다. 유사도 점수만 보면 꽤 높게 나옵니다. 하지만 고추냉이는 고추와 전혀 다른 식물입니다.

“탄산수소나트륨”과 “탄산나트륨”도 비슷합니다. 유사도 점수가 0.8 이상 나올 겁니다. 하지만 이 둘은 서로 다른 물질입니다.

식품 데이터에서 이런 종류의 오매칭은 단순한 불편이 아닙니다. 알레르기 정보가 뒤바뀔 수 있습니다. “비슷하니까 맞겠지”가 통하지 않는 영역입니다.

그리고 유사도 매칭에는 또 하나의 문제가 있었습니다. 재현성이 없다는 것입니다.

유사도 임계값을 0.8로 잡으면 어떤 결과가 나오고, 0.75로 바꾸면 다른 결과가 나옵니다. 사전에 항목이 추가되면 기존 매칭 결과가 바뀔 수도 있습니다. 700만 건의 매칭이 “이번에는 이렇게, 다음에는 저렇게” 달라지면 검증이 불가능합니다.


선택: 단계별 결정성 매칭

결정성 매칭은 이런 구조입니다.

입력: "정백당"

1단계 (exact):     사전에 "정백당"이 있는가? → 없음 → 다음
2단계 (alias):     사전의 이명 목록에 "정백당"이 있는가? → "설탕"의 이명에 있음 → 매칭

각 단계는 “있거나 없거나”입니다. 유사도 계산이 아니라 존재 여부 확인입니다. 같은 입력을 넣으면 항상 같은 결과가 나옵니다.

실제 매칭은 여러 단계로 구성되어 있습니다. 핵심 원칙은 두 가지입니다.

첫째, 위에서 아래로 순서대로 시도하고, 먼저 걸린 곳에서 멈춥니다. 정확 일치를 먼저 시도하고, 안 되면 이명 일치, 그래도 안 되면 정규화 후 일치, 마지막으로 부분 포함 순서입니다. “정백당”이 첫 단계에서 사전 표준명과 일치하면, 나머지 단계는 시도하지 않습니다.

둘째, 각 단계마다 신뢰도 점수를 부여합니다. 정확 일치는 높은 점수, 부분 포함은 낮은 점수. 이 점수가 나중에 “자동 승인”과 “수동 검토”를 나누는 기준이 됩니다.


신뢰도 점수의 의미

각 단계에 부여한 신뢰도 점수(1.0~0.7)는 “이 매칭이 얼마나 확실한가”를 나타냅니다.

이 점수는 매칭 후에 어떤 것을 자동 승인하고, 어떤 것을 수동 검토할지 나누는 기준입니다.

신뢰도 0.9 이상 → 자동 승인 (AUTO)
신뢰도 0.9 미만 → 검토 대기 (PENDING)

정확 일치(1.0)와 정규화 후 일치(0.95)는 자동으로 넘어갑니다. 반면 부분 포함(0.7)은 “고추냉이→고추” 같은 오매칭 가능성이 있으므로 검토 대상입니다.

이렇게 하면 700만 건 전부를 사람이 확인하지 않아도, 불확실한 것만 모아서 집중 검토할 수 있습니다.


contains 매칭의 안전장치

결정성 구조에서 가장 위험한 단계는 contains(부분 포함)입니다. “원재료명 안에 사전 이름이 들어 있으면 매칭”이라는 규칙은 유연하지만, 오매칭 가능성이 높습니다.

이 위험을 줄이기 위해 몇 가지 보호 규칙을 넣었습니다.


사전 구축의 결정성: 동명이인 문제

매칭 자체뿐 아니라, 매칭에 사용하는 사전을 구축하는 과정에도 결정성이 필요했습니다.

4만 3천 개의 표준 원재료 중, 같은 이름을 가진 항목이 있습니다. “물”이 식품원료로서의 물과 위생용품으로서의 물, 양쪽에 등록되어 있는 식입니다.

이때 “어느 쪽을 선택하는가”가 매번 달라지면, 매칭 결과도 달라집니다.

이를 해결하기 위해 코드군 우선순위를 정했습니다. 식품원료(A)가 첨가물(B)보다 우선하고, 첨가물이 위생용품(E)보다 우선합니다. 같은 우선순위라면 최신 수정일이 우선합니다.

이 규칙 덕분에, 사전에 항목이 추가되거나 수정되어도 매칭 결과가 예측 가능한 방식으로만 변합니다.


결과

항목수치
전체 매칭 건수약 725만 건
매칭 성공률99.5%
정확 일치 비율약 93%
미매칭 건수약 3만 8천 건
고유 원재료명 (캐시)중복 제거 후 재계산 생략

한계

미매칭 3만 8천 건은 여전히 남아 있습니다. 결정성 매칭은 어떤 단계에도 해당하지 않으면 “모르겠다”고 말하는 구조입니다. 유사도 매칭이었다면 어떤 값이든 돌려줬을 것입니다. 하지만 잘못된 답보다 “모르겠다”가 낫다고 판단했습니다.

contains 단계에서의 오매칭을 완전히 막지는 못합니다. 안전장치를 넣었지만, 새로운 패턴의 오매칭은 발견될 때마다 규칙을 추가해야 합니다. 이 과정은 끝나지 않았습니다.

한 줄 교훈

식품 데이터에서는 “틀릴 바에야 모르겠다고 말하는 것”이 맞습니다. 유연함보다 재현성을 선택한 것은, 700만 건을 검증 가능하게 만들기 위해서였습니다.


다음 글: 2-Pass Alias 정제: 데이터가 데이터를 하이재킹할 때