LanceDB是一个开源的用 Rust 实现的向量数据库(https://github.com/lancedb/lancedb),它的主要特点是:
pip install lancedb
预览版本:
pip install --pre --extra-index-url https://pypi.fury.io/lancedb/ lancedb
创建数据库:
import lancedb
db = lancedb.connect("./test") # 如果数据库不存在,会自动创建
打开数据库:
db = lancedb.open("./test") # 如果数据库不存在,会报错
data = [
{"vector": [1, 2], "text": "hello"},
{"vector": [3, 4], "text": "world"},
]
table = db.create_table("my_table", data=data, mode="overwrite")
df = pd.DataFrame(data)
table = db.create_table("my_table", data=df, mode="overwrite")
print(db.table_names())
data = [
{"vector": [1, 2], "text": "hello"},
{"vector": [3, 4], "text": "world"},
]
table.add(data)
通过向量查询数据:
query = [1, 2]
results = table.search(query).limit(1).to_pandas()
通过文本查询数据:
query = "hello"
results = table.search(query).limit(1).to_pandas()
table.create_index()
LanceDB 不会自动创建索引,对于数据量较大的情况下,建议手动创建,否则会走全文检索(速度会比较慢)。
table.delete(f'text = "hello"')
删除数据当然也支持 SQL 语法,具体参考官方文档(https://lancedb.github.io/lancedb/sql/#pre-and-post-filtering)。
db.drop_table("my_table")
注意:如果表不存在,会报错,可以通过传入参数忽略错误 ignore_missing=True
。
向量搜索是一种在高维空间中搜索向量的方法,主要是将原始数据通过嵌入模型得到向量,然后通过向量相似度算法计算向量之间的距离,从而找到最相似的向量。
embedding 是将原始数据通过嵌入模型得到向量的过程,嵌入模型可以是预训练的模型,也可以是自己训练的模型,是一种将文本、图像、音频等数据投影到二维空间的方法。
和关系型数据库一样,向量数据库也需要索引来加速查询,索引是一种数据结构,用于快速查找数据,LanceDB 使用基于磁盘的索引:IVF-PQ,是倒排索引的一种变体,使用PQ 来做压缩嵌入。
PQ 原理主要分为以下步骤:
通过以上的处理,原来 1024 维度向量*float类型(1024 * 4 字节)被压缩到 64 个字节,大大减少了存储空间和计算量,当然量化是有损的,所以对于数据量不大的情况,可以不使用索引,直接暴力搜索。
HNSW 是一种基于图的搜索方法,使用图结构来存储向量,然后通过图的搜索来找到最相似的向量,原理类似跳跃表,通过分层的 k-ANN 图来实现递归搜索。
LanceDB 创建 HNSW 索引样例:
data = [
{"vector": row, "item": f"item {i}"}
for i, row in enumerate(np.random.random((10_000, 1536)).astype('float32'))
]
tbl = db.create_table("my_vectors", data=data)
tbl.create_index(index_type=IVF_HNSW_SQ)
import pandas as pd
import lancedb
import numpy as np
db = lancedb.connect("./test")
table = db.create_table("my_table", data=[], mode="overwrite")
df = pd.DataFrame({
"vector": [np.random.rand(100) for _ in range(100)],
"text": [f"hello {i}" for i in range(100)],
})
table.add(df)
import pyarrow as pa
import lancedb
import numpy as np
db = lancedb.connect("./test")
table = db.create_table("my_table", data=[], mode="overwrite")
table = db.create_table("my_table", data=pa.Table.from_pandas(df), mode="overwrite")
import lancedb
from lancedb.pydantic import LanceModel
class MyModel(LanceModel):
vector: list[float]
text: str
db = lancedb.connect("./test")
table = db.create_table("my_table", schema=MyModel, mode="overwrite")
model = MyModel(vector=[1, 2], text="hello")
table.add(model)
import lancedb
import pyarrow as pa
def make_batches():
for i in range(1000):
yield pa.Table.from_pandas(pd.DataFrame({
"vector": [np.random.rand(100) for _ in range(100)],
"text": [f"hello {i}"for i in range(100)],
}))
schema = pa.schema(
[
pa.field("vector", pa.list_(pa.float32(), 4)),
pa.field("item", pa.utf8()),
]
)
db = lancedb.connect("./test")
table = db.create_table("my_table", make_batches(), schema=schema, mode="overwrite")
或者通过迭代器写入数据:
import lancedb
import pyarrow as pa
def make_batches():
for i in range(1000):
yield pa.Table.from_pandas(pd.DataFrame({
"vector": [np.random.rand(100) for _ in range(100)],
"text": [f"hello {i}" for i in range(100)],
}))
db = lancedb.connect("./test")
table = db.create_table("my_table", data=[], mode="overwrite")
table.add(make_batches())
db = lancedb.connect("./test")
data = [
{"x": 1, "vector": [1, 2]},
{"x": 2, "vector": [3, 4]},
{"x": 3, "vector": [5, 6]},
]
# Synchronous client
table = db.create_table("delete_row", data)
table.to_pandas()
# x vector
# 0 1 [1.0, 2.0]
# 1 2 [3.0, 4.0]
# 2 3 [5.0, 6.0]
table.delete("x = 2")
table.to_pandas()
# x vector
# 0 1 [1.0, 2.0]
# 1 3 [5.0, 6.0]
db = lancedb.connect("./test")
data = [
{"x": 1, "vector": [1, 2]},
{"x": 2, "vector": [3, 4]},
{"x": 3, "vector": [5, 6]},
]
# Synchronous client
table = db.create_table("update_row", data)
table.update(where="x = 2", values={"vector": [10, 10]})
由于 lancedb 是嵌入到各个应用中,所以数据更新并不能保持一致,可以通过设置 read_consistency_interval
参数来保证数据更新的一致性。
read_consistency_interval
是一个时间间隔,单位是秒。
from datetime import timedelta
uri = "data/sample-lancedb"
# 保障数据最终一致性
db = lancedb.connect(uri, read_consistency_interval=timedelta(seconds=5))
tbl = db.open_table("test_table")
import lancedb
import numpy as np
db = lancedb.connect("./test")
data = [
{"vector": row, "item": f"item {i}"}
for i, row in enumerate(np.random.random((10_000, 1536)).astype('float32'))
]
tbl = db.create_table("my_vectors", data=data)
tbl.create_index(distance_type='l2', num_partitions=2, num_sub_vectors=4)
如果需要通过 CUDA 加速,可以增加参数:
tbl.create_index(distance_type='l2', num_partitions=2, num_sub_vectors=4, accelerator='cuda')
1)kNN 搜索: 不建立索引,就会扫描全表,计算每个向量的距离,然后返回最相似的 k 个向量,也可以指定距离度量算法。
query = np.random.random(1536).astype('float32')
results = tbl.search(query).limit(10).distance_type("cosine").to_pandas()
2)ANN 搜索: 通过索引搜索,支持 nprobes 和 refine_factor 参数。
query = np.random.random(1536).astype('float32')
tbl.search(query).limit(2).nprobes(20).refine_factor(
10
).to_pandas()
3)基于距离范围搜索: 主要用于不通过topk 查询,而是通过距离范围查询。
query = np.random.random(1536).astype('float32')
tbl.search(query).distance_range(0.1, 0.5).to_pandas()
4)全文搜索: 如果需要对字符串进行索引,并通过关键字搜索进行查询,可以通过创建 FTS 索引。
from lancedb.index import FTS
tbl = db.create_table("my_vectors", data=[
{"vector": np.rand.random(10), "item": f"this item {i}"}
{"vector": np.rand.random(10), "item": f"this item {i + 100}"}
])
tbl.create_fts_index("text", use_tantivy=False)
tbl.search("this item 10").limit(10).select(["item"]).to_pandas()
5)过滤搜索: 通过 SQL 语法进行过滤搜索。
tbl.search("this item 10").limit(10).where("item='this'", prefilter=True).to_pandas()
LanceDB 支持 SQL 语法如下:
>, <, >=, <=
AND, OR, NOT
IS NULL, IS NOT NULL
IS TRUE, IS FALSE
IN
LIKE, NOT LIKE
CAST
regexp_match(column, pattern)
样例如下:
table.search("this item 10").where(
"(item IN ('item 0', 'item 2')) AND (id > 10)"
).to_arrow()
LanceDB 支持结合 embedding 模型进行搜索。
import lancedb
from lancedb.pydantic import LanceModel, Vector
from lancedb.embeddings import get_registry
db = lancedb.connect("./test")
func = get_registry().get("openai").create(name="text-embedding-ada-002")
class Words(LanceModel):
text: str = func.SourceField()
vector: Vector(func.ndims()) = func.VectorField()
table = db.create_table("words", schema=Words, mode="overwrite")
table.add(
[
{"text": "hello world"},
{"text": "goodbye world"}
]
)
query = "greetings"
actual = table.search(query).limit(1).to_pydantic(Words)[0]
print(actual.text)
通过 get_registry() 注册不同的模型参数,其中支持的代码如下:
get_registry().get("sentence-transformers").create(name="BAAI/bge-small-en-v1.5", device="cpu")
get_registry().get("huggingface").create(name='facebook/bart-base')
get_registry().get("ollama").create(name="nomic-embed-text")
get_registry().get("openai").create(name="text-embedding-ada-002")
et_registry().get("instructor").create(source_instruction="represent the docuement for retreival", query_instruction="represent the document for retreiving the most similar documents")
get_registry().get("gemini-text").create()
get_registry().get("open-clip").create()
get_registry().get("imagebind").create()
...1)注册 embedding 函数
from lancedb.embeddings import get_registry
registry = get_registry()
clip = registry.get("open-clip").create()
2)定义数据模型
from lancedb.pydantic import LanceModel, Vector
from typing import List
class Document(LanceModel):
id: str
vector: Vector(clip.ndims()) = clip.VectorField()
image_uri: str = clip.SourceField()
3)创建表并添加数据
db = lancedb.connect("~/lancedb")
table = db.create_table("pets", schema=Pets)
table.add([{"image_uri": u} for u in uris])
4)查询数据
results = (
table.search("dog")
.limit(10)
.to_pandas()
)
(1)https://lancedb.github.io/lancedb/ (2)https://excalidraw-phi-woad.vercel.app/
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有