OpenAI GPTμ pgvectorλ₯Ό νμ©ν μ§λ₯ν μΌνλͺ° νλ«νΌ μμ°μ΄ λνλ₯Ό ν΅ν κ°μΈνλ μν μΆμ² μ 곡
- π€ AI λνν μΆμ²: OpenAI GPT-4 + text-embedding-3-smallμ νμ©ν μμ°μ΄ μν μΆμ²
- π λ²‘ν° μ μ¬λ κ²μ: PostgreSQL pgvector + HNSW μΈλ±μ€λ‘ κ³ μ κ²μ (10-50ms)
- β‘ μ±λ₯ μ΅μ ν: λΉλκΈ° μ²λ¦¬ + Redis μΊμ±μΌλ‘ λΉ λ₯Έ μλ΅
- π 보μ: JWT μΈμ¦ + Spring Security κΈ°λ° κΆν κ΄λ¦¬
- Backend: Spring Boot 3.1.4 (Java 17)
- Database: PostgreSQL 16 + pgvector
- Cache: Redis 7
- AI: OpenAI GPT-4, text-embedding-3-small (1536μ°¨μ)
- Security: Spring Security + JWT
- Spring Data JPA, MyBatis, QueryDSL 5.0
- MapStruct, Lombok, Firebase
- Docker & Docker Compose
μ¬μ©μ 쿼리 β OpenAI Embedding (1536μ°¨μ 벑ν°)
β
PostgreSQL pgvector μ½μ¬μΈ μ μ¬λ κ²μ
β
μΆμ² μν λ°ν + λν μ΄λ ₯ μ μ₯
| μ»΄ν¬λνΈ | μν | μμΉ |
|---|---|---|
| ConversationalRecommendationService | λνν μΆμ² μ€μΌμ€νΈλ μ΄ν° | ai/recommendation/application/ |
| ProductVectorService | pgvector κ²μ μμ§ | ai/recommendation/infrastructure/ |
| EmbeddingApiClient | OpenAI API ν΄λΌμ΄μΈνΈ | ai/embedding/ |
| RecommendationEngine | μΆμ² λ‘μ§ | ai/recommendation/application/ |
- Java 17+
- Docker & Docker Compose
- OpenAI API Key
# OpenAI API ν€ μ€μ
echo "openai.api.key=sk-proj-your-key" > src/main/resources/application-secrets.properties# μΈνλΌ μμ (PostgreSQL + Redis)
docker-compose up -d
# μ ν리μΌμ΄μ
μμ
./gradlew bootRun- μ ν리μΌμ΄μ : http://localhost:8080
- ν¬μ€μ²΄ν¬: http://localhost:8080/actuator/health
src/main/java/com/example/crud/
βββ ai/ # AI κΈ°λ₯ λͺ¨λ
β βββ conversation/ # λν μμ€ν
β βββ embedding/ # OpenAI μλ² λ©
β βββ recommendation/ # μΆμ² μμ§
βββ common/ # κ³΅ν΅ μ»΄ν¬λνΈ (보μ, μ€μ )
βββ controller/ # REST 컨νΈλ‘€λ¬
βββ data/ # λΉμ¦λμ€ λ‘μ§ (μν, μ£Όλ¬Έ, κ²°μ )
βββ entity/ # JPA μν°ν°
βββ repository/ # λ°μ΄ν° μ κ·Ό κ³μΈ΅
SELECT p.number, p.name,
(1 - (p.description_vector <=> CAST(? AS vector))) as similarity
FROM product p
WHERE (1 - (p.description_vector <=> CAST(? AS vector))) > 0.3
ORDER BY p.description_vector <=> CAST(? AS vector)
LIMIT ?;| νλͺ© | μμ μκ° | λΉκ³ |
|---|---|---|
| μλ² λ© μμ± | 300-500ms | OpenAI API |
| Redis μΊμ | 5-10ms | μΊμ ννΈ μ |
| λ²‘ν° κ²μ | 10-50ms | HNSW μΈλ±μ€ |
| μ 체 μλ΅ | 50-400ms | μΊμ μ¬λΆμ λ°λΌ |
Java λ°λ³΅λ¬Έ vs pgvector: 200-600λ°° μ±λ₯ ν₯μ β‘
# ν¬μ€μ²΄ν¬
curl http://localhost:8080/actuator/health
# μλ² λ© μμ±
curl -X POST http://localhost:8080/api/test/recommendation/embedding \
-H "Content-Type: application/json" \
-d '{"text": "warm winter sweater"}'
# μν μΆμ²
curl -X POST http://localhost:8080/api/test/recommendation/text \
-H "Content-Type: application/json" \
-d '{"query": "comfortable knit clothing", "limit": 5}'# OpenAI API μ μ©
embeddingTaskExecutor: μ½μ΄ 4, μ΅λ 8, ν 100
# DB λ²‘ν° κ²μ μ μ©
dbTaskExecutor: μ½μ΄ 4, μ΅λ 8, ν 50String cacheKey = text.trim().toLowerCase().hashCode();- μλ² λ© κ²°κ³Ό μΊμ±μΌλ‘ API νΈμΆ μ΅μν
- product: μν μ 보 + description_vector (1536μ°¨μ)
- conversation: λν μ΄λ ₯
- conversation_message: USER/ASSISTANT λ©μμ§
- member: νμ μ 보 + JWT μΈμ¦
CREATE INDEX idx_product_vector ON product
USING hnsw (description_vector vector_cosine_ops)
WITH (m = 16, ef_construction = 64);OpenAI API μ€ν¨
cat src/main/resources/application-secrets.propertiespgvector μ€λ₯
docker-compose exec db psql -U sungho -d app \
-c "CREATE EXTENSION IF NOT EXISTS vector;"Redis μ°κ²° μ€ν¨
docker-compose exec redis redis-cli pingπ― ν΅μ¬: AI κΈ°μ μ νμ©ν κ°μΈνλ μΌν κ²½ν μ 곡