Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
implementation 'io.minio:minio:9.0.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6'
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
implementation 'org.flywaydb:flyway-core'
Expand Down
20 changes: 19 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,24 @@ services:
timeout: 5s
retries: 10
start_period: 10s

elasticsearch:
build: ./es
container_name: youthpick-es
environment:
- discovery.type=single-node # 단일 노드 (클러스터 구성 안 함)
- xpack.security.enabled=false # 로컬이라 인증 끔
- ES_JAVA_OPTS=-Xms512m -Xmx512m # 안 주면 시스템 메모리의 절반을 먹는다
ports:
- "${ES_PORT:-9200}:9200"
volumes:
- youthpick-es-data:/usr/share/elasticsearch/data
- ./es/config:/usr/share/elasticsearch/config/analysis
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 40s
backend:
build:
context: .
Expand Down Expand Up @@ -103,3 +120,4 @@ volumes:
youthpick-mysql-data:
youthpick-redis-data:
youthpick-minio-data:
youthpick-es-data:
115 changes: 115 additions & 0 deletions docs/2026-09-05-검색-기준선-측정.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# 검색 기준선(before) 측정 — LIKE 검색의 실패 유형

> 2026-09-05 측정. ES 도입 전 현행 `LIKE '%키워드%'` 검색의 상태를 기록한다.
> 대상: `policies` 2,691건 (VISIBLE, deleted_at IS NULL) — **실데이터, 합성 아님**
> 측정 조건: `PolicyRepository.findCards`의 keyword 조건과 동일한 5필드 LIKE
> (title / keywords / description / support_content / organization_name)

## 0. 실사용 검색 로그 (참고)

`search_histories` 53건, 2026-07-25 14:20~15:16 (약 1시간) — **데모 촬영 중 기록**이라 표본으로 쓸 수 없다.

| 검색어 | 횟수 | 결과 |
|---|---|---|
| 서울 | 29 | 56~198 |
| 주거 | 8 | 17 |
| 강원 | 7 | 18 |
| 서산 | 5 | 33 |
| k-디지털 | 2 | **1** |
| k | 1 | **60** |

- `result_count = 0`인 검색은 **0건** — 데모라 잘 나오는 검색어만 입력했기 때문.
- 다만 `k-디지털 → 1건`은 0건이 아니어서 "성공"으로 기록됐지만 **사용자 입장에서는 실패**다.
→ 현행 0건율 지표가 실패를 과소평가한다.
- 검색어 7종 중 4종이 지역명(서울·강원·서산) — 지역 검색 비중이 높다는 실사용 근거.

## 1. 실패 유형과 실측치

### 유형 A — 동의어를 모른다

| 검색어 | 결과 |
|---|---|
| 일자리 | 380 |
| 취업 | 662 |
| 채용 | 166 |
| 구직 | 222 |

**"일자리"로 검색하면 "취업" 정책 488건을 놓친다** (전체 2,691건의 **18.1%**).
"구직" 정책은 158건을 놓친다. 주거 계열도 동일 — "주거" 검색 시 월세 8건 · 주택 25건 누락.

### 유형 B — 띄어쓰기가 다르면 못 찾는다

| 검색어 | 결과 |
|---|---|
| 청년 일자리 (공백 O) | 49 |
| 청년일자리 (공백 X) | 70 |

두 결과 집합이 서로 다르다. 사용자가 띄어 쓰면 붙여 쓴 정책을, 붙여 쓰면 띄어 쓴 정책을 놓친다.

### 유형 C — 어순이 바뀌면 무너진다

| 검색어 | 결과 |
|---|---|
| 지원사업 | 503 |
| 사업 지원 | 24 |
| 청년 월세 지원 | 7 |
| 월세 지원 청년 | **0** |
| 일자리 청년 | 1 |

**단어를 재배열했을 뿐인데 7건 → 0건.** LIKE는 문자열이 그 순서 그대로 붙어 있어야 매칭된다.

### 유형 D — 자연스러운 문장으로 검색하면 0건

| 검색어 | 결과 |
|---|---|
| **서울 청년 취업** | **0** |
| **일자리를 찾고 있어요** | **0** |

가장 심각한 케이스. `서울`·`청년`·`취업`은 각각 수백 건씩 있는 단어인데, **세 단어를 함께 입력하면 0건**이다.
사용자가 검색창에 자연어를 넣는 순간 검색이 사실상 동작하지 않는다.

### 유형 E — 표기 변형·복합어

| 검색어 | 결과 |
|---|---|
| k-디지털 | 3 |
| **K디지털** (하이픈 제거) | **0** |
| 디지털 | 52 |
| 청년도약계좌 | 1 |

실사용 로그에 남은 `k-디지털`은 하이픈을 빼는 순간 0건이 된다.

## 2. 요약

| 유형 | 대표 케이스 | before |
|---|---|---|
| A 동의어 | 일자리 → 취업 정책 누락 | **488건(18.1%) 누락** |
| B 띄어쓰기 | 청년 일자리 / 청년일자리 | 49 vs 70 (불일치) |
| C 어순 | 청년 월세 지원 → 월세 지원 청년 | 7 → **0** |
| D 자연어 | 서울 청년 취업 | **0** |
| E 표기변형 | k-디지털 → K디지털 | 3 → **0** |

**공통 원인:** `LIKE '%키워드%'`는 형태소·동의어·어순 개념이 없는 **문자열 부분일치**다.
쿼리 튜닝으로는 해결되지 않으며, 색인 자료구조를 바꿔야 한다.

또한 이 5개 유형 어디에도 **관련도 순위**가 없다 — 현재 정렬은 `id DESC`(최신순) 고정이라,
제목 정확일치와 본문 구석 일치가 동급이다. (로그의 `k → 60건`이 그 예)

## 3. 재측정 방법 (after 비교용)

동일 조건에서 같은 검색어를 재실행한다.

```bash
# scratchpad/baseline.sh 와 동일한 5필드 LIKE
docker exec youthpick-mysql mysql -uroot -proot --default-character-set=utf8mb4 -N -B youthpick -e "
SELECT COUNT(*) FROM policies p
WHERE p.visibility='VISIBLE' AND p.admin_hidden=0 AND p.deleted_at IS NULL
AND (p.title LIKE '%검색어%' OR p.keywords LIKE '%검색어%' OR p.description LIKE '%검색어%'
OR p.support_content LIKE '%검색어%' OR p.organization_name LIKE '%검색어%');"
```

측정 검색어 26종:
`일자리 취업 채용 구직 일거리 주거 주택 월세 임대 창업 사업 지원금 보조금 수당`
`"청년 일자리" 청년일자리 "일자리 청년" 지원사업 "사업 지원" k-디지털 K디지털 디지털`
`청년도약계좌 도약계좌 일자리를 취업지원`
`"일자리를 찾고 있어요" "청년 월세 지원" "월세 지원 청년" "서울 청년 취업" "청년 취업 서울"`
Loading
Loading