본문 바로가기

프로젝트

Qdrant + 임베딩으로 매운 음식 추천/검색 서버 구축

728x90

이번 프로젝트에서는 Qdrant를 Docker로 띄워서, 매운 음식 데이터를 기반으로 질의응답 서버를 구축했다.

사용자가 좋아하는 음식을 입력하면, 의미 기반 벡터 검색과 조건 필터링으로 관련 음식을 추천해준다.

Qdrant 띄우기

docker run -p 6333:6333 qdrant/qdrant

대시보드 접속: http://localhost:6333/dashboard#/collections

Collection 생성

임베딩 벡터 차원은 사용하는 모델 all-MiniLM-L6-v2 기준 384차원으로 설정했습니다.

curl -X PUT "http://localhost:6333/collections/food_collection" \
  -H "Content-Type: application/json" \
  -d '{
    "vectors": {
      "size": 384,
      "distance": "Cosine"
    }
  }'

샘플 데이터

{
  "id": "buldak_bokkeum_myeon",
  "name": "불닭볶음면",
  "country": "Korea",
  "spice_level": 5,
  "scoville_estimate": 4400,
  "ingredients": ["라면", "닭고기 추출물", "고추", "간장", "설탕"],
  "category": "instant noodles",
  "description": "입안이 얼얼할 정도로 맵고, 기름진 닭볶음 양념이 강렬하다. 한국에서 인기 있는 매운 라면.",
  "tags": ["매운","라면","인기","한국"]
}
  • description: 체감형 매운맛 묘사 → 임베딩 품질 향상
  • spice_level, scoville_estimate: 숫자 기반 필터링
  • country, ingredients, category: 조건 검색/하이브리드 검색 활용

Vector vs Payload

Qdrant에 데이터를 넣을 때는 두 가지 역할로 분리한다.

  • Vector: 의미 기반 검색용 (name + description + ingredients)
  • Payload: 메타데이터/필터용 (id, country, spice_level 등)
{
  "id": "buldak_bokkeum_myeon",
  "vector": [0.12, 0.82, 0.48, ...],
  "payload": {
    "name": "불닭볶음면",
    "country": "Korea",
    "spice_level": 5,
    "scoville_estimate": 4400,
    "ingredients": ["라면", "닭고기 추출물", "고추", "간장", "설탕"],
    "category": "instant noodles",
    "description": "입안이 얼얼할 정도로 맵고..."
  }
}

코사인 유사도

  • 1 → 거의 같은 의미
  • 0 → 관련 없음
  • -1 → 완전히 반대 의미

예시: "매운 라면" ↔ "불닭볶음면" → 0.95, "매운 라면" ↔ "바닐라 아이스크림" → 0.1

검색 방법

  • Similarity Search: 벡터끼리 비교 → 맛/재료/설명 유사한 음식 추천
  • Hybrid Search: 벡터 검색 + Payload 필터링 → 조건 포함 검색 가능
    • 예: "불닭볶음면과 비슷한 음식 중 한국 음식만"
    • 예: "한국에서 닭고기 들어간 매운 라면"

검색 예시 (Axios)

const response = await axios.post(
  `http://localhost:6333/collections/food_collection/points/search`,
  {
    vector,
    limit: 3,
    with_payload: true,
    filter: {
      must: [
        { key: "ingredients", match: { value: "닭고기" } }
      ]
    }
  },
  { headers: { "Content-Type": "application/json" } }
);

검색 결과 예시

{
  "search_results": [
    {
      "score": "0.5414",
      "name": "불닭",
      "description": "매운 양념으로 양념된 닭고기..."
    },
    {
      "score": "0.3152",
      "name": "매운 인도 팔 커리",
      "description": "세계에서 가장 매운 커리 중 하나..."
    },
    {
      "score": "0.3043",
      "name": "매운 멕시코 팅가",
      "description": "닭고기를 매운 고추와 토마토 소스로..."
    }
  ]
}

요약

  • Qdrant: HNSW 기반 ANN 벡터 검색 + 필터링
  • Vector: 의미 검색(name/description/ingredients)
  • Payload: 조건/숫자 필터용(id, country, spice_level)
  • Similarity Search + Payload 필터 → 추천/검색 품질 최적화
728x90
반응형