BigQuery에서 100만 행을 10분 이내에 Fuzzy-Match 하는 방법
Source: Dev.to
Duplicate records rarely look like a priority at first — until they start breaking reporting, outreach, or reconciliation workflows.
중복 레코드는 처음에는 우선순위처럼 보이지 않는 경우가 많습니다 — 보고서, 연락, 혹은 조정 워크플로우를 방해하기 시작할 때까지.
From slightly different versions of “Acme Inc” in a CRM to inconsistent supplier names across systems or messy post‑merger datasets, fuzzy matching becomes essential whenever identical strings are no longer a reliable signal of the same real‑world entity.
CRM에서 약간씩 다른 형태의 “Acme Inc”부터 시스템 간 일관되지 않은 공급업체 이름, 혹은 합병 후 뒤섞인 데이터셋까지, 동일한 문자열이 더 이상 동일한 실제 엔터티를 신뢰할 수 있는 신호가 아닐 때마다 퍼지 매칭은 필수적이 됩니다.
스케일링 장벽: 왜 웨어하우스‑네이티브 퍼지 매칭이 대규모에서 깨지는가
퍼지 매칭은 1,000행 샘플에서는 간단해 보입니다. 하지만 실제 규모에서는 수학이 달라집니다. 모든 대 모든 비교를 단순히 수행하면 O(N²) 로 증가합니다. 100 k+ 행에 도달하면 비교 공간이 폭발적으로 커지고, 로컬 스크립트나 웨어하우스‑네이티브 접근 방식은 느리거나 비용이 많이 들거나 취약해집니다.
실제로 팀들은 실제 복잡성을 깨닫기 전에 보통 여러 접근 방식을 순차적으로 시도합니다:
- 웨어하우스 유사도 함수(예: 편집 거리 또는 토큰 유사도)부터 시작합니다.
- 성능 한계에 부딪힙니다.
- 빠른 파이썬 스크립트로 전환하지만, 메모리 사용량, 블로킹 전략 설계, 데이터 정리와 관련된 새로운 병목 현상을 발견하게 됩니다.
그 시점에서 단순해 보였던 작업이 영구적인 매칭 파이프라인으로 변합니다:
- 블로킹 및 후보 생성 로직
- 문자열 정규화 및 접미사 정리
- 임계값 튜닝 및 평가 루프
- 병렬 처리 및 메모리 관리
빠른 중복 제거 작업으로 시작한 것이 조용히 지속적인 엔지니어링 오버헤드가 됩니다.
해결책: 프로덕션 퍼지‑매칭 엔진 호출
Similarity API는 고성능 중복 제거 및 조정을 위해 설계된 호스팅 인프라 서비스입니다.
자신만의 매칭 파이프라인을 구축하고 유지하는 대신, 잡음이 많은 실제 데이터와 대규모 워크로드에 최적화된 전용 매칭 엔진에 데이터셋을 전송합니다.
기술적 우위: 대규모 적응형 전처리
실제 워크플로에서는 퍼지 매칭 품질이 유사도 메트릭 자체만큼이나 데이터‑준비 전략에 의해 결정됩니다.
로컬 구현에서는 팀이 맞춤형 정규화 규칙, 접미사 정리 로직, 토큰 순서 휴리스틱, 차단 전략 등을 설계해야 하며, 각 요소는 데이터셋이 진화함에 따라 조정되어야 합니다.
Similarity API는 이러한 단계를 매칭 엔진에 직접 내장합니다:
- Dataset‑aware normalization – 전처리는 문자열 길이, 토큰 밀도, 노이즈 패턴에 따라 동적으로 적용됩니다.
- Scale‑optimized cleaning pipeline – 전처리는 분산 매칭 흐름의 일부로 실행되어 1 M+ 행에서도 정리 단계가 병목이 되는 것을 방지합니다.
- Configuration instead of custom code – 매칭 동작은
similarity_threshold,use_token_sort,remove_punctuation와 같은 매개변수로 제어되며, 맞춤 스크립트를 사용할 필요가 없습니다.
이 아키텍처를 통해 팀은 취약한 전처리 파이프라인을 유지보수하는 대신 매칭 검토와 하위 데이터 작업에 집중할 수 있습니다.
BigQuery 노트북
이 가이드는 BigQuery 노트북 환경(BigQuery에 통합된 Colab Enterprise) 내에서 실행되도록 설계되었습니다.
이 노트북을 사용하면 다음을 할 수 있습니다:
- BigQuery에서 프로덕션 테이블을 직접 쿼리합니다.
- 인프라를 프로비저닝하지 않고 Python 데이터 워크플로를 실행합니다.
- 무거운 연산 작업을 위해 외부 API를 호출합니다.
- 결과를 BigQuery 테이블에 다시 씁니다.
실제로 이는 대규모 퍼지 매칭 워크플로에 이상적인 환경을 제공합니다. 데이터는 웨어하우스에 머무르고, 연산 집약적인 매칭은 확장 가능한 외부 서비스에서 수행됩니다.
노트북 셀을 실행하기 전에 Similarity API 프로덕션 토큰이 필요합니다.
토큰은 Similarity API 대시보드에서 생성할 수 있습니다. 토큰은 요청 시 표준 Bearer 인증 헤더로 전달됩니다.
실제로 반환되는 내용
입력 예시
["Acme Inc", "ACME Incorporated", "Beta LLC", "Beta Limited"]
출력 예시
[
[0, 1, 0.94],
[2, 3, 0.91]
]
각 결과는 동일한 실제 엔터티를 나타낼 가능성이 있는 두 행과 유사도 점수를 나타냅니다.
기본적으로 API는 인덱스 쌍을 반환하며, 이를 사용해 BigQuery 테이블에 빠르게 조인하여 검토하거나 병합 워크플로에 활용할 수 있습니다.
출력 형식은 구성 가능하며, 문자열 쌍, 중복 클러스터 그룹, 또는 정리 전략에 따라 완전 중복 제거된 레코드 목록 등을 반환하도록 설정할 수 있습니다.
Notebook example
다음 코드 스니펫은:
- BigQuery에서 직접 데이터셋을 읽고,
- 회사 이름을 Similarity API에 전송하고,
- 중복 인덱스 쌍을 반환합니다.
from google.cloud import bigquery
import requests
import pandas as pd
# ---- CONFIG ----
PROJECT_ID = "YOUR_PROJECT_ID"
DATASET = "YOUR_DATASET"
TABLE = "YOUR_TABLE"
COLUMN = "company_name"
API_KEY = "YOUR_PRODUCTION_KEY"
API_URL = "https://api.similarity-api.com/dedupe"
# ---- LOAD DATA FROM BIGQUERY ----
client = bigquery.Client(project=PROJECT_ID)
query = f"""
SELECT {COLUMN}
FROM `{PROJECT_ID}.{DATASET}.{TABLE}`
WHERE {COLUMN} IS NOT NULL
"""
strings = (
client.query(query)
.result()
.to_dataframe()[COLUMN]
.astype(str)
.tolist()
)
print(f"Loaded {len(strings):,} rows from BigQuery")
# ---- CALL SIMILARITY API ----
payload = {
"data": strings,
"config": {
"similarity_threshold": 0.65,
"remove_punctuation": True,
"to_lowercase": True,
"use_token_sort": False,
"output_format": "index_pairs",
},
}
response = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json=payload,
timeout=3600,
)
response.raise_for_status()
results = response.json().get("response_data", [])
print(f"Workflow complete: found {len(results):,} duplicate pairs")
# ---- OPTIONAL: SAVE RESULTS BACK TO BIGQUERY ----
if results:
dup_df = pd.DataFrame(results, columns=["idx_1", "idx_2"])
table_id = f"{PROJECT_ID}.{DATASET}.dedupe_results"
job = client.load_table_from_dataframe(dup_df, table_id)
job.result()
print(f"Saved results to {table_id}")
The honest “under 10‑minute” claim
Here is how the timing works in practice:
- ~7 minutes – benchmarked processing time for a 1 M‑row dataset in the Similarity API (varies with string length)
- ~2 minutes – copy‑paste the notebook cell, run the query, and start the job
No blocking strategy design. No distributed‑compute tuning. No regex cleanup scripts.
From prototype to production
노트북은 매칭 품질을 검증하고 일회성 조정 작업을 실행하는 데 이상적입니다.
프로덕션 환경에서는 동일한 API 호출 패턴을 다음에 삽입할 수 있습니다:
- 예약된 BigQuery 워크플로
- Airflow 또는 Prefect 파이프라인
- 백엔드 데이터 서비스
- 로우코드 자동화 도구
인터페이스가 표준 HTTP이기 때문에 매칭 엔진은 스택 전반에 걸쳐 재사용 가능한 데이터 품질 구성 요소가 됩니다.
최종 말
대규모에서는 퍼지 매칭이 단순히 문자열‑유사도 문제를 넘어 인프라 문제로 변합니다.
Similarity API는 엔지니어링 시간을 분석 및 제품 로직에 투자하고 싶어하는 팀을 위해 구축되었습니다 — 맞춤형 중복 제거 파이프라인을 유지보수하는 데가 아니라.
수 주에 걸친 파이프라인 작업 대신, 노트북 셀을 실행하여 바로 깨끗한 데이터를 검토하고 활용할 수 있습니다.