Commit Graph

9 Commits

Author SHA1 Message Date
54f8f83a7a 배포용 엑셀에 DB 전 테이블 반영
merchant_keyword(업체↔키워드 연결)와 generation_run(생성 감사 로그)이
빠져 있었다. 시트 2개를 추가해 DB 7개 테이블을 모두 담는다.

시트별 행수를 DB 와 대조해 전부 일치 확인:
  키워드 7,093 / 지역 70 / 업종 9 / 업체 4 /
  업체키워드 11 / QA 20 / 생성이력 4

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 10:27:37 +09:00
8322bd45cb 배포용 DB 덤프 산출물 추가
엑셀이 DB 와 일치하지 않았다. 기존 엑셀은 전국 JSON 에서만 뽑아
군산 상세 데이터셋 850건이 빠져 있었다 (DB 7,093 vs 엑셀 6,243).

- scripts/export-db-xlsx.py — DB 를 기준으로 뽑는다 (JSON 아님)
  시트 6개: 키워드 7,093 / 지역 70 / 업종 9 / 업체 4 / QA 20 / 배포가이드
  임베딩은 담지 않는다 (384 float × 7천 행). 같은 모델로 재생성하면 복원된다
- scripts/db-dump.sh — 임베딩 포함 pg_dump (13MB, .gitignore)
- npm run db:export-xlsx / db:dump

복원 검증 완료: 6개 테이블 행수 일치, 임베딩 7,093/7,093 보존,
HNSW 인덱스 재생성, 복원본에서 벡터 검색 동작 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 10:26:05 +09:00
df8ce5f117 전국 지역별 펜션 키워드 데이터셋 + 엑셀 산출
기획 변경: 군산 단일 지역 → 전국 지역별.

- data/regions.json — 전국 54개 펜션 수요 지역 마스터
  시도/지역/지역키/성격(해변·산간·호수·강변·도심·섬·계곡)/대표 관광지 202곳
  복합 지명은 별칭으로 분리 (보령·대천 → 대천 + 별칭 보령)
- scripts/build-nationwide-dataset.mjs — 지역 성격에 맞는 시설·시즌만 전개
  평창·무주 오션뷰 0건, 태안·거제 산뷰 0건으로 검증
- scripts/export-xlsx.py — 4개 시트 엑셀 (키워드/지역마스터/지역별요약/사용가이드)
- npm run dataset:nationwide

7,138건 / 지역당 평균 110건.
군산 974건을 54개 지역에 곱하면 5만 건이 되지만, 단일 지역 검증에서
저장분의 89%가 미사용이었으므로 티어를 매겨 눌렀다.

검색량·경쟁도 열은 비워 두었다 — 키워드도구로 채운 뒤 월 10 미만을 걷어내야 한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 17:04:40 +09:00
25f2cc871d 스테이머뭄 매칭 품질 개선 4건
② 사전 보강 — 실측으로 찾은 어휘 공백을 메움
   - 인원: 2인·3인 추가 (4/6/10/20인만 있어 기준 2인 업체가 노릴 키워드가 없었다)
   - 단독 명사형: 군산 독채 / 스테이 / 풀빌라 (조합형만 있어 단독 검색을 놓쳤다)
   - 분위기 11종(감성·조용한·사진찍기 좋은·인생샷 …), 여행형태 9종(뚜벅이·1박2일 …)
   - scripts/import-related.ts — 검색광고 키워드도구 내려받기 병합 (파일 임포터)

③ 사전 오염 정리
   - source='llm' 27건 삭제 (강남 미용실·해운대 한식당이 군산 펜션 사전에 있었다)
   - 매칭 후보를 업체 업종으로 한정 + source IN ('dataset','manual') 만 조회
   - 적재 시 데이터셋에서 빠진 행 삭제 — upsert 만 하면 재빌드마다 누적된다 (974 → 1072)

④ 고객 언어 레인 (w=0.9)
   - hashtags + reviewSignals(원문 아닌 빈도 집계) 를 별도 레인으로
   - 사업자 표현보다 검색어에 가까우므로 유형 다음으로 높게 잡음
   - 스테이머뭄 데이터는 아직 없음 — 인스타는 로그인 월이라 스크래퍼가 채워야 함

⑤ 레인 토큰 중복 제거
   - '신흥동' 과 '신흥동 일본식가옥' 이 별개 원소라 같은 낱말이 두 번 실렸다

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 14:09:36 +09:00
f7485aab32 매칭을 속성별 다중 질의 + 가중 RRF + 사실 기반 필터로 재구성
프로필을 통짜로 한 벡터에 넣으면 속성이 희석된다.
실측: 통짜는 점수 폭 0.0076, 속성별로 쪼개면 0.0624 (8배).

- src/serving/match.rules.ts — 레인 빌더, 권역 판정, 수용 인원/시설 필터,
  시설 통제 어휘 정규화
- src/serving/match.service.ts — 레인별 검색 → 가중 RRF 융합 → 필터 →
  레인별 그룹(byLane) 출력. 근거(어느 레인 몇 위)를 함께 반환
- POST /v1/match 에 mode=fusion(기본) / single(기존 통짜, 비교용)
- 데모 페이지: 모드 토글, 레인 카드, 융합/레인별/배제됨 탭

레인 설계에서 실측으로 고친 것
- 브랜드 레인 제거 — 상호는 사전에 없어 generic '군산 펜션 ~예약'만 끌어왔다
- 권역/인근 레인 병합 — '신흥동' 토큰이 겹쳐 위치 키워드가 상위를 쓸어갔다
- RRF 상수 60 → 20 — 60은 1위/40위 기여도 차이가 1.6배뿐이라 generic이 유리했다

사실 기반 필터는 벡터가 못 거르는 모순을 배제한다.
스테이머뭄(최대 4인, 원도심) 기준 61건 배제.
미확인 시설은 배제하지 않고 '보류'로 표시한다 — 없음이 아니라 모름이므로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 16:00:00 +09:00
1addd7a270 스테이머뭄 시드를 실제 업체 정보로 교체
초기 시드의 스테이머뭄 프로필은 데모용으로 지어낸 값이었고
실제와 반대였다 (고군산군도 오션뷰 6객실 → 실제는 군산 원도심
신흥동 말랭이마을 인근 독채 2동, 기준 2인·최대 4인).

- 공개 정보로 확인된 항목만 반영, 미확인 항목은 profile.unverified 로 표시
- 데이터셋 어휘에 원도심 권역 보강 (말랭이마을·신흥동·영화동·근대문화역사거리·
  해망굴·뜬다리부두, 독채스테이/감성숙소/스테이 유형) — 말랭이마을이 누락돼 있었다
- 재적재 976건

매칭 결과가 오션뷰/고군산군도 계열에서
군산 원도심 독채펜션 / 군산 독채스테이 / 말랭이마을 근처 숙소 로 교정됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 15:32:07 +09:00
edde23f15e 고정 데이터셋 1,000건 적재 + 로컬 임베딩 + 매칭 콘솔
정책 변경: 주기 수집 없이 고정 데이터셋을 1회 적재한다.

- data/gunsan-pension-keywords.json — "군산 펜션" 키워드·태그 1,000건
  실제 군산 지명·관광지·숙박 시설 어휘 × 로컬 검색 패턴으로 작성
- 임베딩을 LlmProvider 에서 EmbeddingProvider 로 분리
  (mock | local:multilingual-e5-small | openai), e5 의 query/passage 비대칭 반영
- vector(1536) → vector(384) 마이그레이션, keyword 에 source/kind/category 추가
- scripts/ingest-dataset.ts — 어휘 중복만 자동 병합, 벡터 근접쌍은 검토 목록만 출력
- POST /v1/match — 업체명(띄어쓰기 무관) 또는 문장 → 사전에서 매칭
  업체는 프로필 전체를 질의문으로 조립해 임베딩
- GET /demo — 매칭 콘솔 (public/demo.html)

실측으로 코사인 자동 병합 임계값을 0.92 → 0.99 로 정정.
짧은 한글 키워드는 같은 도메인이면 0.93+ 가 기본이라 0.92 는 오병합을 부른다.

적재 결과: 1,000건 → 어휘 중복 27 병합, 금칙어 2 차단 → 971건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 15:11:45 +09:00
ef7d51da2c 설계 문서 PPTX 덱 추가
docs/architecture.html 내용을 발표용 11장 덱으로 재구성.
전체 흐름·중복제거 4단계·데이터 모델 도식을 이미지가 아니라
네이티브 도형으로 그려 PowerPoint 에서 그대로 편집 가능하다.

- scripts/build-deck.py (python-pptx) 로 재생성 가능
- 슬라이드 경계 이탈 0건, 텍스트 가로 넘침 0건 검증

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 13:50:31 +09:00
209a381091 SEO/AEO 키워드 온톨로지 서비스 초기 구현
발행된 사이트에 업체별 SEO/AEO 키워드를 제공하는 서비스.

- PostgreSQL 16 + pgvector/ltree/pg_trgm 단일 스토어
  (정확·의미·계층 조회를 한 엔진에서 처리)
- 키워드는 전역 사전 + merchant_keyword 연결 테이블 구조
- 4단계 계단식 중복제거: 금칙어 → normalized 완전일치 →
  pg_trgm → 코사인 유사도, 걸린 표기는 aliases[] 로 흡수
- BullMQ 생성 큐 (발행 즉시 / 일 1회 크론 / 성과 기반)
- OpenAI Structured Outputs + mock provider
  (API 키 없이 로컬 전 구간 동작)
- 서빙 API: /v1/sites/:id/seo, /aeo, /performance, /keywords/search
- docs/architecture.html 설계 도식

JSON-LD 조립과 o2o-site-AEO 연동은 후속 작업.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 11:56:34 +09:00