From 535704707bebe14c39a1f71d9edc67b6c4211159 Mon Sep 17 00:00:00 2001 From: htlee Date: Thu, 16 Apr 2026 10:13:35 +0900 Subject: [PATCH] =?UTF-8?q?fix(prediction):=20FUZZY=20=EC=A0=95=EA=B7=9C?= =?UTF-8?q?=ED=99=94=EB=A5=BC=20=EA=B3=B5=EB=B0=B1/=EB=8C=80=EC=86=8C?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EB=A7=8C=EC=9C=BC=EB=A1=9C=20=EC=B6=95?= =?UTF-8?q?=EC=86=8C=20+=20name=5Fen=20=EC=A0=84=EC=9A=A9=20(A-2=20?= =?UTF-8?q?=ED=9B=84=EC=86=8D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 버그 원인: 초기 정규화가 선박번호(suffix)까지 제거 → '浙岭渔20865' → '浙岭渔' 로 축약 → 동명이 수십 개 발생 → len(unassigned)>1 조건에 전부 탈락 → FUZZY=0건. 중국/한국 어선명은 업체명+선박번호가 고유 식별자이므로 숫자 자체는 보존해야 함. 정규화는 공백/구두점/대소문자/'NO.' 마커만 통일: 'ZHE LING YU 20865' ↔ 'zhelingyu20865' ↔ 'ZHE-LING-YU-20865' 모두 일치 FUZZY 매칭 key 는 name_en 만 등록 (AIS 보고 이름이 영문이 주류). --- prediction/fleet_tracker.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/prediction/fleet_tracker.py b/prediction/fleet_tracker.py index 7efed02..02f97bc 100644 --- a/prediction/fleet_tracker.py +++ b/prediction/fleet_tracker.py @@ -23,16 +23,11 @@ GEAR_IDENTITY_LOG = qualified_table('gear_identity_log') GEAR_CORRELATION_SCORES = qualified_table('gear_correlation_scores') FLEET_TRACKING_SNAPSHOT = qualified_table('fleet_tracking_snapshot') -# 선박명 정규화: 공백/구두점 제거, 선박번호 suffix 제거, upper() 통일. -# AIS 이름과 fishery_permit_cn 이름 간 suffix/공백 차이로 NAME_EXACT 매칭률 8.7% → 정규화 기반 매칭으로 회복. -_NAME_STRIP_SUFFIX = re.compile( - r'(?:' - r'[\s_]*(?:NO\.?|#|#)?[\s_]*\d+\s*(?:호|號|号)?' # 123 / No.123 / #123 / 123호 / 12号 - r'|[\s_]*(?:호|號|号)' # 말미 호/號/号 단독 - r')\s*$', - re.IGNORECASE, -) -_NAME_STRIP_CHARS = re.compile(r'[\s\-_./,()\[\]·•\u3000]+') +# 선박명 정규화 (중국/한국 어선 식별자 보존): +# - 중국 어선명 = 업체명(浙岭渔) + 선박번호(20865) 로 고유 식별. 번호 제거 시 동명이 수십 개 발생 → 번호 유지 +# - 통일 대상: 공백/구두점, 대소문자, NO./No. prefix +_NAME_STRIP_CHARS = re.compile(r'[\s\-_./,()\[\]·•\u3000##]+') +_NAME_STRIP_PREFIX_NUMBER_MARKER = re.compile(r'\bNO\.?\s*', re.IGNORECASE) _PERIOD_RANGE_PATTERN = re.compile( @@ -65,13 +60,13 @@ def _normalize_vessel_name(name: Optional[str]) -> str: """선박명을 매칭용으로 정규화. 1. upper() + strip - 2. 말미 선박번호 패턴 제거 (호/號/号, No.N, #N, 공백숫자) - 3. 남은 공백/구두점 제거 + 2. 'No.123' / 'NO 123' 의 번호 마커만 제거 (숫자 자체는 고유 식별자로 유지) + 3. 공백/구두점/중간점/전각공백/#/# 제거 """ if not name: return '' s = name.strip().upper() - s = _NAME_STRIP_SUFFIX.sub('', s) + s = _NAME_STRIP_PREFIX_NUMBER_MARKER.sub('', s) s = _NAME_STRIP_CHARS.sub('', s) return s @@ -128,11 +123,9 @@ class FleetTracker: self._vessels[vid] = v if r[3]: self._name_cn_map[r[3]] = vid - key_cn = _normalize_vessel_name(r[3]) - if key_cn: - self._name_fuzzy_map.setdefault(key_cn, []).append(vid) if r[4]: self._name_en_map[r[4].lower().strip()] = vid + # FUZZY 매칭은 name_en 만 대상 (AIS 가 보고하는 이름은 영문이 주류) key_en = _normalize_vessel_name(r[4]) if key_en: self._name_fuzzy_map.setdefault(key_en, []).append(vid)