Skip to content

Commit bf6452d

Browse files
committed
feat: 添加命名空间支持和文档说明 - 在.gitignore中添加了对虚拟环境文件夹的忽略 - 新增命名空间使用指南文档,详细介绍了如何在Cloudflare Vectorize中使用命名空间管理向量 - 更新CloudflareVectorize类,支持在插入、查询和更新向量时指定命名空间 - 在utils中添加命名空间字段的验证逻辑 Closes #1
1 parent c715821 commit bf6452d

4 files changed

Lines changed: 414 additions & 4 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ wheels/
2222

2323
# Virtual Environment
2424
venv/
25+
.venv/
2526
ENV/
2627
env/
2728
.env/

docs/namespace_usage.md

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
# Cloudflare Vectorize Namespaces 使用指南
2+
3+
## 概述
4+
5+
Namespaces 提供了一种在索引内分段管理向量的方法。您可以按客户、商户、店铺 ID 或任何其他逻辑分组来组织向量。
6+
7+
## 主要特性
8+
9+
- **向量分组**:按命名空间组织向量,便于管理和查询
10+
- **隔离查询**:在特定命名空间内搜索,提高查询精度
11+
- **自动添加**:客户端自动为向量添加命名空间字段
12+
- **灵活管理**:支持最多 1,000 个命名空间per索引
13+
14+
## ⚠️ 重要注意事项:一致性模型
15+
16+
Cloudflare Vectorize 使用**最终一致性**模型:
17+
18+
- **写入延迟**:新插入的向量可能需要几秒到几分钟才能在查询中可见
19+
- **批量优化**:Vectorize 会将多个变更合并为批次处理以提高性能
20+
- **推荐做法**:插入向量后,等待适当时间再进行查询验证
21+
22+
根据 [Cloudflare 官方文档](https://developers.cloudflare.com/vectorize/best-practices/insert-vectors/#improve-write-throughput)
23+
- 批量处理最多 200,000 个向量或 1,000 个更新操作
24+
- 大量向量的索引可能需要几分钟到几小时完成
25+
26+
## 使用方法
27+
28+
### 1. 插入带命名空间的向量
29+
30+
#### 方法一:自动添加命名空间
31+
```python
32+
from cloudflare_vectorize import CloudflareVectorize
33+
34+
client = CloudflareVectorize(
35+
account_id="your-account-id",
36+
auth_config={"bearer_token": "your-token"}
37+
)
38+
39+
# 原始向量数据(不带namespace)
40+
vectors_data = '''{"id": "doc1", "values": [0.1, 0.2, 0.3]}
41+
{"id": "doc2", "values": [0.4, 0.5, 0.6]}'''
42+
43+
# 插入时指定namespace,客户端会自动添加
44+
result = client.insert_vectors(
45+
index_name="my-index",
46+
vectors_data=vectors_data,
47+
namespace="documents" # 自动为每个向量添加此namespace
48+
)
49+
50+
print(f"插入成功,mutation_id: {result['result']['mutationId']}")
51+
52+
# ⚠️ 等待索引更新(推荐)
53+
import time
54+
time.sleep(5) # 等待5秒让索引更新
55+
```
56+
57+
#### 方法二:手动在数据中包含命名空间
58+
```python
59+
# 手动创建带namespace的向量数据
60+
vectors_data = '''{"id": "text1", "values": [0.1, 0.2, 0.3], "namespace": "text"}
61+
{"id": "image1", "values": [0.4, 0.5, 0.6], "namespace": "images"}'''
62+
63+
# 直接插入(不需要指定namespace参数)
64+
result = client.insert_vectors(
65+
index_name="my-index",
66+
vectors_data=vectors_data
67+
)
68+
```
69+
70+
### 2. 在命名空间内查询向量
71+
72+
```python
73+
# 仅在特定命名空间内搜索
74+
result = client.query_vectors(
75+
index_name="my-index",
76+
vector=[0.1, 0.2, 0.3],
77+
top_k=5,
78+
namespace="documents" # 仅搜索documents命名空间
79+
)
80+
81+
# 不指定命名空间则搜索所有向量
82+
result = client.query_vectors(
83+
index_name="my-index",
84+
vector=[0.1, 0.2, 0.3],
85+
top_k=5
86+
# 不指定namespace,搜索全部
87+
)
88+
```
89+
90+
### 3. 处理索引延迟的推荐模式
91+
92+
```python
93+
import time
94+
95+
# 插入向量
96+
result = client.insert_vectors(
97+
index_name="my-index",
98+
vectors_data=vectors_data,
99+
namespace="my_namespace"
100+
)
101+
102+
mutation_id = result['result']['mutationId']
103+
print(f"向量插入成功: {mutation_id}")
104+
105+
# 推荐:等待索引更新
106+
def wait_for_indexing(client, index_name, vector_ids, max_wait=60):
107+
"""等待向量被索引"""
108+
start_time = time.time()
109+
while time.time() - start_time < max_wait:
110+
try:
111+
result = client.get_vectors(index_name, vector_ids)
112+
if len(result['result']) > 0:
113+
print("向量已被索引,可以进行查询")
114+
return True
115+
except:
116+
pass
117+
time.sleep(2)
118+
print("等待超时,但向量可能仍在处理中")
119+
return False
120+
121+
# 使用示例
122+
vector_ids = ["doc1", "doc2"]
123+
wait_for_indexing(client, "my-index", vector_ids)
124+
125+
# 现在可以安全地进行命名空间查询
126+
result = client.query_vectors(
127+
index_name="my-index",
128+
vector=[0.1, 0.2, 0.3],
129+
namespace="my_namespace"
130+
)
131+
```
132+
133+
### 4. 更新/插入带命名空间的向量
134+
135+
```python
136+
# 使用upsert方法,支持namespace
137+
result = client.upsert_vectors(
138+
index_name="my-index",
139+
vectors_data=vectors_data,
140+
namespace="updated_docs"
141+
)
142+
```
143+
144+
## 命名空间限制和最佳实践
145+
146+
### 限制
147+
- 命名空间名称最大 **64 字符**
148+
- 每个索引最多 **1,000 个命名空间**
149+
- 命名空间必须是非空字符串
150+
151+
### 最佳实践
152+
153+
#### 1. 按业务逻辑分组
154+
```python
155+
# 按客户分组
156+
client.insert_vectors(index_name, customer_vectors, namespace="customer_123")
157+
158+
# 按内容类型分组
159+
client.insert_vectors(index_name, text_vectors, namespace="text")
160+
client.insert_vectors(index_name, image_vectors, namespace="images")
161+
162+
# 按时间分组
163+
client.insert_vectors(index_name, vectors, namespace="2024-01")
164+
```
165+
166+
#### 2. 命名空间性能优化
167+
```python
168+
# 命名空间过滤在向量搜索之前应用,提高搜索精度
169+
result = client.query_vectors(
170+
index_name="large-index",
171+
vector=query_vector,
172+
namespace="specific_customer", # 先过滤,再搜索
173+
top_k=10
174+
)
175+
```
176+
177+
#### 3. 批量插入优化
178+
```python
179+
# 推荐:批量插入向量以提高性能
180+
large_vectors_data = '\n'.join([
181+
f'{{"id": "vec_{i}", "values": {[random.random() for _ in range(dimensions)]}}}'
182+
for i in range(1000)
183+
])
184+
185+
client.insert_vectors(
186+
index_name="my-index",
187+
vectors_data=large_vectors_data,
188+
namespace="batch_insert"
189+
)
190+
```
191+
192+
#### 4. 元数据配合使用
193+
```python
194+
vectors_data = '''{"id": "doc1", "values": [0.1, 0.2], "namespace": "docs", "metadata": {"category": "tech", "date": "2024-01-15"}}'''
195+
```
196+
197+
## 验证和错误处理
198+
199+
```python
200+
try:
201+
# 命名空间长度验证
202+
long_namespace = "a" * 65 # 超过64字符
203+
client.insert_vectors(index_name, vectors, namespace=long_namespace)
204+
except ValueError as e:
205+
print(f"命名空间验证失败: {e}")
206+
207+
try:
208+
# 空命名空间验证
209+
client.insert_vectors(index_name, vectors, namespace="")
210+
except ValueError as e:
211+
print(f"命名空间不能为空: {e}")
212+
213+
# 处理索引延迟
214+
try:
215+
result = client.query_vectors(index_name, vector, namespace="my_ns")
216+
if result['result']['count'] == 0:
217+
print("未找到结果,可能需要等待索引更新")
218+
except Exception as e:
219+
print(f"查询失败: {e}")
220+
```
221+
222+
## 故障排除
223+
224+
### 问题:插入成功但查询不到向量
225+
226+
**原因**:Vectorize 使用最终一致性,新插入的向量需要时间索引
227+
228+
**解决方案**
229+
1. 等待几秒到几分钟后重试
230+
2. 使用 `get_vectors()` 检查向量是否存在
231+
3. 进行全局查询(不指定namespace)验证向量是否在索引中
232+
233+
```python
234+
# 检查向量是否存在
235+
result = client.get_vectors("my-index", ["vector_id"])
236+
if len(result['result']) == 0:
237+
print("向量还未被索引,请稍后重试")
238+
else:
239+
print(f"向量存在,namespace: {result['result'][0].get('namespace')}")
240+
```
241+
242+
### 问题:命名空间查询返回空结果
243+
244+
**排查步骤**
245+
1. 确认向量已被索引
246+
2. 验证namespace名称拼写正确
247+
3. 检查全局查询中向量的实际namespace
248+
249+
```python
250+
# 调试namespace查询
251+
import random
252+
253+
# 1. 全局查询找到现有向量
254+
global_result = client.query_vectors(
255+
index_name="my-index",
256+
vector=[random.random() for _ in range(dimensions)],
257+
top_k=10,
258+
return_metadata="all"
259+
)
260+
261+
# 2. 查看实际的namespace值
262+
for match in global_result['result']['matches']:
263+
if 'namespace' in match:
264+
print(f"ID: {match['id']}, namespace: '{match['namespace']}'")
265+
266+
# 3. 使用确认的namespace进行查询
267+
result = client.query_vectors(
268+
index_name="my-index",
269+
vector=[random.random() for _ in range(dimensions)],
270+
namespace="confirmed_namespace",
271+
top_k=5
272+
)
273+
```
274+
275+
## 完整示例
276+
277+
```python
278+
from cloudflare_vectorize import CloudflareVectorize
279+
import random
280+
import time
281+
282+
# 初始化客户端
283+
client = CloudflareVectorize(
284+
account_id="your-account-id",
285+
auth_config={"bearer_token": "your-token"}
286+
)
287+
288+
# 创建不同类型的向量数据
289+
text_vectors = '''{"id": "text1", "values": [0.1, 0.2, 0.3]}
290+
{"id": "text2", "values": [0.4, 0.5, 0.6]}'''
291+
292+
image_vectors = '''{"id": "img1", "values": [0.7, 0.8, 0.9]}
293+
{"id": "img2", "values": [1.0, 1.1, 1.2]}'''
294+
295+
# 插入到不同命名空间
296+
print("插入文本向量...")
297+
result1 = client.insert_vectors("my-index", text_vectors, namespace="text")
298+
print(f"文本向量插入成功: {result1['result']['mutationId']}")
299+
300+
print("插入图片向量...")
301+
result2 = client.insert_vectors("my-index", image_vectors, namespace="images")
302+
print(f"图片向量插入成功: {result2['result']['mutationId']}")
303+
304+
# 等待索引更新
305+
print("等待索引更新...")
306+
time.sleep(10)
307+
308+
# 在特定命名空间内查询
309+
query_vector = [0.2, 0.3, 0.4]
310+
311+
# 仅搜索文本向量
312+
text_results = client.query_vectors(
313+
"my-index", query_vector, top_k=2, namespace="text"
314+
)
315+
316+
# 仅搜索图片向量
317+
image_results = client.query_vectors(
318+
"my-index", query_vector, top_k=2, namespace="images"
319+
)
320+
321+
# 搜索所有向量
322+
all_results = client.query_vectors(
323+
"my-index", query_vector, top_k=4
324+
)
325+
326+
print(f"文本结果: {text_results['result']['count']} 个匹配")
327+
print(f"图片结果: {image_results['result']['count']} 个匹配")
328+
print(f"全部结果: {all_results['result']['count']} 个匹配")
329+
```
330+
331+
## 参考文档
332+
333+
- [Cloudflare Vectorize Namespaces 官方文档](https://developers.cloudflare.com/vectorize/best-practices/insert-vectors/#namespaces)
334+
- [Vectorize API 参考](https://developers.cloudflare.com/api/resources/vectorize/subresources/indexes/methods/insert/)
335+
- [Vectorize 性能优化](https://developers.cloudflare.com/vectorize/best-practices/insert-vectors/#improve-write-throughput)

0 commit comments

Comments
 (0)