向量数据库之Lancedb学习记载

打印 上一主题 下一主题

主题 673|帖子 673|积分 2019

简介

Lancedb是一个用于人工智能的开源矢量数据库,旨在存储、管理、查询和检索大规模多模式数据的嵌入。Lancedb的核心是用Rust编写的,并构建在Lance之上,专为高性能 ML 工作负载和快速随机访问而设计。
快速开始

安装

  1. pip install lancedb
复制代码
现在0.6.8必要pyarrow-12.0.0及以上,亲测15.0会报错。
创建客户端

  1. import lancedb
  2. import pandas as pd
  3. import pyarrow as pa
  4. uri = "data/sample-lancedb"
  5. db = lancedb.connect(uri)   
  6. # 异步客户端
  7. #async_db = await lancedb.connect_async(uri)   
复制代码
与Chroma不同,lancedb没有服务端-客户端模式。支持同步和异步客户端,看起来异步客户端更新较快,从官方文档来看没发现使用上的区别。
创建一张表

  1. data = [
  2.     {"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
  3.     {"vector": [5.9, 26.5], "item": "bar", "price": 20.0},
  4. ]
  5. tbl = db.create_table("my_table", data=data)
复制代码
假如表名已经存在,则会报错。假如盼望覆盖已经创建的同名表,可以添加mode='overwrite’参数。
  1. tbl = db.create_table("my_table", data=data, mode='overwrite')
复制代码
假如不盼望覆盖已经创建的同名表,而直接打开的话,可以添加exist_ok=True参数。
  1. tbl = db.create_table("my_table", data=data, exist_ok=True)
复制代码
创建一张空表

  1. schema = pa.schema([pa.field("vector", pa.list_(pa.float32(), list_size=2))])
  2. tbl = db.create_table("empty_table", schema=schema)
复制代码
类似SQL语法,先创建一张空表,插入数据可以放到反面举行。
添加数据

  1. # 直接添加数据
  2. data = [
  3.     {"vector": [1.3, 1.4], "item": "fizz", "price": 100.0},
  4.     {"vector": [9.5, 56.2], "item": "buzz", "price": 200.0},
  5. ]
  6. tbl.add(data)
  7. # 添加df数据帧
  8. df = pd.DataFrame(data)
  9. tbl.add(data)
复制代码
查找数据

  1. # Synchronous client
  2. tbl.search([100, 100]).limit(2).to_pandas()
复制代码
通过向量来查找相似的向量。默认情况下没有对向量创建索引,因此是全表暴力检索。官方保举数据量凌驾50万以上才必要创建索引,否则全表暴力检索的延迟也在可以接受的范围之内。(明显就是没实现,还说的冠冕堂皇。。)
删除数据

  1. tbl.delete('item = "fizz"')
复制代码
类似SQL语法中的WHERE声明,必要指定字段和对应的值。
修改数据

  1. table.update(where='item = "fizz"', values={"vector": [10, 10]})
复制代码
类似SQL语法中的UPDATE声明,必要指定字段和对应的值。
删除表

  1. db.drop_table("my_table")
复制代码
查看全部表

  1. print(db.table_names())
  2. tbl = db.open_table("my_table")   
复制代码
table_names可以返回该数据库中已经创建的全部表,使用open_table可以打开对应的表。
高级用法

数据范例

多种数据范例

除了直接添加数据和添加df数据帧之外,lancedb还支持用pyarrow创建schema和添加数据。
  1. import pyarrow as pa
  2. schema = pa.schema(
  3.     [
  4.         pa.field("vector", pa.list_(pa.float16(), 2)),
  5.         pa.field("text", pa.string())
  6.     ]
  7. )   
复制代码
lancedb直接float16数据范例,这就比chromadb有存储上风了。
自定义数据范例

  1. from lancedb.pydantic import Vector, LanceModel
  2. class Content(LanceModel):
  3.     movie_id: int
  4.     vector: Vector(128)
  5.     genres: str
  6.     title: str
  7.     imdb_id: int
  8.     @property
  9.     def imdb_url(self) -> str:
  10.         return f"https://www.imdb.com/title/tt{self.imdb_id}"   
复制代码
LanceModel是pydantic.BaseModel的子类,重要就是实现了Vector数据范例的定义,避免手动创建schema中vector的定义,只必要指定维度即可。
复合数据范例

  1. class Document(BaseModel):
  2.     content: str
  3.     source: str
  4.    
  5. class NestedSchema(LanceModel):
  6.     id: str
  7.     vector: Vector(1536)
  8.     document: Document
  9. tbl = db.create_table("nested_table", schema=NestedSchema, mode="overwrite")
复制代码
索引

创建IVF_PQ索引

  1. tbl.create_index(num_partitions=256, num_sub_vectors=96)
复制代码
lancedb支持创建倒排索引的乘积量化。num_partitions是索引中的分区数,默认值是行数的平方根。num_sub_vectors是子向量的数量,默认值是向量的维度除以16。
使用GPU创建

  1. accelerator="cuda"
  2. # accelerator="mps"
复制代码
支持CUDA的GPU大概Apple的MPS加速
使用索引加速近似查找

  1. tbl.search(np.random.random((1536))) \
  2. .limit(2) \
  3. .nprobes(20) \
  4. .refine_factor(10) \
  5. .to_pandas()
复制代码
nprobes是探针数量,默认为20,增长探针数量则会进步查找的精度并相应增长计算耗时。refine_factor是一个粗召的数量,用于读取额外元素并重新排列,以此来进步召回。
向量化模子

内置向量模子

  1. import lancedb
  2. from lancedb.pydantic import LanceModel, Vector
  3. from lancedb.embeddings import get_registry
  4. model = get_registry().get("sentence-transformers").create(name="BAAI/bge-small-en-v1.5", device="cpu")
  5. class Words(LanceModel):
  6.     text: str = model.SourceField() # 指定这个字段为需要模型进行向量化的字段
  7.     vector: Vector(model.ndims()) = model.VectorField() # 指定这个字段为模型向量化的结果
  8. table = db.create_table("words", schema=Words)
  9. table.add(
  10.     [
  11.         {"text": "hello world"},
  12.         {"text": "goodbye world"}
  13.     ]
  14. )
  15. query = "greetings"
  16. actual = table.search(query).limit(1).to_pydantic(Words)[0]
  17. print(actual.text)
复制代码
官方支持了多种sentence-transformers的向量化模子。用上述方法调用内置模子必要指定模子的SourceField和VectorField。
自定义向量模子

  1. from lancedb.embeddings import register
  2. from lancedb.util import attempt_import_or_raise
  3. @register("sentence-transformers")
  4. class SentenceTransformerEmbeddings(TextEmbeddingFunction):
  5.     name: str = "all-MiniLM-L6-v2"
  6.     # set more default instance vars like device, etc.
  7.     def __init__(self, **kwargs):
  8.         super().__init__(**kwargs)
  9.         self._ndims = None
  10.     def generate_embeddings(self, texts):
  11.         return self._embedding_model().encode(list(texts), ...).tolist()
  12.     def ndims(self):
  13.         if self._ndims is None:
  14.             self._ndims = len(self.generate_embeddings("foo")[0])
  15.         return self._ndims
  16.     @cached(cache={})
  17.     def _embedding_model(self):
  18.         return sentence_transformers.SentenceTransformer(name)
复制代码
  1. from lancedb.pydantic import LanceModel, Vector
  2. registry = EmbeddingFunctionRegistry.get_instance()
  3. stransformer = registry.get("sentence-transformers").create()
  4. class TextModelSchema(LanceModel):
  5.     vector: Vector(stransformer.ndims) = stransformer.VectorField()
  6.     text: str = stransformer.SourceField()
  7. tbl = db.create_table("table", schema=TextModelSchema)
  8. tbl.add(pd.DataFrame({"text": ["halo", "world"]}))
  9. result = tbl.search("world").limit(5)
复制代码
官方提供了模板用于自定义模子,但是我觉得直接调用模子举行向量化表现更直接吧,如许感觉有点寻求格式化的同一了。
总结

与Chromadb对比,没有服务端模式,全部在客户端完成,固然官方声称有云原生的版本,但感觉大部分场景下可能都不必要放在云上,感觉这一款产物会更加轻量化。
此外,创建表的时候没有默认的向量化模子,感觉对开发者可能更加灵活一些,相比之下Chromadb默认会从HuggingFace下载模子,对于内网环境不太友好。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表