尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LanceSchema 实战指南:在 @lancedb/lancedb 中用声明式 Schema 集成 Embedding 函数

LanceSchema 实战指南:在 @lancedb/lancedb 中用声明式 Schema 集成 Embedding 函数 向量数据库数据库人工智能后端【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址https://gitcode.com/gh_mirrors/la/lancedb点击查看免费下载LanceSchema()是lancedb/lancedbNode.js 客户端embedding命名空间提供的核心工厂函数用于在创建表时以声明式方式声明源字段 向量字段 Embedding 函数的映射关系。通过它你可以在建表的同时绑定文本列与向量列写入数据时自动生成 embedding查询时自动为搜索词编码向量从而省去手动调用 embedding 模型、维护两套数据的繁琐工作。读完本文你将掌握LanceSchema的完整用法、sourceField/vectorField的参数细节、内部实现原理以及如何将其与内建或自定义的 Embedding 函数配合落地到真实项目。LanceSchema 是什么在lancedb/lancedb中LanceSchema是一个接收字段定义、返回 Apache ArrowSchema对象的函数function LanceSchema(fields: Record string, object | [object, Mapstring, EmbeddingFunction] ): Schema其签名与普通 ArrowSchema构造器的最大区别在于每个字段的值可以是两种形态之一普通的 Arrow 数据类型对象例如new Int32()、new Utf8()此时该字段就是一个普通列一个二元组[DataType, Mapstring, EmbeddingFunction]其中Map携带了 embedding 函数的绑定信息。这种元组正是由EmbeddingFunction实例的sourceField()与vectorField()方法产生的。LanceDB 官方为LanceSchema提供的核心示例见 embedding 命名空间文档 与 index.ts 源码注释如下class MyEmbeddingFunction extends EmbeddingFunction { // ... } const func new MyEmbeddingFunction(); const schema LanceSchema({ id: new Int32(), text: func.sourceField(new Utf8()), vector: func.vectorField(), // 可选显式指定数据类型和/或维度 vector2: func.vectorField({ datatype: new Float32(), dims: 3 }), }); const table await db.createTable(my_table, data, { schema });建表时把schema作为createTable的选项传入LanceDB 就会把text列当作源列、vector/vector2列当作向量列并自动用MyEmbeddingFunction完成双向的向量编解码。两个核心方法sourceField 与 vectorFieldLanceSchema本身不做 embedding 计算真正的绑定逻辑来自EmbeddingFunction基类 上的两个辅助方法。sourceField声明源字段sourceField( optionsOrDatatype: PartialFieldOptions | DataType, ): [DataType, Mapstring, EmbeddingFunction]sourceField用于声明哪个列是 embedding 的输入源。它接收一个 Arrow 数据类型或带datatype选项的对象返回一个[数据类型, 元数据 Map]元组其中Map内部被标记为source_column_for实现见 embedding_function.ts// 文本列显式指定 Utf8 text: func.sourceField(new Utf8()), // 也支持结构化选项写法 text: func.sourceField({ datatype: new Utf8() }),传入的 datatype 会被sanitizeType做规范化处理若未提供 datatype会直接抛出Datatype is required错误。对于TextEmbeddingFunction文本型 embedding 函数的基类sourceField被重写为默认使用new Utf8()实现见 embedding_function.ts所以调用时可以省略参数text: sentenceTransformer.sourceField(), // 等价于 sourceField(new Utf8())vectorField声明向量字段vectorField( optionsOrDatatype?: PartialFieldOptions | DataType, ): [DataType, Mapstring, EmbeddingFunction]vectorField用于声明哪个列存放 embedding 输出的向量内部标记为vector_column_for。它的维度与类型解析规则实现见 embedding_function.ts非常灵活支持四种写法// 1. 无参数默认 Float32维度取 func.ndims() vector: func.vectorField(), // 2. 只指定数据类型必须是 Float 类型或 FixedSizeList vector: func.vectorField(new Float32()), vector: func.vectorField(new Float64()), // 3. 结构化选项显式指定 datatype 与 dims vector: func.vectorField({ datatype: new Float32(), dims: 3 }), // 4. 直接传入 FixedSizeList 向量类型 vector: func.vectorField( new FixedSizeList(3, new Field(item, new Float32(), true)), ), vector: func.vectorField({ datatype: new FixedSizeList(3, new Field(item, new Float32(), true)), dims: 3, }),解析逻辑可以概括为未传参datatype 默认为Float32最终会通过newVectorType(dims, dtype)构造成FixedSizeList向量列传入 Float 类型维度优先取ndims()embedding 函数声明的输出维度若ndims()未实现且没有通过{ dims: n }显式指定则抛出ndims is required for vector field传入FixedSizeList直接采用该类型作为向量列类型无需再提供维度传入其他类型抛出Expected FixedSizeList or Float as datatype for vector field。也就是说只要你的 embedding 函数实现了ndims()最简单的func.vectorField()一行即可获得类型正确的向量列否则必须通过{ datatype, dims }或FixedSizeList显式声明。深入实现LanceSchema 内部做了什么LanceSchema的完整实现位于 nodejs/lancedb/embedding/index.ts整个流程可以拆解为四步第一步遍历字段定义区分普通列与 embedding 绑定列。Object.entries(fields).forEach(([key, value]) { if (Array.isArray(value)) { const [dtype, metadata] value as [object, Mapstring, EmbeddingFunction]; arrowFields.push(new Field(key, sanitizeType(dtype), true)); parseEmbeddingFunctions(embeddingFunctions, key, metadata); } else { arrowFields.push(new Field(key, sanitizeType(value), true)); } });所有字段都会被规范化为 ArrowField并且默认 nullable 为true。凡是被数组元组包裹的字段还会额外进入 embedding 绑定解析流程。第二步把字段级元数据归并为函数级配置。parseEmbeddingFunctions见 index.ts检查元数据Map中的标记命中source_column_for把当前字段名记录为该函数的sourceColumn命中vector_column_for把当前字段名记录为该函数的vectorColumn。同一个函数实例可能同时在多个字段上出现例如sourceField与vectorField各自携带同一个函数引用最终会合并成一个完整的EmbeddingFunctionConfig{ sourceColumn, vectorColumn, function }。这也意味着一个 embedding 函数可以对应多个向量列测试用例parses one function writing several vector columns见 embedding.test.ts验证了这种一对多的能力。第三步把函数配置序列化为 schema 元数据。const registry getRegistry(); const metadata registry.getTableMetadata( Array.from(embeddingFunctions.values()) as EmbeddingFunctionConfig[], ); const schema new Schema(arrowFields, metadata);getTableMetadata见 registry.ts会把每个函数序列化为{ sourceColumn, vectorColumn, name, model }形式的 JSON写入 schema 元数据的embedding_functions键。model来自函数实例的toJSON()默认返回构造函数收到的原始配置见 embedding_function.ts保证函数配置可以被持久化并在后续会话中重建。第四步返回携带元数据的 Arrow Schema。建表后表的 schema 中始终带有embedding_functions元数据测试 embedding.test.ts 通过table.schema().metadata.get(embedding_functions)断言了这一点。后续无论是追加数据还是打开既有表LanceDB 都能依据这份元数据自动调用对应函数写入时用computeSourceEmbeddings批量编码查询时用computeQueryEmbeddings编码搜索词实现见 embedding_function.ts。值得一提的是元数据解析器parseEmbeddingMetadata同时兼容sourceColumn/source_column两种键名拼写——因为 Python 绑定写入的是 snake_case而 JS 侧使用 camelCase统一解析保证跨语言的数据可以互通。实战一与内建 Embedding 函数配合lancedb/lancedb内置了openai与huggingface基于 transformers.js两个 embedding 提供方在首次调用getRegistry()时注册见 index.ts。使用内置函数的完整流程如下来自 sentence-transformers.test.ts 的真实用例import * as lancedb from lancedb/lancedb; import lancedb/lancedb/embedding/transformers; import { LanceSchema, getRegistry } from lancedb/lancedb/embedding; import type { EmbeddingFunction } from lancedb/lancedb/embedding; import { Utf8 } from apache-arrow; const db await lancedb.connect(databaseDir); // 1. 从注册表创建内建函数实例 const func (await getRegistry() .get(huggingface) ?.create()) as EmbeddingFunction; // 2. 用 LanceSchema 声明 schema const factsSchema LanceSchema({ text: func.sourceField(new Utf8()), vector: func.vectorField(), }); // 3. 建表写入原始文本即可向量自动生成 const tbl await db.createTable(facts, facts, { mode: overwrite, schema: factsSchema, }); // 4. 直接传文本搜索查询向量自动编码 const actual await tbl.search(How many bones are in the human body?) .limit(1).toArray();OpenAI 函数的用法类似只需getRegistry().get(openai).create({ model: text-embedding-ada-002, apiKey: ... })。注意使用内建函数需要导入对应的副作用模块如lancedb/lancedb/embedding/transformers以触发注册这一点在示例中通过import lancedb/lancedb/embedding/transformers完成。实战二自定义 Embedding 函数当内建函数不满足需求时可以继承TextEmbeddingFunction文本输入或EmbeddingFunction任意输入用register()装饰器注册后配合LanceSchema使用。完整的自定义实现来自 custom_embedding_function.test.tsimport { LanceSchema, TextEmbeddingFunction, getRegistry, register } from lancedb/lancedb/embedding; register(sentence-transformers) class SentenceTransformersEmbeddings extends TextEmbeddingFunction { name Xenova/all-miniLM-L6-v2; #ndims!: number; extractor!: FeatureExtractionPipeline; async init() { this.extractor await pipeline(feature-extraction, this.name, { dtype: fp32, }); this.#ndims await this.generateEmbeddings([hello]).then( (e) e[0].length, ); } ndims() { return this.#ndims; } toJSON() { return { name: this.name }; } async generateEmbeddings(texts: string[]) { const output await this.extractor(texts, { pooling: mean, normalize: true, }); return output.tolist(); } } // 从注册表创建实例 const sentenceTransformer await getRegistry() .getSentenceTransformersEmbeddings(sentence-transformers)! .create(); // 配合 LanceSchema 使用 const schema LanceSchema({ vector: sentenceTransformer.vectorField(), text: sentenceTransformer.sourceField(), }); const db await lancedb.connect(databaseDir); const table await db.createEmptyTable(table, schema, { mode: overwrite, }); await table.add([{ text: hello }, { text: world }]); const results await table.search(greeting).limit(1).toArray();实现自定义函数时需要关注四个关键点ndims()返回 embedding 输出维度。实现后vectorField()无需再传dims如示例中先跑一次推理获取真实维度embeddingDataType()声明向量列的元素类型基类返回Float32见 TextEmbeddingFunction 实现generateEmbeddings(texts)批量计算文本向量init()可选在计算前加载模型等资源registry.get(name).create()会自动等待init()完成见 registry.ts。由于TextEmbeddingFunction重写了sourceField()默认使用Utf8上例中text: sentenceTransformer.sourceField()可以不带参数代码更简洁。进阶维度、类型与多向量列灵活控制向量列的数据类型测试用例 embedding.test.ts 系统验证了Float16、Float32、Float64三种浮点类型在vectorField各写法下的一致性const schema LanceSchema({ text: func.sourceField(new Utf8()), vector: func.vectorField(floatType), // 直接传类型 }); const schema2 LanceSchema({ text: func2.sourceField(new Utf8()), vector: func2.vectorField({ datatype: floatType, dims: 3 }), // 结构化选项 }); const schema3 LanceSchema({ text: func2.sourceField(new Utf8()), vector: func.vectorField({ datatype: new FixedSizeList(3, new Field(item, floatType, true)), dims: 3, }), });测试断言三种写法产出的 Arrow Schema 完全一致都是FixedSizeList(3)、元素为对应浮点类型、nullable 为true的向量列。你可以据此按存储精度与推理性能的取舍自由选择Float16/Float32/Float64。一个函数产出多个向量列LanceSchema支持同一函数绑定多个向量列例如对同一源文本投影出多个不同名称的向量视图。注册表解析时以向量列名为键组织配置见 registry.ts并通过去重检查防止两个配置抢占同一向量列名见parseEmbeddingMetadata中的重复校验。用 $var: 语法管理敏感配置embedding 函数的配置支持变量引用。通过registry.setVar(name, value)设置变量后可以在配置中使用$var:variable_name语法见 embedding_function.tsconst registry getRegistry(); registry.setVar(openai_api_key, sk-...); const func registry.get(openai)?.create({ model: text-embedding-ada-002, apiKey: $var:openai_api_key, }) as EmbeddingFunction; const wordsSchema LanceSchema({ text: func.sourceField(new Utf8()), vector: func.vectorField(), });$var:支持默认值语法$var:name:default变量名不能包含冒号。这一机制让 schema 元数据中不落盘明文密钥配合getSensitiveKeys()基类中可声明敏感键未使用$var:语法直接传入原始值时抛错实现密钥的安全管理。测试用例propagates variables through all methods见 embedding.test.ts验证了该链路。常见错误与排查结合源码与测试以下是使用LanceSchema时最容易踩的坑错误场景报错信息原因与对策vectorField()未传参且函数未实现ndims()ndims is required for vector field维度无法确定。实现ndims()或改用vectorField({ datatype, dims })显式声明vectorField传入非 Float / 非 FixedSizeList 类型Expected FixedSizeList or Float as datatype for vector field向量列只接受浮点类型或定长列表类型sourceField()未提供 datatypeDatatype is required显式传入new Utf8()等类型TextEmbeddingFunction子类除外打开表后追加数据但函数未注册Function mock not found in registry表元数据引用了注册表中不存在的函数名。需先register(mock)或用registry.register()注册同名函数对应测试 embedding.test.ts元数据中缺少 source/vector 列名Embedding function x metadata names no source or vector column手动构造的embedding_functions元数据不完整应通过LanceSchema自动生成另外注意LanceSchema构造的所有字段默认 nullable 为true写入时若源列或向量列的值为undefined/null/缺失embedding 函数会自动补算测试should handle undefined vector field验证了这一点见 embedding.test.ts。相关资源速查函数定义与实现nodejs/lancedb/embedding/index.tsEmbeddingFunction基类与sourceField/vectorFieldnodejs/lancedb/embedding/embedding_function.ts注册表、元数据序列化与$var:变量nodejs/lancedb/embedding/registry.ts官方测试含多类型、多向量列、错误路径nodejs/test/embedding.test.ts内建 huggingface 函数实战nodejs/examples/sentence-transformers.test.ts自定义 embedding 函数实战nodejs/examples/custom_embedding_function.test.ts相关类型文档EmbeddingFunction 类、FunctionOptions 接口、FieldOptions 接口、embedding 命名空间总览掌握LanceSchema后你可以把表结构声明 embedding 函数绑定收敛到一处让数据写入、查询编码、元数据持久化全链路自动化——这正是 LanceDB 声明式数据建模的核心体验。赞分享向量数据库数据库人工智能后端【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址https://gitcode.com/gh_mirrors/la/lancedb点击查看免费下载相关推荐LanceDB Node.js embedding 命名空间完全指南从 EmbeddingFunction 到 LanceSchema 的声明式向量建表LanceDB Node.js embedding 命名空间完全指南从 EmbeddingFunction 到 LanceSchema 的声明式向量建表 em向量数据库数据库人工智能后端LanceDB Node.js SDK 的 makeJsonField 指南在 Arrow Schema 中声明 JSON 扩展字段LanceDB Node.js SDK 的 makeJsonField 指南在 Arrow Schema 中声明 JSON 扩展字段 导读 本文讲解 Lanc向量数据库数据库人工智能后端LanceDB JS SDK blob() 函数实战指南声明 lance.blob.v2 大对象列并高效读取二进制数据LanceDB JS SDK blob 函数实战指南声明 lance.blob.v2 大对象列并高效读取二进制数据 导读 blob 是 LanceDB Jav向量数据库数据库人工智能后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表