惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
宝玉的分享
宝玉的分享
I
InfoQ
P
Privacy International News Feed
V
V2EX
IT之家
IT之家
S
SegmentFault 最新的问题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V2EX - 技术
V2EX - 技术
C
CERT Recently Published Vulnerability Notes
C
Check Point Blog
The Register - Security
The Register - Security
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
AWS News Blog
AWS News Blog
M
MIT News - Artificial intelligence
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
B
Blog
N
Netflix TechBlog - Medium
B
Blog RSS Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
T
Threatpost
Forbes - Security
Forbes - Security
U
Unit 42
A
Arctic Wolf
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Recorded Future
Recorded Future
L
Lohrmann on Cybersecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
月光博客
月光博客
Spread Privacy
Spread Privacy
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
I
Intezer
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
The Hacker News
The Hacker News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
LangChain Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
MyScale Blog
MyScale Blog
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位

卡卡罗特

最后代码 | 卡卡罗特 swagger文档 | 卡卡罗特 react脚手架开发 | 卡卡罗特 python的对象增强 | 卡卡罗特 langchain实现Agent | 卡卡罗特 03.python列表集合元组字典 | 卡卡罗特 python依赖打包 | 卡卡罗特 python的异步 | 卡卡罗特 python的生成器 | 卡卡罗特 eino整合Tools | 卡卡罗特 eino实现Agent | 卡卡罗特 eino整合RAG | 卡卡罗特 docker打包go服务 | 卡卡罗特 01-docker入门 | 卡卡罗特 docker-compose | 卡卡罗特 dockerfile | 卡卡罗特 linux安装docker | 卡卡罗特 hertz中间件 | 卡卡罗特 langchainjs | 卡卡罗特 ollama调用各大模型 | 卡卡罗特 spring-ai | 卡卡罗特 自定义一个MCP | 卡卡罗特 context.Context是什么? | 卡卡罗特 01-获取指定网站的所有的链接 | 卡卡罗特 01-Bing每日一图接口 | 卡卡罗特 02-腾讯API高清QQ头像https调用接口 | 卡卡罗特 openCV初体验 | 卡卡罗特 RWMutex读写锁 | 卡卡罗特 SyncMap的使用 | 卡卡罗特 defer的使用 | 卡卡罗特
go整合向量数据库ChromaDB | 卡卡罗特
2026-04-28 · via 卡卡罗特

go

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

// --- 配置和全局变量 ---
var (
	baseURL       string
	client        *http.Client
	defaultTenant = "default_tenant"
	defaultDB     = "default_database"
)

// --- 数据结构 ---
type CreateCollectionV2Req struct {
	Name     string                 `json:"name"`
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

type CreateCollectionV2Resp struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Tenant   string `json:"tenant"`
	Database string `json:"database"`
}

type AddRecordsV2Req struct {
	IDs        []string                 `json:"ids"`
	Embeddings [][]float32              `json:"embeddings"`
	Documents  []string                 `json:"documents,omitempty"`
	Metadatas  []map[string]interface{} `json:"metadatas,omitempty"`
}

type QueryV2Req struct {
	QueryEmbeddings [][]float32 `json:"query_embeddings"`
	NRResults       int         `json:"n_results"`
	Include         []string    `json:"include,omitempty"`
}

type QueryV2Resp struct {
	IDs       [][]string                 `json:"ids"`
	Documents [][]string                 `json:"documents"`
	Distances [][]float32                `json:"distances"`
	Metadatas [][]map[string]interface{} `json:"metadatas,omitempty"`
}

// 存储集合信息
var currentCollection struct {
	ID       string
	Name     string
	Tenant   string
	Database string
}

func main() {
	baseURL = "http://127.0.0.1:8000"
	client = &http.Client{Timeout: 10 * time.Second}
	fmt.Printf("🔗 连接 ChromaDB v2: %s\n", baseURL)

	// 1. 心跳检测
	if !heartbeat() {
		fmt.Println("❌ 无法连接到 ChromaDB")
		return
	}
	fmt.Println("✅ 服务连接正常")

	// 2. 获取或创建集合
	collectionName := "my-go-collection"
	if err := getOrCreateCollection(collectionName); err != nil {
		fmt.Printf("❌ 获取/创建集合失败: %v\n", err)
		return
	}
	fmt.Printf("✅ 集合已就绪,ID: %s, 名称: %s\n", currentCollection.ID, currentCollection.Name)

	// 3. 添加数据(使用完整的路径)
	if err := addData(); err != nil {
		fmt.Printf("❌ 添加数据失败: %v\n", err)
		return
	}
	fmt.Println("✅ 数据添加成功")

	// 4. 查询数据
	queryData()
}

// 心跳检测
func heartbeat() bool {
	resp, err := client.Get(baseURL + "/api/v2/heartbeat")
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	return resp.StatusCode == http.StatusOK
}

// 获取或创建集合
func getOrCreateCollection(name string) error {
	// 先尝试获取已存在的集合
	err := getCollection(name)
	if err == nil {
		fmt.Printf("📂 找到已存在的集合: %s (ID: %s)\n", name, currentCollection.ID)
		return nil
	}

	// 集合不存在,创建新集合
	fmt.Printf("📂 集合 '%s' 不存在,正在创建...\n", name)
	return createCollection(name)
}

// 获取已存在的集合
func getCollection(name string) error {
	url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections",
		baseURL, defaultTenant, defaultDB)

	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	// 解析集合列表
	var collections []CreateCollectionV2Resp
	if err := json.Unmarshal(body, &collections); err != nil {
		return err
	}

	// 查找指定名称的集合
	for _, col := range collections {
		if col.Name == name {
			currentCollection.ID = col.ID
			currentCollection.Name = col.Name
			currentCollection.Tenant = col.Tenant
			currentCollection.Database = col.Database
			return nil
		}
	}

	return fmt.Errorf("集合 '%s' 不存在", name)
}

// 创建新集合
func createCollection(name string) error {
	url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections",
		baseURL, defaultTenant, defaultDB)

	reqBody := CreateCollectionV2Req{
		Name: name,
		Metadata: map[string]interface{}{
			"description": "Go 客户端测试集合",
			"created_at":  time.Now().Format(time.RFC3339),
		},
	}

	jsonData, _ := json.Marshal(reqBody)
	fmt.Printf("📤 创建集合请求: %s\n", string(jsonData))

	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	// 解析响应获取集合信息
	var result CreateCollectionV2Resp
	if err := json.Unmarshal(body, &result); err != nil {
		return err
	}

	currentCollection.ID = result.ID
	currentCollection.Name = result.Name
	currentCollection.Tenant = result.Tenant
	currentCollection.Database = result.Database

	fmt.Printf("📥 创建成功: ID=%s, Name=%s, Tenant=%s, Database=%s\n",
		result.ID, result.Name, result.Tenant, result.Database)
	return nil
}

// 添加数据 - 使用完整的 API 路径
func addData() error {
	// 关键修正:使用完整的路径包含 tenant 和 database
	url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections/%s/add",
		baseURL,
		currentCollection.Tenant,
		currentCollection.Database,
		currentCollection.ID)

	fmt.Printf("\n📤 添加数据到集合: %s\n", currentCollection.Name)
	fmt.Printf("🔗 完整 URL: %s\n", url)

	reqBody := AddRecordsV2Req{
		IDs: []string{"doc1", "doc2"},
		Embeddings: [][]float32{
			{0.1, 0.2, 0.3, 0.4, 0.5},
			{0.6, 0.7, 0.8, 0.9, 1.0},
		},
		Documents: []string{
			"Go 语言是并发的王者",
			"ChromaDB 是一个向量数据库",
		},
		Metadatas: []map[string]interface{}{
			{"source": "go-demo", "language": "go", "type": "programming"},
			{"source": "go-demo", "topic": "database", "type": "technology"},
		},
	}

	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return err
	}

	fmt.Printf("📦 请求体: %s\n", string(jsonData))

	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	fmt.Printf("📥 响应状态: %d\n", resp.StatusCode)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	if len(body) > 0 {
		fmt.Printf("📥 响应内容: %s\n", string(body))
	}
	return nil
}

// 查询数据 - 使用完整的 API 路径
func queryData() {
	url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections/%s/query",
		baseURL,
		currentCollection.Tenant,
		currentCollection.Database,
		currentCollection.ID)

	fmt.Printf("\n🔍 查询 URL: %s\n", url)

	reqBody := QueryV2Req{
		QueryEmbeddings: [][]float32{{0.1, 0.2, 0.3, 0.4, 0.5}},
		NRResults:       3,
		Include:         []string{"documents", "distances", "metadatas"},
	}

	jsonData, _ := json.Marshal(reqBody)
	fmt.Printf("🔍 查询请求: %s\n", string(jsonData))

	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		fmt.Printf("❌ 查询失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("❌ 查询失败: HTTP %d - %s\n", resp.StatusCode, string(body))
		return
	}

	var result QueryV2Resp
	if err := json.Unmarshal(body, &result); err != nil {
		fmt.Printf("❌ 解析失败: %v\n原始响应: %s\n", err, string(body))
		return
	}

	// 显示结果
	if len(result.Documents) > 0 && len(result.Documents[0]) > 0 {
		fmt.Println("\n🎉 查询成功!找到以下结果:")
		for i, doc := range result.Documents[0] {
			distance := float32(0)
			if len(result.Distances) > 0 && len(result.Distances[0]) > i {
				distance = result.Distances[0][i]
			}

			// 显示元数据(如果有)
			metadata := ""
			if len(result.Metadatas) > 0 && len(result.Metadatas[0]) > i {
				if lang, ok := result.Metadatas[0][i]["language"]; ok {
					metadata = fmt.Sprintf(" [语言: %v]", lang)
				}
			}

			fmt.Printf("  %d.%s %s (距离: %.4f)\n", i+1, metadata, doc, distance)
		}
	} else {
		fmt.Println("\n⚠️ 未找到相关结果")
	}
}

text

🔗 连接 ChromaDB v2: http://127.0.0.1:8000
✅ 服务连接正常
📂 集合 'my-go-collection' 不存在,正在创建...
📤 创建集合请求: {"name":"my-go-collection","metadata":{"created_at":"2026-04-05T16:21:22+08:00","description":"Go 客户端测试集合"}}
📥 创建成功: ID=29578383-f2a0-4e6c-a02a-5490554493d8, Name=my-go-collection, Tenant=default_tenant, Database=default_database
✅ 集合已就绪,ID: 29578383-f2a0-4e6c-a02a-5490554493d8, 名称: my-go-collection

📤 添加数据到集合: my-go-collection
🔗 完整 URL: http://127.0.0.1:8000/api/v2/tenants/default_tenant/databases/default_database/collections/29578383-f2a0-4e6c-a02a-5490554493d8/add
📦 请求体: {"ids":["doc1","doc2"],"embeddings":[[0.1,0.2,0.3,0.4,0.5],[0.6,0.7,0.8,0.9,1]],"documents":["Go 语言是并发的王者","ChromaDB 是一个向量数据库"],"metadatas":[{"language":"go","source":"go-demo","type":"programming"},{"source":"go-demo","topic":"database","type":"technology"}]}
📥 响应状态: 201
📥 响应内容: {}
✅ 数据添加成功

🔍 查询 URL: http://127.0.0.1:8000/api/v2/tenants/default_tenant/databases/default_database/collections/29578383-f2a0-4e6c-a02a-5490554493d8/query
🔍 查询请求: {"query_embeddings":[[0.1,0.2,0.3,0.4,0.5]],"n_results":3,"include":["documents","distances","metadatas"]}

🎉 查询成功!找到以下结果:
  1. [语言: go] Go 语言是并发的王者 (距离: 0.0000)
  2. ChromaDB 是一个向量数据库 (距离: 1.2500)