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
반응형
'프로젝트 ' 카테고리의 다른 글
#4 [REACT.JS] 에디터 구현하기-1 (0) | 2024.02.14 |
---|---|
[chat gpt] 구글 시트에서 GPT for Sheets 사용해보기 (0) | 2023.02.19 |
#4 [REACT.JS] 엑셀 데이터 기반 드래그앤드랍 명함 편집 기능 구현기 (0) | 2023.01.28 |
#4 [REACT.JS] 사진 불러오기, 엑셀 읽어오기 (0) | 2021.11.22 |
#3 기본 레이아웃 구성 및 팝업 생성 (0) | 2021.11.21 |