LanceDB
LanceDB
LanceDB는 벡터 데이터베이스를 지원하는 오픈소스 중 하나로, 이전에 벡터 유사도 검색을 지원하는 라이브러리와 프레임워크를 벤치마킹하면서 알게되었다.
당시에는 같은 인메모리 데이터베이스 중에서 ChromaDB 및 Faiss에 비해 메리트가 없다고 느꼈었는데, 최근 Hybrid Search가 필요해 벤치마크들을 다시 조사하게 되면서 LanceDB가 이를 지원한다는 사실을 알게되었다.
그래서 오늘은 LanceDB에는 어떤 기능들이 있는지, 다른 벡터 데이터베이스와는 어떤 차이점이 있는지 다루어보려고 한다.
LanceDB vs pgvector
평소 벡터 데이터베이스 중에서는 PGVector가 가장 편리하고 production 환경에 적합하다고 생각했는데, 상황에 따라 LanceDB도 좋은 옵션이 될 수 있겠다는 생각도 들었다.
PGVector는 PostgreSQL의 extension으로써 벡터 데이터베이스 기능을 RDBMS를 기반으로 제공하는 반면, LanceDB는 인메모리 및 오브젝트 스토리지를 기반으로 제공한다.
이 덕분에 LanceDB를 MinIO, AWS S3 등과 쉽게 연동할 수 있으며, 오프라인에서 배치로 작업한 결과물을 다른 환경에서 사용할 때 큰 강점이 있다.
| - | PGVector | LanceDB |
|---|---|---|
| Storage | PostgreSQL | In-memory / Object storage |
| Type Support | Vector | Vector (pyarrow) |
| Filtering | Y | Y |
| Joining | Y | N |
| Transaction | ACID | Table versioning |
| Vector Index | IVF-Flat, HNSW | IVF_FLAT, IVF-PQ, IVF-HNSW 등 |
| Full-text Index | Y (tsvector, tsquery) | Y |
| Rerank | DIY | RRF, custom |
| SQL | Y | N (Enterprise only) |
| Data handling | ORM | SDK, Arrow, Polars |
MinIO Integration
LanceDB에서 MinIO(AWS S3)를 연결하는 예제를 만들어보았다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
services:
minio:
container_name: minio
hostname: minio
image: minio/minio
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio123
MINIO_DOMAIN: minio
command: server /data --console-address ":9001"
healthcheck:
test: "mc ready local"
interval: 10s
retries: 3
start_period: 5s
minio-client:
container_name: minio-client
hostname: minio-client
image: minio/mc
entrypoint: >
/bin/bash -c "
mc config --quiet host add storage http://minio:9000 minio minio123 || true;
mc mb --quiet --ignore-existing storage/lance || true;
"
environment:
AWS_ACCESS_KEY_ID: minio
AWS_SECRET_ACCESS_KEY: minio123
S3_ENDPOINT: http://minio:9000
S3_PATH_STYLE_ACCESS: true
depends_on:
minio:
condition: service_healthy
Docker를 이용해 MinIO를 실행한 후, Access Keys를 발급받는다. 이후 LanceDB와 연결할 때, 버킷 URI와 storage config를 입력하면 파일이 MinIO와 동기화된다.
1
2
3
4
5
6
7
8
9
10
11
import lancedb
db = lancedb.connect(
uri="s3://lance",
storage_options={
"aws_endpoint": "http://localhost:9000",
"aws_access_key_id": "",
"aws_secret_access_key": "",
"allow_http": "True",
}
)
그런 다음 pyarrow 혹은 pydantic을 이용해 스키마를 정의하고 테이블을 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pyarrow as pa
schema = pa.schema(
[
pa.field("doc_id", pa.uuid()),
pa.field("doc_type", pa.string()),
pa.field("title", pa.string()),
pa.field("searchable_text", pa.string()),
pa.field("embedding", pa.list_(pa.float32(), 128)),
]
)
table_name = "documents"
try:
table = db.open_table(table_name)
except ValueError:
table = db.create_table(
table_name,
schema=schema,
mode="overwrite"
)
가짜 데이터를 집어넣은 후,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
data = [
{
"doc_id": f"{i}",
"doc_type": "table",
"title": "Orders table",
"searchable_text": "table sales.orders columns: id, customer_id, status, total_amount, created_at",
"embedding": np.random.random(128),
}
for i in range(256)
]
table.add(data)
Vector Index와 FTS Index를 생성해두면
1
2
3
4
5
6
7
8
9
10
11
table.create_index(
metric="cosine",
vector_column_name="embedding",
index_type="IVF_PQ",
replace=True,
)
table.create_fts_index(
field_names="searchable_text",
replace=True,
)
Hybrid Search를 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from lancedb.rerankers import RRFReranker
reranker = RRFReranker()
query = "total amount"
query_vector = np.random.random(128)
results = (
table.search(query_type="hybrid")
.vector(query_vector)
.text(query)
.rerank(reranker)
.limit(5)
.to_pandas()
)
print(results)