9 BUILDING KNOWLEDGE GRAPHS · CHAPTER 9 · PART II

아이덴티티
지식 그래프

Identity Knowledge Graphs — Entity Resolution & Master Data

사람이나 사물을 확신을 갖고 식별하는 능력은 비즈니스 정보 시스템의 기반암이다. 두 레코드가 주어졌을 때, 그것이 같은 현실 세계의 것(사람·조직·장소 등)을 나타내는지 판정할 수 있는가? 서로 다른 시스템의 데이터를 통합할 때 흔히 마주치는 이 문제는 엔터티 해석(entity resolution) 또는 마스터 데이터 관리라 불린다. 이 장은 지식 그래프의 위상이 여러 엔터티를 연결할 확신을 주어, 단일한 골든 레코드처럼 추론하게 해 주는 방법을 다룬다.

Jesús Barrasa · Jim Webber O'Reilly Media, 2023 Part II. Use Cases pp. 135–154
Knowing Your Customer

고객을 안다는 것 — Jane Coleman은 Jane Downe인가

아이덴티티와 그 무수한 어려움은 일상의 경험이다. Jane Coleman은 수년간 은행 신용카드의 행복하고 수익성 있는 고객이었다. 몇 달 전 Jane은 남편 Peter와 결혼하며 남편의 성을 따르기로 했다. Jane Downe과 Peter Downe은 이 은행의 공동 당좌 계좌 소유자다. 그런데 은행은 Jane Coleman과 Jane Downe이 같은 사람임을 어떻게 알 수 있을까? Jane이 은행에 알릴 의무는 없다 — (의사 같은 일부 전문직에서 드물지 않듯) 결혼 전 성을 계속 쓸 자유도 있다.

그 결과 Jane은 이미 가진 신용카드 계좌를 개설하라는 초대장을 우편함으로 정기적으로 받는다. 명백한 시간과 돈의 낭비이고 Jane에게는 가벼운 성가심이다. 그러나 Jane이 사기꾼이었다면, 단일한 아이덴티티를 분별하지 못한다는 사실이 그 모든 활동의 추적을 방해했을 것이다.

레코드에 일관된 강한 식별자(strong identifier)가 있으면 연결은 쉽다 — 개인의 사회보장번호나 여권 번호, 제품의 고유 SKU, 정부 기관이 발급한 고유 기업 식별자 같은 것들이다. 데이터베이스 실무자들이 고유 식별자에 그토록 신경 쓰는 이유다. 그러나 모든 것이 고유 식별자만큼 단순하지는 않다 — 강한 식별자가 존재하되 모든 데이터에 걸쳐 일관되지 않은 경우가 있다. Jane이 신용카드 계좌는 운전면허증으로, 당좌 계좌는 여권으로 개설했을 수도 있다.

Example 9-1 · 전형적인 그림 — 쉬운 쌍과 어려운 쌍CSV
rowid, Source, AccountNo, Name, Passport, DriversLic, DOB
1, "Credit",  9918475, "Pete Downe",     "VX83041",,           1987-03-12
2, "Current", 2436930, "Peter J. Downe", "VX83041",,           1987-03-12
3, "Credit",  ,        "Jane Coleman",   ,          "49587640", 1989-10-28
4, "Current", 2436930, "Jane Downe",     "RA14958",,           1989-10-28

1·2행은 잇기 쉽다 — 같은 여권 번호가 있으니 Pete Downe과 Peter J. Downe이 같은 사람이라고 안전하게 추론할 수 있다. 3·4행은 훨씬 어렵다 — 이름이 다르고(결혼 전·후의 성) 공통 영숫자 식별자도 없다. 이 데이터만으로는 두 행이 서로 다른 두 사람일 강한 가능성을 결론 내려야 할 것이다. 강한 식별자가 아예 없으면 문제는 더 심각해진다 — 그때는 가용한 피처가 무엇이든, 종종 그 조합을 사용해 두 유사한 참조가 같은 것을 가리키는지 판정해야 한다.

When Does the Problem Appear?

문제가 나타나는 세 가지 시나리오

중복 데이터를 마주치는 시나리오는 여럿이지만, 가장 흔한 것은 다음 셋이다.

① 데이터 통합

아마도 가장 빈번한 경우다. 판매·CRM·마케팅 등 각 애플리케이션이 고객(제품·이벤트…) 데이터의 변형을 독립적으로 수집·관리한다. 시스템 간 일관된 강한 식별자 없이 레코드가 제각기 식별·기술되며, 중복 문제를 먼저 풀지 않으면 통합 데이터의 어떤 분석 워크로드도 신뢰할 수 없다. 중복 레코드를 식별해 마스터 데이터 엔터티(골든 레코드)로 병합하고 단일 신뢰 뷰를 세워야 한다.

② 익명 활동

공개 시스템 다수는 인증 없이 상호작용(예: 상품 탐색)을 허용한다. 정의상 사용자를 식별할 인증은 없지만, 사용자는 활동과 접속 장치의 흔적(클릭스트림)을 남긴다 — 시간, 쿠키 ID, 심지어 탐색 선택까지. 이 흔적이 패턴을, 궁극적으로는 고유 사용자와 세션을 식별하는 데 도움이 된다.

③ 의도적/사기적 중복

악의적 행위자가 시스템을 속이려 일부러 중복을 만들기도 한다 — 주소·나이 등을 살짝 바꿔 더 좋은 보험 견적을 받으려는 개인, 가짜 이메일·이름으로 서비스 무료 체험을 남용하는 사용자, 노출과 판매 기회를 극대화하려 같은 상품의 소소한 변형 리스팅을 여럿 올리는 온라인 판매자.

공통의 근본 질문

세 시나리오 모두 같은 근본 질문을 공유한다 — 두 레코드가 주어졌을 때, 같은 엔터티를 가리키는가, 다른 엔터티를 가리키는가? 그래프 기반 엔터티 해석은 세 가지 근본 활동으로 진행된다: 데이터 준비 → 엔터티 매칭 → 마스터 엔터티의 영속 레코드 큐레이션.

실습 데이터로 개인 정보를 담은 세 개의 겹치는 데이터셋(ds1·ds2·ds3.csv)을 쓴다 — 중복을 제거하고 단일 뷰로 통합해야 한다. ds1은 full_name·ssn·passport_no·yob(출생 연도), ds2는 "성, 이름" 형식의 name과 age(나이), ds3은 first_name/last_name 분리와 dob(완전한 생년월일)을 갖는다 — Sidney Bernardy, Cherish Gosnall, Husein·Hana Sprull, Jonathan Pedracci, Ernestine Ouchterlony의 변형 레코드들이 파일들에 흩어져 있다.

Data Preparation

데이터 준비 — 비교 가능한 형태로 조화시키기

준비 국면의 목적은 데이터가 요구되는 품질 특성을 충족하도록 만드는 것이다. 독립적으로 관리되는 여러 데이터셋이 있으면 서로 비교 가능하도록 조화(harmonize)시켜야 한다 — 데이터 타입·단위 정렬 (모든 거리는 km, 모든 가격은 달러, 모든 점수는 0~1 등)이 여기 포함된다. 단일 소스라도 매칭에 쓸 피처는 모두 정제·표준화해야 결과 품질이 최대화된다 — null이 문자열 "null"이 아니라 진짜 null인지, 문자열 형식 통일(전부 대문자 또는 소문자, 인코딩), 트리밍, 다중 공백·특수문자 제거 등이다.

첫걸음은 데이터를 지식 그래프로 모델링해 그래프 데이터베이스에 담는 것이다. 각 레코드가 사람을 나타내므로 모델은 가장 단순하다 — 행마다 Person 노드, 컬럼마다 그 노드의 속성이다. 파일별 고유 컬럼(yob·age·dob)이 노드 구조에 약간의 가변성을 만들지만, 지금은 괜찮다 — 매칭 국면 전에 처리한다.

Example 9-3 · 개인 데이터 파일 적재 (source로 계보 기록)Cypher
LOAD CSV WITH HEADERS FROM "file:///ds1.csv" AS row
CREATE (p:Person) SET p.source = "ds1", p += properties(row) ;

LOAD CSV WITH HEADERS FROM "file:///ds2.csv" AS row
CREATE (p:Person) SET p.source = "ds2", p += properties(row) ;

LOAD CSV WITH HEADERS FROM "file:///ds3.csv" AS row
CREATE (p:Person) SET p.source = "ds3", p += properties(row) ;
Note — 데이터 관리에 단 하나의 방법은 없다

이 국면의 작업 일부는 데이터가 그래프에 적재되기 전에 수행해도 정당하다 — 파일에 직접 Python(pandas가 훌륭한 도구다)을 쓰거나, 클라우드 데이터 웨어하우스에 적재 후 SQL 변환으로 할 수도 있다. 그 경우 Example 9-3은 매칭 준비가 끝난 데이터를 그래프 DBMS에 싣기만 하면 된다(단, 그래프로 모델링된 뒤에만 추출 가능한 그래프 피처는 예외다). 접근법 선택의 기준은 단순성·견고성·성능이다.

파일 간 가장 뚜렷한 차이는 생년월일 정보의 상세 수준이다 — ds1은 4자리 문자열 연도(yob), ds2는 현재 나이 문자열(age), ds3은 완전한 생년월일 문자열(dob)이다. 매칭 국면에서 비교 가능하게 만들 정보의 최소 공통분모는 출생 연도다. source 속성으로 소스별 변환 로직을 분기하고, 수 캐스팅·날짜 함수·산술 연산자를 원본 데이터에 적용해 정수형 m_yob(matching year of birth)를 만든다. 이름도 정렬이 필요하다 — 성·이름 분리, "성, 이름" CSV, 전체 이름 단일 문자열이 혼재하므로, trim·toLower·split으로 firstname lastname의 정준 표현인 m_fullname을 만든다.

Example 9-4 · 날짜 정규화 (m_yob)Cypher
MATCH (p:Person) WHERE p.source = "ds1"
SET p.m_yob = toInteger(p.yob) ;

MATCH (p:Person) WHERE p.source = "ds2"
SET p.m_yob = date().year - toInteger(p.age) ;

MATCH (p:Person) WHERE p.source = "ds3"
SET p.m_yob = date(p.dob).year ;
Example 9-5 · 이름 정규화 (m_fullname)Cypher
MATCH (p:Person) WHERE p.source = "ds1"
SET p.m_fullname = toLower(trim(p.full_name)) ;

MATCH (p:Person) WHERE p.source = "ds2"
WITH p, split(p.name,",") AS parts
SET p.m_fullname =
  toLower(trim(parts[1]) + ' ' + trim(parts[0]));

MATCH (p:Person) WHERE p.source = "ds3"
SET p.m_fullname =
  toLower(trim(p.first_name) + ' ' + trim(p.last_name)) ;
Sidebar — 블로킹 키: n² 을 길들이기

준비 국면에는 선택적으로 블로킹 키(blocking key) 생성이 포함될 수 있다. 중복을 찾으려면 모든 레코드를 서로 비교해야 하므로 n개 요소에 n² 연산이 필요하다. 이를 감당 가능한 계산량으로 줄이려면 매치를 낳을 것 같지 않은 쌍의 비교를 피해야 한다 — 그것이 블로킹 키의 일이다. 같은 블로킹 키를 가진 후보끼리만 비교한다. 우편번호처럼 데이터의 "자연스러운" 피처를 쓸 수도 있고(합리적 근접 범위의 엔터티만 비교), 없으면 알고리즘이나 ML 모델의 제안을 포함해 합성으로 생성할 수도 있다.

Entity Matching

엔터티 매칭 — 다섯 단계의 규칙 적용

매칭은 엔터티 해석 과정의 중심 활동으로, 아이덴티티 로직이 적용되는 곳이다. 비즈니스 휴리스틱에 기반해 두 엔터티가 같다고 간주되는 시점을 정의하고, 준비 국면에서 식별·가공한 피처에 규칙 집합을 적용한다. 규칙의 복잡도는 다양하지만 일반적으로 정확 일치(강한 식별자에 유용), 거리 정의 기반 근사 일치(숫자·날짜·임베딩), 그리고 퍼지 요소(문자열 유사도, 값 근사 등)에 기반한다. 어떤 규칙은 단정적 매치를 주고(강한 식별자), 어떤 규칙은 확률적 점수화를 위한 가중치를 준다.

1

SAME_AS — 강한 식별자 일치

강한 식별자 피처가 일치하는 노드 사이에 SAME_AS 관계를 만든다.

2

SIMILAR — 약한 식별자의 임계 초과 일치

약한 식별자 피처가 임계값을 넘겨 일치하고 SAME_AS가 없는 노드 사이에 가중 SIMILAR 관계를 만든다. 가중치는 유사도 점수다.

3

강한 식별자 불일치 폐기

강한 식별자 피처 중 하나라도 불일치하는 SIMILAR 관계를 폐기한다.

4

비식별 피처로 가중치 보정

비식별(nonidentifying) 피처가 임계 초과로 일치하면 SIMILAR 가중치에 보정 계수를 적용한다.

5

최소 점수 미달 폐기

유사도 점수가 최소 임계값에 못 미치는 SIMILAR 관계를 폐기한다. → SAME_AS·SIMILAR로 연결된 노드들이 고유 엔터티를 식별하는 그래프가 남는다.

이 다섯 단계는 암묵적으로 세 유형의 피처를 정의한다 — 강한 식별자(예제에서 passport_no와 ssn), 약한 식별자(m_fullname — 이름 일치만으로는 동일인 도출이 불충분하므로 2차 식별자로 취급), 비식별 피처(m_yob)다.

Example 9-6 · Step 1 — SAME_AS 생성Cypher
MATCH (p1:Person), (p2:Person)
WHERE p1.source <> p2.source
  AND (p1.ssn = p2.ssn OR p1.passport_no = p2.passport_no)
  AND id(p1) > id(p2)
CREATE (p1)-[:SAME_AS { ssn_match : p1.ssn = p2.ssn,
              passport_match : p1.passport_no =
              p2.passport_no}]->(p2)

// id(p1) > id(p2): SAME_AS는 대칭이므로
// 양방향 중복 비교·생성을 피한다
Example 9-7 · Step 2 — SIMILAR 생성 (Jaro–Winkler)Cypher
MATCH (p1:Person), (p2:Person)
WHERE NOT (p1)-[:SAME_AS]-(p2)
      AND p1.source <> p2.source
      AND id(p1) > id(p2)
      AND apoc.text.jaroWinklerDistance(
            p1.m_fullname, p2.m_fullname) < 0.2
CREATE (p1)-[:SIMILAR { sim_score : 1 -
  apoc.text.jaroWinklerDistance(
    p1.m_fullname, p2.m_fullname)}]->(p2)

// 거리 지표라서 부등호가 반대다.
// sim_score = 1 - 거리 → 0~1, 높을수록 유사.
// 점수 의미의 일관성이 비교·합성 가능성을 만든다
Example 9-8 · Step 3 — 강ID 불일치 삭제 + 9-9 · Step 4 — 보정Cypher
MATCH (p1:Person)-[sim:SIMILAR]->(p2:Person)
WHERE p1.ssn <> p2.ssn OR p1.passport_no <> p2.passport_no
DELETE sim

// Step 4 — m_yob(비식별)로 ±10% 보정
MATCH (p1:Person)-[sim:SIMILAR]->(p2:Person)
WITH sim, abs(p1.m_yob - p2.m_yob) AS yob_diff
SET sim.sim_score = sim.sim_score *
  CASE WHEN yob_diff > $yob_threshold
  THEN .9 ELSE 1.1 END
Example 9-10 · Step 5 — 임계 미달 삭제Cypher
MATCH (p1:Person)-[sim:SIMILAR]->(p2:Person)
WHERE sim.sim_score < $sim_score_threshold
DELETE sim

// 보정 함수는 사용 사례가 요구하는 만큼
// 정교해질 수 있다
Note — 단일 패스 vs 추적성

Step 3·4의 로직은 Step 2와 함께 구현할 수도 있고, 경우에 따라 데이터를 한 번만 훑어 성능이 개선된다. 단점은 각 단계의 효과에 대한 상세한 추적성(traceability)의 상실이다. 이 장에서는 명료성을 위해 단계를 분리했다.

사례 — Sprull 부녀(?)의 추가와 제거

Step 2 실행 후 만들어졌다가 Step 3에서 제거되는 SIMILAR도 있다 — Husein SprullHana Sprull이 그 예다. Step 2에서 이름 유사성으로 관계가 생성되지만, Step 3에서 사회보장번호 불일치 때문에 제거된다(그림 9-2). 이것이 강한 식별자가 약한 신호를 기각하는 안전장치다.

Master Entities

마스터 엔터티 — WCC가 골든 레코드를 빚는다

관련 엔터티 집합이 정해지고 관계가 그래프에 명시되면, 마지막 단계는 흔히 마스터 엔터티라 불리는 것의 영속 표현을 만드는 것이다. 본질적으로 이는 매칭 규칙 적용의 결과인 SAME_AS 또는 SIMILAR 관계로 연결된 노드 집합을 탐지하는 일이다. 한 집합의 모든 노드는 연결 요소(connected component)를 이루며 하나의 고유 엔터티와 동치다. 이것이 바로 WCC(Weakly Connected Components) 알고리즘의 일이다 — "약하게(weakly)"는 무방향 그래프에서 작동한다는 뜻인데, SAME_AS와 SIMILAR 모두 대칭이라 방향이 무의미한 이 문제의 목적에 딱 들어맞는다.

연결 요소 = 고유 엔터티 → PersonMaster (골든 레코드) golden_id = 0 SAME_AS SAME_AS SIMILAR sidneybernardy sydney j.bernardy sjbernardy golden_id = 1 cherishgosnall cherisegosnall cgosnall golden_id = 5 · 9 (단독) hanasprull huseinsprull SSN 불일치로 SIMILAR가 제거되어 별개 엔터티로 남는다 :PersonMaster {uid: 0} :PersonMaster {uid: 1} HAS_REFERENCE로 원본 연결 = 추적성
그림 9-1 · 9-3 · 매칭 규칙 적용의 그래프 결과 — 각 연결 요소가 마스터 엔터티를 정의하고, HAS_REFERENCE가 원본 레코드로의 추적성을 보존한다
Example 9-11 · 프로젝션 + 9-12 · WCC 스트림Cypher
CALL gds.graph.project(
  'identity-wcc',
  'Person',
  ['SAME_AS','SIMILAR']
)

CALL gds.wcc.stream('identity-wcc')
YIELD nodeId, componentId
WITH gds.util.asNode(nodeId) AS person,
     componentId AS golden_id
RETURN golden_id, person.m_fullname,
       person.passport_no, person.ssn
ORDER BY golden_id
Example 9-14 · 골든 레코드 생성 + 원본 연결Cypher
CALL gds.wcc.stream('identity-wcc')
YIELD nodeId, componentId
WITH gds.util.asNode(nodeId) AS person,
     componentId AS golden_id
MERGE (pg:PersonMaster { uid: golden_id })
    ON CREATE SET pg.fullname = person.m_fullname,
        pg.ssn = person.ssn,
        pg.passport_no = person.passport_no
    ON MATCH SET pg.ssn = coalesce(pg.ssn,person.ssn),
        pg.passport_no =
          coalesce(pg.passport_no,person.passport_no)
MERGE (pg)-[:HAS_REFERENCE]->(person)

스트림 결과(Example 9-13)는 연결 요소당 하나의 식별자를 낸다 — Bernardy의 세 변형이 golden_id 0, Gosnall의 세 변형이 1, Pedracci 두 변형이 4로 묶이고, Hana Sprull(5)·Ernestine Ouchterlony(7)·Husein Sprull(9)은 단독이다. 결과가 만족스러우면 영속화한다 — 노드에 요소 ID를 주석하는 gds.wcc.write를 써도 되지만, Example 9-14는 stream 출력으로 연결 요소의 맞춤 영속 표현을 만든다. 생성된 서브그래프 자체가 마스터 엔터티(골든 레코드)의 표현이고, coalesce로 소스들의 식별자를 채워 넣으며, 매치된 모든 레코드를 마스터에 연결하여 추적성(traceability)을 확보한다. 이후 Example 9-15처럼 마스터 엔터티를 질의해 소스별 상세를 모두 담은 집계 뷰를 만들고, 상호운용을 위해 Cypher에서 곧바로 JSON 직렬화(Example 9-16 — Bernardy 마스터와 ds1·ds2·ds3의 세 레퍼런스)를 산출할 수도 있다.

Note — 살아 있는 데이터와 델타

엔터티 해석이 적용되는 데이터 소스는 살아 있고 시간과 함께 변한다 — 과정은 일회성이 아니라 반복이다. 큰 데이터셋에서는 전체 새 버전 대신 델타(추가·제거분)를 정기적으로 받는 것이 일반적인데, 새 데이터 포인트의 추가(또는 제거)가 이전 매치에 영향을 주고 연결 요소를 새로 만들거나 바꿀 수 있어 일이 복잡해진다. 이를 수용하려면 델타의 제거 요소를 그래프에서 먼저 제거하는 예비 단계가 필요하다.

Note — 그래프 피처는 공짜로 따라온다

그래프의 정보로 해석 결과를 개선하는 것이 종종 도움이 된다 — 접근법을 관계나 이웃 노드의 속성으로 확장할 수 있고, 차수·중심성 같은 구조적 지표도 포함할 수 있다. 사실 그래프의 가장 강력한 점 하나는 이 모든 피처가 엔터티 해석에 자동으로 가용하다는 것이다.

Working with Unstructured Data

비정형 데이터 — 토큰의 이분 그래프와 Node Similarity

데이터에 강한 식별자가 없으면 약한 식별자와 비식별 피처를 더 정교하게 다뤄야 한다. 이들은 종종 텍스트 기술(記述)이고, 지금까지는 문자열 유사도 지표만 제안되었다. 그래프는 어떤 다른 선택지를 주는가? Amazon–Google 제품 카탈로그 데이터셋이 좋은 실험대다 — Amazon.com의 제품 기술 1,363건과 Google 제품 3,226건을 담고, 두 소스의 공통 속성은 제품명·제품 설명·제조사·가격이다.

준비 국면은 제품명을 소문자화하고 모든 비영숫자 문자를 제거한 뒤 (replace(tolower(p.name),"[^a-zA-Z0-9]", " ")) 단어로 쪼개 토큰화한다. 여기서는 split 함수(공백 구분)를 썼지만, NLTK·spaCy·Hugging Face 같은 자연어 패키지의 토크나이저를 써도 똑같이 된다. 토큰은 Word 노드가 되고 제품이 includes 관계로 잇는다 — 제품과 단어의 이분(bipartite) 그래프가 만들어지고, 일부 토큰은 제품들 사이에 공유된다(그림 9-4).

Example 9-17·9-18 · 제품 적재와 토큰화Cypher
LOAD CSV WITH HEADERS FROM "file:///amz.csv" AS row
CREATE (p:Product { sid: row.id })
SET p.source = "AMZ", p += properties(row) ;
-- ggl.csv도 동일 (source = "GGL")

CREATE INDEX FOR (w:Word) ON w.txt ;

MATCH (p:Product { source : "GGL" })
UNWIND [x in split(apoc.text.replace(
  tolower(p.name),"[^a-zA-Z0-9]", " ")," ")
  WHERE x <> "" ] AS txt
MERGE (w:Word { txt: txt })
MERGE (p)-[:includes]->(w) ;
-- AMZ는 p.title 기준으로 동일
Example 9-19·9-20·9-22 · 프로젝션·유사도·SIMILARCypher
CALL gds.graph.project(
    'identity-sim',
    ['Product', 'Word'],
    ['includes']
);

CALL gds.nodeSimilarity.stream('identity-sim',
    { similarityCutoff: 0.8 })
YIELD node1, node2, similarity
WITH similarity, gds.util.asNode(node1) AS node1,
     gds.util.asNode(node2) AS node2
WHERE node1.source = "GGL" AND node2.source = "AMZ"
MERGE (node1)-[:SIMILAR { sim_score : similarity }]
      ->(node2)
// 기본 지표는 Jaccard.
// similarityMetric: 'OVERLAP'로 교체 가능
// (Szymkiewicz–Simpson 계수)

Node Similarity 알고리즘은 노드들이 연결된 이웃에 기반해 비교한다 — 두 노드는 같은 이웃을 많이 공유할수록 유사하다고 간주되며, 여기서는 제품명의 단어를 공유한다는 뜻이다. 이분 그래프 프로젝션의 구현은 고도로 메모리 최적화되어 수십억 그래프 요소를 상용 하드웨어에서 성능 좋게 처리할 수 있다. similarityCutoff 0.8로 수용 불가한 낮은 유사도를 폐기한다.

tk_simstr_simProd1 (GGL)Prod2 (AMZ)
0.80.7969allume internet cleanup 3.0internet cleanup 3.0
0.80.7831marware project x project management softwareproject x project management software
0.80.7703allume morpheus photo animation suitemorpheus photo animation suite
0.80.7627mobile media converter (pc) pinnaclepinnacle mobile media converter
0.80.7593extensis suitcase fusion 1u boxsuitcase fusion 1u box
0.80.7423sp linux we 50 lic/cd 3.0chp sp linux we 50 lic/cd 3.0c (t3586a)
0.80.7406serverlock manager - 100 serverswatchguard serverlock manager (100 servers)
0.80.7234print shop deluxe 21broderbund print shop 21 deluxe
0.80.6965apple apple mac os x server 10 4 7 10 clientmac os x server v10.4.7 10-client
Note — 토큰 기반이 문자열 유사도보다 강건하다

비교를 위해 Jaro–Winkler 문자열 유사도(str_sim) 열을 추가했다. 마지막 행이 요점이다 — 제품명 포맷 변경처럼 무해한 차이(apple apple mac os x server 10 4 7 10 client vs mac os x server v10.4.7 10-client)가 문자열 유사도에는 큰 타격(0.6965)을 주어, 높은 임계값을 쓰면 이 매치를 놓친다. 토큰 기반 접근은 같은 쌍에 0.8을 준다. 이후 SIMILAR 관계를 만들고(제품명은 약한 식별자다), 알고리즘이 계속 그래프를 구축하면 연결 요소가 매칭 엔터티를 산출한다 — 정형 데이터와 같은 길이다.

Case Study

사례 연구 — Meredith Corporation 아이덴티티 그래프

Meredith Corporation은 연 매출 32억 달러의 미디어 복합기업이었다. Parents, People, Real Simple, Coastal Living 등 30개 이상의 톱 소비자 브랜드를 보유했고, 닷컴·앱·웹사이트·팟캐스트·비디오에 걸쳐 월 1억 8천만 사용자 이상에 도달했다. Meredith는 하루 내내 사용자에게 딱 맞는 개인화 콘텐츠를 주고자 했다 — 그러려면 사용자를 정말로 알아야 하는데, 대부분의 사람은 로그인하지 않는다.

Meredith는 장치에 떨어지는 고유 쿠키로 익명 사용자를 식별했다. 그러나 쿠키 손실, 다양한 장치, 기본값으로 쿠키를 차단하는 브라우저 때문에 360도 뷰 확보는 어려웠고, 작동하는 쿠키조차 수명이 짧다. 그래프 질의는 그래프가 아무리 커도 빠른 답을 주지만, 같은 질의를 반복해 사용자 프로필을 쌓고 있다면 더 나은 길이 있다 — 그래프 전체에 그래프 알고리즘을 돌리는 것이다. Meredith 데이터 과학 팀은 더 큰 그래프 안의 고유 서브그래프(연결 요소)를 식별하기 위해 WCC 알고리즘을 선택했다.

프로덕션 규모와 성과 — 쿠키에서 프로필로 4.4 TB 20개월 1st+3rd파티 데이터 300억 노드 속성 670억 · 관계 350억 3.5억 → 1.63억 "고유 개인" 프로필의 통합 +20~30% 고객 이해도 향상 터치포인트 지속 쿠키 14일 프로필 241일 평균 방문 쿠키당 4회 프로필당 23.8회
Meredith Identity Graph · WCC 기반 프로필 통합의 규모와 성과 — 관심사·선호의 고해상 뷰가 더 강한 모델과 재방문의 선순환을 만들었다

고유 개인으로 간주되었을 3억 5천만 프로필이 서로 다른 관심·패턴을 가진 것처럼 보였지만, 실제로는 1억 6,300만 개의 더 풍부하고 정확한 프로필로 통합되었다. 사용자 관심·선호의 고해상 뷰는 더 강한 모델의 연료가 되었고, 더 적합한 콘텐츠와 시간이 갈수록 더 많은 재방문 사용자로 이어졌다 — 선순환이다. Meredith의 말이다: "개별 쿠키만 보는 대신 시간에 걸쳐 데이터가 어떻게 연결되는지 봄으로써 고객에 대한 이해를 기본적으로 20~30% 늘렸다. 어둠 속에서 광고하는 대신 이제 고객을 더 잘 이해하며, 이는 상당한 수익 증가와 더 잘 서비스받는 소비자로 번역된다."

Summary

요약 — 약한 식별자들을 모아 강한 식별자로

아이덴티티는 지식 그래프를 현실 세계에 연결하는 핵심 기둥이다. 이 장에서 데이터의 강한 식별자와 약한 식별자를 배웠고, 지식 그래프와 그래프 알고리즘으로 약한 식별자들의 집합이 강한 식별자로 집계될 수 있음을 발견했다. 이 기법들로 제멋대로인 데이터셋조차 다뤄서 진정으로 그 데이터를 마스터할 수 있다 — 연결 요소로든, 노드 유사도로든, 맞춤 그래프 매칭으로든, 필요한 도구는 손안에 있다.

1

같은 것인가, 다른 것인가. Jane Coleman/Downe처럼 강한 식별자가 있어도 데이터 전반에 일관되지 않을 수 있다. 문제는 데이터 통합, 익명 활동, 의도적·사기적 중복의 세 시나리오에서 나타나며, 해법은 준비 → 매칭 → 마스터 영속화의 3막이다.

2

준비 = 조화. 최소 공통분모로 정규화(m_yob)하고 정준 표현을 만들며(m_fullname), source 속성으로 소스별 로직을 분기한다. n² 비교는 블로킹 키로 길들인다. 그래프 밖(pandas/SQL)에서 해도 되지만 그래프 피처만은 그래프가 필요하다.

3

매칭 5단계. SAME_AS(강ID) → SIMILAR(약ID, Jaro–Winkler, sim_score=1-거리) → 강ID 불일치 폐기(Sprull 사례) → 비식별 피처 보정(±10%) → 임계 미달 폐기. 점수 의미의 일관성(0~1, 높을수록 유사)이 비교·합성을 가능케 한다.

4

WCC가 골든 레코드를 만든다. SAME_AS·SIMILAR 모두 대칭이라 무방향 연결 요소가 고유 엔터티다. PersonMaster에 coalesce로 식별자를 모으고 HAS_REFERENCE로 추적성을 보존한다. 살아 있는 데이터는 델타 반복을, 그래프는 차수·중심성 피처를 공짜로 준다.

5

비정형에는 토큰 이분 그래프. 제품명을 Word 노드로 토큰화하고 Node Similarity(Jaccard/overlap)를 돌리면, 포맷 변경에 취약한 문자열 유사도보다 강건하다. Meredith는 이 계열의 WCC로 3.5억 프로필을 1.63억으로 통합해 고객 이해를 20~30% 높였다.

Next — 10장 예고

마스터링으로 데이터 품질이 크게 개선되었으니, 이제 대규모 패턴 매칭 그래프로 이동한다 — 사기를 멈추고 더 나은 팀을 꾸리는 패턴 탐지 지식 그래프(10장, Pattern Detection Knowledge Graphs)다.