
📌 임베딩 데이터를 저장하는 최적의 방법은?
최근 AI 기술의 발전과 함께 텍스트 임베딩(Text Embeddings) 이 점점 더 중요한 역할을 하고 있습니다.
임베딩은 텍스트 데이터를 고차원 벡터로 변환한 것으로, 이를 활용하면 유사한 의미를 가진 텍스트를 쉽게 비교 하거나 빠르게 검색할 수 있는 기능 을 구현할 수 있습니다.
하지만 한 가지 문제점이 있습니다.
"임베딩 데이터를 효과적으로 저장하고 빠르게 검색하려면 어떻게 해야 할까?"
많은 사람들은 CSV, Pickle, Numpy 배열 같은 방법을 사용하지만, 이 방법들은 저장 공간을 많이 차지하고 속도도 비효율적입니다.
더 좋은 방법은 없을까요?
이 글에서는 Parquet 파일과 Polars 라이브러리를 활용한 최적의 임베딩 저장 방법 을 소개합니다.
이를 통해 효율적인 데이터 저장, 빠른 검색, 그리고 실용적인 활용법까지 모두 알아볼 수 있습니다.
🧐 임베딩 데이터 저장 방식과 문제점
임베딩을 저장하는 방법은 여러 가지가 있지만, 기존 방법들은 단점이 많습니다.
1️⃣ CSV 파일: 간단하지만 비효율적
CSV 파일은 가장 직관적인 방법이지만, 다음과 같은 문제점이 있습니다.
✔ 숫자를 텍스트로 변환하여 저장하기 때문에 파일 크기가 커짐
✔ 데이터를 불러올 때 다시 숫자로 변환해야 해서 속도가 느림
✔ 다차원 배열(임베딩 데이터) 저장이 어려움
📌 예제 코드 (CSV 저장 및 불러오기)
import numpy as np
import pandas as pd
# 랜덤한 768차원 임베딩 데이터 생성
embeddings = np.random.rand(10000, 768).astype(np.float32)
# CSV 파일로 저장
df = pd.DataFrame(embeddings)
df.to_csv("embeddings.csv", index=False)
# CSV 파일 불러오기
df = pd.read_csv("embeddings.csv")
embeddings = df.values.astype(np.float32)
이 방식은 데이터가 많아질수록 불필요한 변환 비용 이 증가하고 속도가 느려집니다.
2️⃣ Pickle 파일: 빠르지만 비효율적인 방식
Pickle은 Python 객체를 그대로 저장하는 방식입니다.
CSV보다 저장 속도는 빠르지만, 몇 가지 문제점이 있습니다.
✔ 보안 문제: Pickle 파일은 임의의 코드 실행이 가능하여 위험함
✔ 이식성 부족: 다른 언어에서 사용하기 어려움
✔ 데이터 검색 불가능: 저장된 데이터를 빠르게 검색할 수 없음
3️⃣ Numpy 파일(.npy): 빠르지만 메타데이터 저장이 어려움
Numpy 배열을 그대로 저장하는 방식도 있습니다.
np.save("embeddings.npy", embeddings)
embeddings = np.load("embeddings.npy")
✔ 빠르고 효율적이지만, 메타데이터(예: 문장 ID, 태그 등)를 함께 저장하기 어려움
✔ 데이터 필터링 및 검색 기능이 부족함
🚀 Parquet와 Polars: 더 나은 대안
✅ Parquet 파일이란?
Parquet는 Apache에서 개발한 컬럼형 저장 방식의 파일 포맷 입니다.
CSV와 달리 숫자를 압축된 바이너리 형태로 저장하여 파일 크기를 줄이고 속도를 향상 시킬 수 있습니다.
✔ 빠른 저장 및 로딩 속도
✔ 저장 공간 절약 (CSV 대비 5~10배 더 효율적)
✔ 컬럼별 저장이 가능하여 검색 속도 증가
📌 예제 코드 (Parquet 저장 및 불러오기)
import pandas as pd
df = pd.DataFrame({"id": range(10000), "embedding": list(embeddings)})
df.to_parquet("embeddings.parquet", index=False)
# 불러오기
df = pd.read_parquet("embeddings.parquet")
embeddings = np.vstack(df["embedding"].to_numpy())
✅ Polars 라이브러리를 활용한 고속 데이터 처리
Polars는 Pandas보다 10배 이상 빠른 속도 를 제공하는 데이터 프레임 라이브러리입니다.
특히 Parquet와 함께 사용하면 큰 데이터도 빠르게 처리 할 수 있습니다.
✔ Pandas보다 훨씬 빠른 속도
✔ Zero-Copy 지원 → 메모리 효율적 사용
✔ 복잡한 데이터 필터링도 쉽고 빠름
📌 Polars를 활용한 Parquet 파일 저장 및 로딩
import polars as pl
df = pl.DataFrame({"id": range(10000), "embedding": embeddings.tolist()})
df.write_parquet("embeddings.parquet")
# 불러오기
df = pl.read_parquet("embeddings.parquet")
embeddings = np.array(df["embedding"].to_list(), dtype=np.float32)
이제 데이터 로딩 속도가 훨씬 빨라지고, 파일 크기도 줄어든다 는 것을 확인할 수 있습니다.
🏎 빠른 유사도 검색(dot product 활용)
임베딩 데이터를 저장하는 것뿐만 아니라, 빠르게 검색하는 것도 중요 합니다.
보통 벡터 데이터베이스를 사용하지만, 작은 프로젝트에서는 Polars와 Numpy를 활용하여 빠르게 검색할 수도 있습니다.
def fast_dot_product(query, matrix, k=3):
dot_products = query @ matrix.T
idx = np.argpartition(dot_products, -k)[-k:]
idx = idx[np.argsort(dot_products[idx])[::-1]]
return idx, dot_products[idx]
# 예제: 특정 임베딩과 가장 유사한 3개 찾기
query_embedding = embeddings[0]
idx, scores = fast_dot_product(query_embedding, embeddings, k=3)
print(f"유사한 임베딩 인덱스: {idx}, 점수: {scores}")
✔ Numpy의 dot product 연산을 활용하여 매우 빠르게 유사한 데이터를 찾을 수 있습니다.
✔ 작은 규모의 데이터라면 벡터 데이터베이스 없이도 충분히 빠르게 검색이 가능합니다.
벡터 데이터베이스 없이도 최적의 임베딩 저장과 검색 가능!
- CSV, Pickle, Numpy 등의 기존 방식은 효율적이지 않음
- Parquet 파일 을 사용하면 공간 절약 + 빠른 데이터 로딩 가능
- Polars 라이브러리 를 활용하면 데이터 검색 및 필터링 속도 향상
- 작은 규모의 프로젝트에서는 벡터 데이터베이스 없이도 충분히 빠른 검색 가능
✅ "벡터 데이터베이스를 꼭 사용해야 할까?"
👉 작은 프로젝트에서는 Parquet + Polars 조합이 더 효율적일 수도 있습니다!
https://minimaxir.com/2025/02/embeddings-parquet/
The Best Way to Use Text Embeddings Portably is With Parquet and Polars
Never store embeddings in a CSV!
minimaxir.com

'DB' 카테고리의 다른 글
PostgreSQL에서 그래프 데이터베이스로 pgRouting 활용하기 (0) | 2025.03.04 |
---|---|
Rust로 다시 태어난 SQLite: Limbo 프로젝트를 소개합니다 (0) | 2024.12.13 |
2025년에 주목해야 할 7가지 데이터베이스: 기술 혁신을 탐구하다 (0) | 2024.12.11 |
실시간 데이터 동기화의 핵심! Change Data Capture (CDC) 알아보기 (0) | 2024.11.13 |
Prepared Statement란 무엇인가? (0) | 2024.11.06 |