1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
| import requests from pymongo import MongoClient import time
OPENROUTER_API_KEY = "your_api_key_here" MONGO_URI = "mongodb://admin:password@localhost:27017/" DATABASE_NAME = "vector_search_demo" COLLECTION_NAME = "tech_qa"
sample_data = [ { "question": "如何部署 MongoDB Atlas Local?", "answer": "使用 Docker Compose 可以快速部署 MongoDB Atlas Local,需要配置持久化卷和环境变量。" }, { "question": "什么是 BM25 算法?", "answer": "BM25 是一种基于概率的全文检索算法,广泛用于搜索引擎的相关性评分。" }, { "question": "向量检索的原理是什么?", "answer": "向量检索通过计算查询向量和文档向量的相似度(如余弦相似度)来找到语义相关的内容。" }, { "question": "如何优化数据库查询性能?", "answer": "可以通过创建索引、优化查询语句、使用连接池等方式提升数据库性能。" } ]
def get_embedding(text: str, api_key: str) -> list: """ 调用 OpenRouter API 生成文本的 embedding 向量
Args: text: 要向量化的文本 api_key: OpenRouter API key
Returns: 长度为 3072 的向量列表 """ url = "https://openrouter.ai/api/v1/embeddings" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } payload = { "model": "google/gemini-embedding-001", "input": text }
response = requests.post(url, headers=headers, json=payload) response.raise_for_status() return response.json()["data"][0]["embedding"]
def insert_documents_with_embeddings(collection, documents: list, api_key: str): """ 为文档生成 embedding 并批量插入 MongoDB
Args: collection: MongoDB 集合对象 documents: 文档列表 api_key: OpenRouter API key """ for doc in documents: text = f"{doc['question']} {doc['answer']}" print(f"正在生成 embedding: {doc['question'][:30]}...") doc["embedding"] = get_embedding(text, api_key)
collection.insert_many(documents) print(f"✓ 成功插入 {len(documents)} 条文档")
def create_vector_index(collection): """ 创建 MongoDB 向量搜索索引
参考文档:https://www.mongodb.com/docs/atlas/atlas-vector-search/create-index/
注意: 1. 此方法需要 MongoDB Atlas 或 Atlas Local 支持 2. Atlas Search 索引使用 mappings 字段(不是 fields) 3. 索引创建是异步的,需要等待构建完成 """ index_definition = { "mappings": { "dynamic": True, "fields": { "embedding": { "type": "knnVector", "dimensions": 3072, "similarity": "cosine" } } } }
try: result = collection.create_search_index( {"definition": index_definition, "name": "vector_index"} ) print(f"✓ 向量索引 '{result}' 创建成功")
print("⏳ 等待索引构建完成...") max_wait_time = 60 elapsed_time = 0
while elapsed_time < max_wait_time: try: indices = list(collection.list_search_indexes(result)) if len(indices) and indices[0].get("queryable") is True: print(f"✓ 索引 '{result}' 已就绪,可以查询") return except Exception as e: print(f"检查索引状态时出错: {e}")
time.sleep(5) elapsed_time += 5
print(f"⚠️ 索引创建超时,但可能仍在后台构建中")
except Exception as e: print(f"❌ 创建索引失败: {e}") print("提示:请检查 MongoDB Atlas Local 是否正确配置") raise
def vector_search(collection, query_text: str, api_key: str, limit: int = 3) -> list: """ 执行向量相似度检索
Args: collection: MongoDB 集合对象 query_text: 查询文本 api_key: OpenRouter API key limit: 返回结果数量
Returns: 检索结果列表,包含 question、answer 和相似度 score """ query_embedding = get_embedding(query_text, api_key)
pipeline = [ { "$vectorSearch": { "index": "vector_index", "path": "embedding", "queryVector": query_embedding, "numCandidates": 100, "limit": limit } }, { "$project": { "_id": 0, "question": 1, "answer": 1, "score": {"$meta": "vectorSearchScore"} } } ]
results = list(collection.aggregate(pipeline)) return results
def main(): """主函数:完整的向量检索演示流程"""
print("=" * 60) print("MongoDB Atlas Vector Search 演示") print("=" * 60) print("\n[1/5] 连接 MongoDB...") client = MongoClient(MONGO_URI) db = client[DATABASE_NAME] collection = db[COLLECTION_NAME] print("✓ 连接成功")
print("\n[2/5] 清空旧数据...") collection.drop() print("✓ 集合已清空")
print("\n[3/5] 生成 embeddings 并插入文档...") insert_documents_with_embeddings(collection, sample_data, OPENROUTER_API_KEY)
print("\n[4/5] 创建向量索引...") create_vector_index(collection)
print("\n[5/5] 执行向量检索测试") print("=" * 60)
test_queries = [ "怎么安装数据库?", "搜索算法有哪些?", "提升查询速度的方法" ]
for query in test_queries: print(f"\n📝 查询: {query}") print("-" * 60) results = vector_search(collection, query, OPENROUTER_API_KEY)
for i, result in enumerate(results, 1): print(f"{i}. [相似度: {result['score']:.4f}] {result['question']}") print(f" {result['answer'][:60]}...")
print("\n" + "=" * 60) print("✓ 演示完成") print("=" * 60)
if __name__ == "__main__": main()
|