diff --git a/data/nationwide-pension-keywords.json b/data/nationwide-pension-keywords.json index db57cfa..deaf5f2 100644 --- a/data/nationwide-pension-keywords.json +++ b/data/nationwide-pension-keywords.json @@ -3,7 +3,7 @@ "locale": "ko-KR", "generatedBy": "region master × search-pattern expansion (region-type aware)", "regionCount": 54, - "count": 7138, + "count": 7129, "items": [ { "sido": "경기", @@ -989,18 +989,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경기", - "region": "가평", - "regionKey": "kr.gyeonggi.gapyeong", - "regionType": "호수·산간", - "keyword": "가평 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경기", "region": "가평", @@ -2561,18 +2549,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경기", - "region": "양평", - "regionKey": "kr.gyeonggi.yangpyeong", - "regionType": "강변·산간", - "keyword": "양평 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경기", "region": "양평", @@ -4109,18 +4085,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경기", - "region": "포천", - "regionKey": "kr.gyeonggi.pocheon", - "regionType": "호수·산간", - "keyword": "포천 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경기", "region": "포천", @@ -7205,18 +7169,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "인천", - "region": "강화", - "regionKey": "kr.incheon.ganghwa", - "regionType": "해변·산간", - "keyword": "강화 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "인천", "region": "강화", @@ -12017,18 +11969,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "강원", - "region": "홍천", - "regionKey": "kr.gangwon.hongcheon", - "regionType": "산간·계곡", - "keyword": "홍천 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "강원", "region": "홍천", @@ -12053,6 +11993,42 @@ "tier": "보조", "relevance": 0.76 }, + { + "sido": "강원", + "region": "홍천", + "regionKey": "kr.gangwon.hongcheon", + "regionType": "산간·계곡", + "keyword": "홍천 스키 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "홍천", + "regionKey": "kr.gangwon.hongcheon", + "regionType": "산간·계곡", + "keyword": "홍천 스키장 근처 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "홍천", + "regionKey": "kr.gangwon.hongcheon", + "regionType": "산간·계곡", + "keyword": "홍천 보드 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, { "sido": "강원", "region": "홍천", @@ -13541,18 +13517,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "강원", - "region": "인제", - "regionKey": "kr.gangwon.inje", - "regionType": "산간·계곡", - "keyword": "인제 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "강원", "region": "인제", @@ -15029,6 +14993,18 @@ "tier": "보조", "relevance": 0.76 }, + { + "sido": "강원", + "region": "평창", + "regionKey": "kr.gangwon.pyeongchang", + "regionType": "산간", + "keyword": "평창 눈꽃 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, { "sido": "강원", "region": "평창", @@ -15046,7 +15022,19 @@ "region": "평창", "regionKey": "kr.gangwon.pyeongchang", "regionType": "산간", - "keyword": "평창 눈꽃 펜션", + "keyword": "평창 스키장 근처 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "평창", + "regionKey": "kr.gangwon.pyeongchang", + "regionType": "산간", + "keyword": "평창 보드 펜션", "kind": "keyword", "intent": "local", "category": "시즌", @@ -16589,18 +16577,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "강원", - "region": "정선", - "regionKey": "kr.gangwon.jeongseon", - "regionType": "산간·계곡", - "keyword": "정선 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "강원", "region": "정선", @@ -16625,6 +16601,42 @@ "tier": "보조", "relevance": 0.76 }, + { + "sido": "강원", + "region": "정선", + "regionKey": "kr.gangwon.jeongseon", + "regionType": "산간·계곡", + "keyword": "정선 스키 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "정선", + "regionKey": "kr.gangwon.jeongseon", + "regionType": "산간·계곡", + "keyword": "정선 스키장 근처 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "정선", + "regionKey": "kr.gangwon.jeongseon", + "regionType": "산간·계곡", + "keyword": "정선 보드 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, { "sido": "강원", "region": "정선", @@ -19829,18 +19841,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "강원", - "region": "속초", - "regionKey": "kr.gangwon.sokcho", - "regionType": "해변·산간", - "keyword": "속초 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "강원", "region": "속초", @@ -27521,6 +27521,18 @@ "tier": "보조", "relevance": 0.76 }, + { + "sido": "강원", + "region": "태백", + "regionKey": "kr.gangwon.taebaek", + "regionType": "산간", + "keyword": "태백 눈꽃 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, { "sido": "강원", "region": "태백", @@ -27538,7 +27550,19 @@ "region": "태백", "regionKey": "kr.gangwon.taebaek", "regionType": "산간", - "keyword": "태백 눈꽃 펜션", + "keyword": "태백 스키장 근처 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "강원", + "region": "태백", + "regionKey": "kr.gangwon.taebaek", + "regionType": "산간", + "keyword": "태백 보드 펜션", "kind": "keyword", "intent": "local", "category": "시즌", @@ -29033,18 +29057,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "충북", - "region": "단양", - "regionKey": "kr.chungbuk.danyang", - "regionType": "산간·강변", - "keyword": "단양 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "충북", "region": "단양", @@ -30617,18 +30629,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "충북", - "region": "제천", - "regionKey": "kr.chungbuk.jecheon", - "regionType": "호수·산간", - "keyword": "제천 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "충북", "region": "제천", @@ -32165,18 +32165,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "충북", - "region": "충주", - "regionKey": "kr.chungbuk.chungju", - "regionType": "호수·산간", - "keyword": "충주 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "충북", "region": "충주", @@ -33677,18 +33665,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "충북", - "region": "괴산", - "regionKey": "kr.chungbuk.goesan", - "regionType": "산간·계곡", - "keyword": "괴산 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "충북", "region": "괴산", @@ -45041,18 +45017,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "전북", - "region": "변산", - "regionKey": "kr.jeonbuk.buan", - "regionType": "해변·산간", - "keyword": "변산 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "전북", "region": "변산", @@ -48041,18 +48005,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "전북", - "region": "무주", - "regionKey": "kr.jeonbuk.muju", - "regionType": "산간·계곡", - "keyword": "무주 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "전북", "region": "무주", @@ -48077,6 +48029,42 @@ "tier": "보조", "relevance": 0.76 }, + { + "sido": "전북", + "region": "무주", + "regionKey": "kr.jeonbuk.muju", + "regionType": "산간·계곡", + "keyword": "무주 스키 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "전북", + "region": "무주", + "regionKey": "kr.jeonbuk.muju", + "regionType": "산간·계곡", + "keyword": "무주 스키장 근처 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, + { + "sido": "전북", + "region": "무주", + "regionKey": "kr.jeonbuk.muju", + "regionType": "산간·계곡", + "keyword": "무주 보드 펜션", + "kind": "keyword", + "intent": "local", + "category": "시즌", + "tier": "보조", + "relevance": 0.76 + }, { "sido": "전북", "region": "무주", @@ -49625,18 +49613,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "전북", - "region": "남원", - "regionKey": "kr.jeonbuk.namwon", - "regionType": "도심·산간", - "keyword": "남원 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "전북", "region": "남원", @@ -55745,18 +55721,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "전남", - "region": "구례", - "regionKey": "kr.jeonnam.gurye", - "regionType": "산간·계곡", - "keyword": "구례 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "전남", "region": "구례", @@ -57389,18 +57353,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "전남", - "region": "해남", - "regionKey": "kr.jeonnam.haenam", - "regionType": "해변·산간", - "keyword": "해남 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "전남", "region": "해남", @@ -68237,18 +68189,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경북", - "region": "울진", - "regionKey": "kr.gyeongbuk.uljin", - "regionType": "해변·산간", - "keyword": "울진 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경북", "region": "울진", @@ -69773,18 +69713,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경북", - "region": "문경", - "regionKey": "kr.gyeongbuk.mungyeong", - "regionType": "산간·계곡", - "keyword": "문경 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경북", "region": "문경", @@ -76025,18 +75953,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경남", - "region": "하동", - "regionKey": "kr.gyeongnam.hadong", - "regionType": "산간·강변", - "keyword": "하동 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경남", "region": "하동", @@ -79085,18 +79001,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "경남", - "region": "산청", - "regionKey": "kr.gyeongnam.sancheong", - "regionType": "산간·계곡", - "keyword": "산청 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "경남", "region": "산청", @@ -83861,18 +83765,6 @@ "tier": "보조", "relevance": 0.76 }, - { - "sido": "제주", - "region": "서귀포", - "regionKey": "kr.jeju.seogwipo", - "regionType": "해변·산간", - "keyword": "서귀포 스키 펜션", - "kind": "keyword", - "intent": "local", - "category": "시즌", - "tier": "보조", - "relevance": 0.76 - }, { "sido": "제주", "region": "서귀포", @@ -84476,7 +84368,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 펜션", "kind": "keyword", @@ -84488,7 +84380,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 숙소", "kind": "keyword", @@ -84500,7 +84392,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 독채펜션", "kind": "keyword", @@ -84512,7 +84404,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 풀빌라", "kind": "keyword", @@ -84524,7 +84416,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 애견펜션", "kind": "keyword", @@ -84536,7 +84428,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 펜션 추천", "kind": "keyword", @@ -84548,7 +84440,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 펜션 예약", "kind": "keyword", @@ -84560,7 +84452,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 펜션 가격", "kind": "keyword", @@ -84572,7 +84464,7 @@ { "sido": "경기", "region": "경기", - "regionKey": "rollup.경기", + "regionKey": "kr.gyeonggi", "regionType": "", "keyword": "경기 펜션 후기", "kind": "keyword", @@ -84584,7 +84476,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 펜션", "kind": "keyword", @@ -84596,7 +84488,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 숙소", "kind": "keyword", @@ -84608,7 +84500,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 독채펜션", "kind": "keyword", @@ -84620,7 +84512,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 풀빌라", "kind": "keyword", @@ -84632,7 +84524,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 애견펜션", "kind": "keyword", @@ -84644,7 +84536,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 펜션 추천", "kind": "keyword", @@ -84656,7 +84548,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 펜션 예약", "kind": "keyword", @@ -84668,7 +84560,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 펜션 가격", "kind": "keyword", @@ -84680,7 +84572,7 @@ { "sido": "인천", "region": "인천", - "regionKey": "rollup.인천", + "regionKey": "kr.incheon", "regionType": "", "keyword": "인천 펜션 후기", "kind": "keyword", @@ -84692,7 +84584,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 펜션", "kind": "keyword", @@ -84704,7 +84596,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 숙소", "kind": "keyword", @@ -84716,7 +84608,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 독채펜션", "kind": "keyword", @@ -84728,7 +84620,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 풀빌라", "kind": "keyword", @@ -84740,7 +84632,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 애견펜션", "kind": "keyword", @@ -84752,7 +84644,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 펜션 추천", "kind": "keyword", @@ -84764,7 +84656,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 펜션 예약", "kind": "keyword", @@ -84776,7 +84668,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 펜션 가격", "kind": "keyword", @@ -84788,7 +84680,7 @@ { "sido": "강원", "region": "강원", - "regionKey": "rollup.강원", + "regionKey": "kr.gangwon", "regionType": "", "keyword": "강원 펜션 후기", "kind": "keyword", @@ -84800,7 +84692,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 펜션", "kind": "keyword", @@ -84812,7 +84704,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 숙소", "kind": "keyword", @@ -84824,7 +84716,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 독채펜션", "kind": "keyword", @@ -84836,7 +84728,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 풀빌라", "kind": "keyword", @@ -84848,7 +84740,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 애견펜션", "kind": "keyword", @@ -84860,7 +84752,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 펜션 추천", "kind": "keyword", @@ -84872,7 +84764,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 펜션 예약", "kind": "keyword", @@ -84884,7 +84776,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 펜션 가격", "kind": "keyword", @@ -84896,7 +84788,7 @@ { "sido": "충북", "region": "충북", - "regionKey": "rollup.충북", + "regionKey": "kr.chungbuk", "regionType": "", "keyword": "충북 펜션 후기", "kind": "keyword", @@ -84908,7 +84800,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 펜션", "kind": "keyword", @@ -84920,7 +84812,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 숙소", "kind": "keyword", @@ -84932,7 +84824,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 독채펜션", "kind": "keyword", @@ -84944,7 +84836,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 풀빌라", "kind": "keyword", @@ -84956,7 +84848,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 애견펜션", "kind": "keyword", @@ -84968,7 +84860,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 펜션 추천", "kind": "keyword", @@ -84980,7 +84872,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 펜션 예약", "kind": "keyword", @@ -84992,7 +84884,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 펜션 가격", "kind": "keyword", @@ -85004,7 +84896,7 @@ { "sido": "충남", "region": "충남", - "regionKey": "rollup.충남", + "regionKey": "kr.chungnam", "regionType": "", "keyword": "충남 펜션 후기", "kind": "keyword", @@ -85016,7 +84908,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 펜션", "kind": "keyword", @@ -85028,7 +84920,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 숙소", "kind": "keyword", @@ -85040,7 +84932,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 독채펜션", "kind": "keyword", @@ -85052,7 +84944,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 풀빌라", "kind": "keyword", @@ -85064,7 +84956,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 애견펜션", "kind": "keyword", @@ -85076,7 +84968,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 펜션 추천", "kind": "keyword", @@ -85088,7 +84980,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 펜션 예약", "kind": "keyword", @@ -85100,7 +84992,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 펜션 가격", "kind": "keyword", @@ -85112,7 +85004,7 @@ { "sido": "전북", "region": "전북", - "regionKey": "rollup.전북", + "regionKey": "kr.jeonbuk", "regionType": "", "keyword": "전북 펜션 후기", "kind": "keyword", @@ -85124,7 +85016,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 펜션", "kind": "keyword", @@ -85136,7 +85028,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 숙소", "kind": "keyword", @@ -85148,7 +85040,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 독채펜션", "kind": "keyword", @@ -85160,7 +85052,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 풀빌라", "kind": "keyword", @@ -85172,7 +85064,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 애견펜션", "kind": "keyword", @@ -85184,7 +85076,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 펜션 추천", "kind": "keyword", @@ -85196,7 +85088,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 펜션 예약", "kind": "keyword", @@ -85208,7 +85100,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 펜션 가격", "kind": "keyword", @@ -85220,7 +85112,7 @@ { "sido": "전남", "region": "전남", - "regionKey": "rollup.전남", + "regionKey": "kr.jeonnam", "regionType": "", "keyword": "전남 펜션 후기", "kind": "keyword", @@ -85232,7 +85124,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 펜션", "kind": "keyword", @@ -85244,7 +85136,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 숙소", "kind": "keyword", @@ -85256,7 +85148,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 독채펜션", "kind": "keyword", @@ -85268,7 +85160,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 풀빌라", "kind": "keyword", @@ -85280,7 +85172,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 애견펜션", "kind": "keyword", @@ -85292,7 +85184,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 펜션 추천", "kind": "keyword", @@ -85304,7 +85196,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 펜션 예약", "kind": "keyword", @@ -85316,7 +85208,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 펜션 가격", "kind": "keyword", @@ -85328,7 +85220,7 @@ { "sido": "경북", "region": "경북", - "regionKey": "rollup.경북", + "regionKey": "kr.gyeongbuk", "regionType": "", "keyword": "경북 펜션 후기", "kind": "keyword", @@ -85340,7 +85232,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 펜션", "kind": "keyword", @@ -85352,7 +85244,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 숙소", "kind": "keyword", @@ -85364,7 +85256,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 독채펜션", "kind": "keyword", @@ -85376,7 +85268,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 풀빌라", "kind": "keyword", @@ -85388,7 +85280,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 애견펜션", "kind": "keyword", @@ -85400,7 +85292,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 펜션 추천", "kind": "keyword", @@ -85412,7 +85304,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 펜션 예약", "kind": "keyword", @@ -85424,7 +85316,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 펜션 가격", "kind": "keyword", @@ -85436,7 +85328,7 @@ { "sido": "경남", "region": "경남", - "regionKey": "rollup.경남", + "regionKey": "kr.gyeongnam", "regionType": "", "keyword": "경남 펜션 후기", "kind": "keyword", @@ -85448,7 +85340,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 펜션", "kind": "keyword", @@ -85460,7 +85352,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 숙소", "kind": "keyword", @@ -85472,7 +85364,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 독채펜션", "kind": "keyword", @@ -85484,7 +85376,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 풀빌라", "kind": "keyword", @@ -85496,7 +85388,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 애견펜션", "kind": "keyword", @@ -85508,7 +85400,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 펜션 추천", "kind": "keyword", @@ -85520,7 +85412,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 펜션 예약", "kind": "keyword", @@ -85532,7 +85424,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 펜션 가격", "kind": "keyword", @@ -85544,7 +85436,7 @@ { "sido": "부산", "region": "부산", - "regionKey": "rollup.부산", + "regionKey": "kr.busan", "regionType": "", "keyword": "부산 펜션 후기", "kind": "keyword", @@ -85556,7 +85448,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 펜션", "kind": "keyword", @@ -85568,7 +85460,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 숙소", "kind": "keyword", @@ -85580,7 +85472,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 독채펜션", "kind": "keyword", @@ -85592,7 +85484,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 풀빌라", "kind": "keyword", @@ -85604,7 +85496,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 애견펜션", "kind": "keyword", @@ -85616,7 +85508,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 펜션 추천", "kind": "keyword", @@ -85628,7 +85520,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 펜션 예약", "kind": "keyword", @@ -85640,7 +85532,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 펜션 가격", "kind": "keyword", @@ -85652,7 +85544,7 @@ { "sido": "제주", "region": "제주", - "regionKey": "rollup.제주", + "regionKey": "kr.jeju", "regionType": "", "keyword": "제주 펜션 후기", "kind": "keyword", diff --git a/data/regions.json b/data/regions.json index 908fcb4..606156a 100644 --- a/data/regions.json +++ b/data/regions.json @@ -1,5 +1,5 @@ { - "note": "전국 펜션 수요 지역 마스터. type 은 그 지역에서 유효한 시설 키워드를 결정한다 (해변→오션뷰, 산간→계곡뷰 등). spots 는 실제 대표 관광지. aliases 는 같은 지역을 가리키는 다른 검색 표기 (예: 대천/보령).", + "note": "전국 펜션 수요 지역 마스터. type 은 그 지역에서 유효한 시설 키워드를 결정한다 (해변→오션뷰, 산간→계곡뷰 등). spots 는 실제 대표 관광지. aliases 는 같은 지역을 가리키는 다른 검색 표기 (예: 대천/보령). ski=true 는 실제 스키장이 있는 지역 (산간이라고 다 스키장이 있는 건 아니다).", "regions": [ { "sido": "경기", @@ -117,7 +117,8 @@ "비발디파크", "은행나무숲", "홍천강" - ] + ], + "ski": true }, { "sido": "강원", @@ -146,7 +147,8 @@ "월정사", "알펜시아", "양떼목장" - ] + ], + "ski": true }, { "sido": "강원", @@ -160,7 +162,8 @@ "하이원리조트", "레일바이크", "병방치스카이워크" - ] + ], + "ski": true }, { "sido": "강원", @@ -261,7 +264,8 @@ "태백산", "검룡소", "365세이프타운" - ] + ], + "ski": true }, { "sido": "충북", @@ -456,7 +460,8 @@ "무주리조트", "반디랜드", "구천동계곡" - ] + ], + "ski": true }, { "sido": "전북", diff --git a/data/전국_펜션_SEO_AEO_키워드.xlsx b/data/전국_펜션_SEO_AEO_키워드.xlsx index 9407f00..9d4b59e 100644 Binary files a/data/전국_펜션_SEO_AEO_키워드.xlsx and b/data/전국_펜션_SEO_AEO_키워드.xlsx differ diff --git a/package.json b/package.json index 607039a..7e28996 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "dataset:ingest": "tsx scripts/ingest-dataset.ts", "dataset:purge": "tsx scripts/purge-nondataset.ts", "dataset:import-related": "tsx scripts/import-related.ts", - "dataset:nationwide": "node scripts/build-nationwide-dataset.mjs && python3 scripts/export-xlsx.py" + "dataset:nationwide": "node scripts/build-nationwide-dataset.mjs && python3 scripts/export-xlsx.py", + "dataset:ingest-nationwide": "tsx scripts/ingest-nationwide.ts" }, "dependencies": { "@huggingface/transformers": "^4.2.0", diff --git a/scripts/build-nationwide-dataset.mjs b/scripts/build-nationwide-dataset.mjs index 613e733..80b1f25 100644 --- a/scripts/build-nationwide-dataset.mjs +++ b/scripts/build-nationwide-dataset.mjs @@ -38,7 +38,7 @@ const FEATURES_COMMON = ['바베큐', '스파', '자쿠지', '수영장', '독 const SEASON_BY_TYPE = { 해변: ['여름휴가', '물놀이', '해수욕', '일출', '낙조'], 섬: ['여름휴가', '일출'], - 산간: ['겨울', '단풍', '스키', '눈꽃'], + 산간: ['겨울', '단풍', '눈꽃'], 계곡: ['여름휴가', '물놀이', '단풍'], 호수: ['여름휴가', '단풍', '벚꽃'], 강변: ['벚꽃', '단풍'], @@ -69,7 +69,12 @@ const uniq = (a) => [...new Set(a)]; for (const r of regions) { const R = r.name; const feats = uniq([...r.type.flatMap((t) => FEATURES_BY_TYPE[t] ?? []), ...FEATURES_COMMON]); - const seasons = uniq([...r.type.flatMap((t) => SEASON_BY_TYPE[t] ?? []), ...SEASON_COMMON]); + // '산간'이라고 다 스키장이 있는 건 아니다. 가평·양평·강화에 '스키 펜션'이 생기면 안 된다. + const seasons = uniq([ + ...r.type.flatMap((t) => SEASON_BY_TYPE[t] ?? []), + ...(r.ski ? ['스키', '스키장 근처', '보드'] : []), + ...SEASON_COMMON, + ]); // T1 코어 — 주력 후보. // 별칭(대천/보령 처럼 같은 지역의 다른 검색 표기)도 코어·의도 계층까지는 함께 전개한다. @@ -131,10 +136,12 @@ for (const r of regions) { add(r, t, { kind: 'tag', category: '태그', tier: '태그', relevance: 0.5 }); } -// 광역 단위 롤업 +// 광역 단위 롤업. ltree 라벨은 ASCII 만 허용하므로 시군 키에서 마지막 마디를 떼어 쓴다. +const sidoKey = {}; +for (const r of regions) sidoKey[r.sido] ??= r.key.split('.').slice(0, -1).join('.'); const sidoList = uniq(regions.map((x) => x.sido)); for (const sido of sidoList) { - const pseudo = { sido, name: sido, key: `rollup.${sido}`, type: [] }; + const pseudo = { sido, name: sido, key: sidoKey[sido], type: [] }; for (const s of ['펜션', '숙소', '독채펜션', '풀빌라', '애견펜션']) add(pseudo, `${sido} ${s}`, { category: '광역', tier: '주력', relevance: 0.92 }); for (const m of ['추천', '예약', '가격', '후기']) diff --git a/scripts/ingest-nationwide.ts b/scripts/ingest-nationwide.ts new file mode 100644 index 0000000..140ea41 --- /dev/null +++ b/scripts/ingest-nationwide.ts @@ -0,0 +1,105 @@ +/** + * 전국 지역별 펜션 키워드를 pgvector 에 적재한다. + * npx tsx scripts/ingest-nationwide.ts + * + * 군산 상세 데이터셋(source='dataset')과 공존시킨다. + * 이쪽은 source='nationwide' 로 넣고, 잔여 정리도 그 출처 안에서만 한다. + */ +import { readFileSync } from 'node:fs'; +import { createSql, toVector } from '../src/db/db'; +import { canonicalizeKeyword, isBanned, normalizeKeyword } from '../src/keywords/normalize'; +import { LocalEmbeddingProvider } from '../src/embedding/local.provider'; +import { MockEmbeddingProvider } from '../src/embedding/mock.provider'; +import { env } from '../src/config/env'; + +const SOURCE = 'nationwide'; + +interface Item { + sido: string; region: string; regionKey: string; regionType: string; + keyword: string; kind: string; intent: string; category: string; tier: string; relevance: number; +} + +async function main() { + const sql = createSql(); + const embedder = + env.embedding.provider === 'mock' ? new MockEmbeddingProvider() : new LocalEmbeddingProvider(); + + const ds = JSON.parse(readFileSync('data/nationwide-pension-keywords.json', 'utf8')); + const items: Item[] = ds.items; + const regions = JSON.parse(readFileSync('data/regions.json', 'utf8')).regions as + Array<{ sido: string; name: string; key: string }>; + console.log(`📦 ${items.length}건 / ${ds.regionCount}개 지역 · 임베딩 ${embedder.name}`); + + // 1) 지역 계층 심기 (시도 → 시군). ltree 라벨은 ASCII 만 허용한다. + const nodes = new Map(); + for (const r of regions) { + const sidoKey = r.key.split('.').slice(0, -1).join('.'); + nodes.set(sidoKey, r.sido); + nodes.set(r.key, r.name); + } + nodes.set('kr', '대한민국'); + for (const [key, name] of [...nodes].sort((a, b) => a[0].length - b[0].length)) { + await sql`INSERT INTO region (id, path, name) VALUES (${key}, ${key}::ltree, ${name}) + ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name`; + } + console.log(` 🗺 지역 노드 ${nodes.size}개 등록`); + + // 2) 어휘 중복 정리 — 키는 (지역, 정규화 키워드) + const byKey = new Map(); + let banned = 0; + for (const it of items) { + const canonical = canonicalizeKeyword(it.keyword); + const n = normalizeKeyword(canonical); + if (!n || isBanned(canonical)) { banned++; continue; } + const k = `${it.regionKey}|${n}`; + if (!byKey.has(k)) byKey.set(k, { item: { ...it, keyword: canonical }, norm: n }); + } + const uniq = [...byKey.values()]; + console.log(` 어휘 중복제거 → ${uniq.length}건 (금칙어 ${banned})`); + + // 3) 임베딩 + const t0 = Date.now(); + const vecs = await embedder.embed(uniq.map((u) => u.item.keyword), 'passage'); + console.log(` 임베딩 ${vecs.length}건 · ${embedder.dimensions}차원 · ${Date.now() - t0}ms`); + + // 4) 적재. + // keyword.normalized 는 (normalized, locale) 유니크다. 지역이 달라도 같은 문자열이면 + // 한 행으로 합쳐진다 — '오션뷰' 같은 태그가 그렇다. 지역 고유 키워드는 지명이 들어가 + // 자연히 구분되므로 문제되지 않는다. + let inserted = 0, updated = 0; + await sql.begin(async (tx) => { + for (let i = 0; i < uniq.length; i++) { + const { item, norm } = uniq[i]; + const res = await tx>` + INSERT INTO keyword + (canonical, normalized, locale, aliases, intent, kind, category, source, + industry_id, region_id, embedding) + VALUES (${item.keyword}, ${norm}, 'ko-KR', ${[]}, + ${item.intent}::keyword_intent, ${item.kind}, ${item.category}, ${SOURCE}, + 'stay.pension', ${item.kind === 'tag' ? null : item.regionKey}, + ${toVector(vecs[i])}::vector) + ON CONFLICT (normalized, locale) DO UPDATE SET + canonical = EXCLUDED.canonical, intent = EXCLUDED.intent, kind = EXCLUDED.kind, + category = EXCLUDED.category, source = EXCLUDED.source, + region_id = COALESCE(keyword.region_id, EXCLUDED.region_id), + embedding = EXCLUDED.embedding, updated_at = now() + RETURNING (xmax = 0) AS inserted`; + res[0]?.inserted ? inserted++ : updated++; + if (i % 500 === 0) process.stdout.write(`\r 적재 ${i}/${uniq.length}`); + } + }); + console.log(`\r ✅ 신규 ${inserted} · 갱신 ${updated} `); + + // 5) 이 출처 안에서만 잔여 정리 + const wanted = uniq.map((u) => u.norm); + const stale = await sql` + DELETE FROM keyword WHERE source = ${SOURCE} AND NOT (normalized = ANY(${wanted})) RETURNING id`; + console.log(` 🧹 이전 판본 잔여 ${stale.length}건 삭제`); + + const counts = await sql>` + SELECT source, count(*)::int AS n FROM keyword GROUP BY source ORDER BY n DESC`; + console.log(' 📚 사전 현황: ' + counts.map((c) => `${c.source} ${c.n}`).join(' · ')); + await sql.end(); +} + +main().catch((e) => { console.error('❌', e); process.exit(1); }); diff --git a/src/serving/match.service.ts b/src/serving/match.service.ts index 434029a..2a46081 100644 --- a/src/serving/match.service.ts +++ b/src/serving/match.service.ts @@ -15,7 +15,7 @@ const RRF_K = 20; const LANE_DEPTH = 50; // 레인당 후보 깊이 — 깊을수록 generic 이 유리해진다 const LANE_FLOOR = 0.80; // 이 코사인 미만은 그 레인에서 기여하지 않는다 // 매칭 후보로 인정하는 출처. 고정 데이터셋 정책상 LLM 생성물은 사전에 섞이면 안 된다. -const MATCH_SOURCES = ['dataset', 'manual']; +const MATCH_SOURCES = ['dataset', 'nationwide', 'manual']; interface Hit { id: string; canonical: string; intent: string; kind: string;