4. 基础 CRUD 操作
4.1 创建和获取 Collection
import { ChromaClient } from 'chromadb'
const client = new ChromaClient({ path: 'http://localhost:8000' })
// 创建 Collection(已存在则报错)
const collection = await client.createCollection({
name: 'my_docs',
metadata: {
'hnsw:space': 'cosine', // 使用余弦距离(推荐)
description: '产品文档知识库', // 自定义描述,方便管理
},
})
// 获取已有 Collection(不存在则报错)
const existing = await client.getCollection({ name: 'my_docs' })
// 获取或创建(最常用,不用判断是否存在)
const safe = await client.getOrCreateCollection({
name: 'my_docs',
metadata: { 'hnsw:space': 'cosine' },
})
// 列出所有 Collection
const allCollections = await client.listCollections()
console.log(allCollections) // ['my_docs', 'user_feedback', ...]
// 删除 Collection(谨慎!数据会全部删除)
await client.deleteCollection({ name: 'old_collection' })
4.2 添加数据
安装向量函数库:
添加数据的时候我们一般需要指定向量(embeddings),如不指定,让Chroma通过向量函数(embeddingFunction)自动生成也是可以的。这个时候我们就要配置向量函数,比如我们可以使用:@chroma-core/default-embed 这个库:
npm install @chroma-core/default-embed
这个库很好安装,但是国内用起来还是有点小麻烦的,这个库首次使用的时候会下载all-MiniLM-L6-v2模型,问题就出在这,国内的网络很可能下载不下来。这时候就需要使用代理,不过就算你的电脑上已经装了代理工具,但是代码运行时好像一直用不上代理,还是会出现网络问题。我尝试了多个方法,这种方法可以解决问题:
-
安装
undici库npm uninstall undici注意,要根据您的nodejs版本来选择
undici库,比如:npm uninstall undici@5 -
编写使用代理的代码并运行
import { setGlobalDispatcher, ProxyAgent } from 'undici' setGlobalDispatcher(new ProxyAgent('http://127.0.0.1:7890')) import { ChromaClient } from 'chromadb' import { DefaultEmbeddingFunction } from '@chroma-core/default-embed' const embedder = new DefaultEmbeddingFunction(); embedder.generate(['test']) // 触发下载执行上面的代码,就会自动下载
all-MiniLM-L6-v2模型,等下再完毕,这段代码就没啥用了,undici库也没什么用了,都可以移除。
添加数据的操作
import { ChromaClient } from 'chromadb'
import { DefaultEmbeddingFunction } from '@chroma-core/default-embed'
// 创建一个本地、免费、无需外部API的文本向量化函数
const embedder = new DefaultEmbeddingFunction();
// 生成密码
const auth = Buffer.from("admin:123456").toString("base64");
const client = new ChromaClient({
ssl: false,
host: '192.168.31.249',
port: 7777,
headers: { Authorization: `Basic ${auth}` },
});
async function main() {
// 创建连接的时候,指定向量函数
const collection = await client.getCollection({ name: 'my_docs', embeddingFunction: embedder });
// 批量添加(推荐,减少网络请求次数)
await collection.add({
ids: ['doc_001', 'doc_002', 'doc_003'],
documents: [
'量子纠缠是两个粒子之间的神秘关联,无论相距多远都能瞬间影响彼此。',
'薛定谔的猫是一个著名的思想实验,用来说明量子叠加态的概念。',
'波粒二象性表明光既是波又是粒子,取决于观测方式。',
],
metadatas: [
{ source: '量子力学.pdf', chapter: '第一章', page: 1 },
{ source: '量子力学.pdf', chapter: '第二章', page: 15 },
{ source: '量子力学.pdf', chapter: '第二章', page: 18 },
],
// 如果不传 embeddings,Chroma 会用配置的 embedding 函数自动计算
});
console.log('添加成功,当前数据量:', await collection.count())
}
main()
如果我们插入的文档的id是相同的,那么会跳过插入。如果我们想插入时候遇到想通的id就更新,可以使用upsert(),
// 存在就更新,不存在就插入
await collection.upsert({
ids: ['doc_003'],
documents: ['中国人民万岁'],
metadatas: [
{ source: '测试文档.pdf', chapter: '第一章', page: 1 },
],
});
console.log('添加成功,当前数据量:', await collection.count())
const existing = await collection.get({ ids: ['doc_003'] });
console.log(existing);
4.3 查询数据
按照 id 进行查询
// 按 ID 精确获取
const result = await collection.get({
ids: ['doc_001', 'doc_002'],
include: ['documents', 'metadatas', 'embeddings'],
// include 控制返回哪些字段,embeddings 比较大,按需返回
})
console.log(result.ids) // ['doc_001', 'doc_002']
console.log(result.documents) // ['量子纠缠是...', '薛定谔的猫是...']
console.log(result.metadatas) // [{source: '...', ...}, ...]
根据 metadata 条件过滤
const collection = await client.getCollection({ name: 'my_docs' });
const result = await collection.get({
// 设置查询条件
where: { chapter: '第二章' }
});
console.log(result);
const result = await collection.get({
where: {
page: { '$gt': 10 } // page > 10
}
});
// 多条件组合(and)
const result = await collection.get({
where: {
'$and': [
{ source: '量子力学.pdf' },
{ page: { '$gte': 15 } }
]
}
});
支持的操作符:$eq、$ne、$gt、$gte、$lt、$lte、$in、$nin,逻辑组合用 $and、$or。
根据文档内容过滤
const result = await collection.get({
whereDocument: { '$contains': '量子' }
});
console.log(result);
语义相似度查询(最常用,向量检索的核心)
// 用文本查询,会自动转成向量再做相似度搜索
const result = await collection.query({
queryTexts: ['什么是量子纠缠'],
nResults: 2, // 返回最相似的2条
})
console.log(result);
组合使用(最强大):相似度 + metadata 过滤
const result = await collection.query({
queryTexts: ['量子物理相关内容'],
nResults: 5,
where: { source: '量子力学.pdf' }, // 先按条件过滤
whereDocument: { '$contains': '粒子' } // 再按文本过滤
});
console.log(result);
分页和偏移量
| 参数 | get() |
query() |
|---|---|---|
limit |
✅ 支持 | ✅ 支持(但叫 nResults) |
offset |
✅ 支持 | ❌ 不支持 |
await collection.get({
limit: 100,
offset: 200 // 跳过前200条,取接下来100条
});
await collection.query({
queryTexts: ['量子纠缠'],
nResults: 10, // 注意:这里不叫 limit,叫 nResults
});
4.4 更新数据
// 更新已有数据(ID 必须存在,否则报错)
await collection.update({
ids: ['doc_001'],
documents: ['更新后的量子纠缠说明...'],
metadatas: [{ source: '量子力学第2版.pdf', page: 1 }],
})
// upsert:存在则更新,不存在则创建(最安全的写法)
await collection.upsert({
ids: ['doc_001', 'doc_new'],
documents: ['量子纠缠更新版', '全新的文档内容'],
metadatas: [
{ source: '量子力学第2版.pdf' },
{ source: '新文件.pdf' },
],
})
chroma 只能支持根据id更新,对于不知道id的可以先查询出来数据,然后根据id进行更新。
4.5 删除数据
// 按 ID 删除
await collection.delete({
ids: ['doc_001', 'doc_002'],
})
// 按元数据条件删除(删除某个来源的所有数据)
await collection.delete({
where: { source: '旧文档.pdf' },
})
// 查看剩余数量
console.log('剩余:', await collection.count())
4.6 纯内存模式(测试用)
import { ChromaClient } from 'chromadb'
// 不传 path,使用内存模式,无需启动服务端
// 注意:重启后数据全部丢失,只适合单元测试
const memoryClient = new ChromaClient()
const testCollection = await memoryClient.createCollection({
name: 'test',
})
💬 评论 0
还没有评论,快来抢沙发吧~