Chroma 教程

where_document:文本过滤

🎉摘要:详解Chroma的where_document文本过滤:$contains与$not_contains按子串匹配且大小写敏感,$regex与$not_regex支持正则表达式匹配,可匹配邮箱和手机号。底层基于SQLite FTS5粗筛加正则校验。

前面介绍的 where 是用来过滤 metadata,而本章的 where_document 则是用来过滤 chunk 原文文本。在向量检索前先做文本筛选,再算相似度召回。

注意:

(1)不是向量语义检索,是字符串 / 正则匹配。

(2)大小写敏感,Hello 和 hello 不匹配。

(3)要求子串至少 3 个字符,太短会报错。  

$contains /$not_contains

按子串匹配,区分大小写。中文也能用:

print("\n--- 包含“退款” ---")
res = col.get(where_document={"$contains": "退款"})
show(res)

print("\n--- 包含“退” ---")
res = col.get(where_document={"$contains": "退"})
show(res)

print("\n--- 不包含“退款” ---")
res = col.get(where_document={"$not_contains": "退款"})
show(res)

运行代码,输出如下:

--- 包含“退款” ---
id=r1, document=退款流程 refund, metadata={'year': 2020, 'tags': ['a', 'b'], 'cat': '售后', 'is_public': True, 'score': 0.9}

--- 包含“退” ---
id=r1, document=退款流程 refund, metadata={'is_public': True, 'year': 2020, 'score': 0.9, 'tags': ['a', 'b'], 'cat': '售后'}
id=r4, document=退货政策, metadata={'is_public': False, 'cat': '售后', 'tags': ['b', 'd'], 'score': 0.3, 'year': 2024}

--- 不包含“退款” ---
id=r2, document=发票 invoice, metadata={'tags': ['c'], 'year': 2022, 'is_public': False, 'score': 0.5, 'cat': '财务'}
id=r3, document=物流 logistics, metadata={'cat': '物流', 'tags': ['a', 'd'], 'score': 0.7, 'year': 2024, 'is_public': False}
id=r4, document=退货政策, metadata={'year': 2024, 'score': 0.3, 'is_public': False, 'tags': ['b', 'd'], 'cat': '售后'}

英文大小写敏感,实测:

print("\n--- 包含“refund” ---")
res = col.get(where_document={"$contains": "refund"})
show(res)

print("\n--- 包含“Refund” ---")
res = col.get(where_document={"$contains": "Refund"})
show(res)

运行代码,输出如下:

--- 包含“refund” ---
id=r1, document=退款流程 refund, metadata={'score': 0.9, 'year': 2020, 'cat': '售后', 'tags': ['a', 'b'], 'is_public': True}

--- 包含“Refund” ---

注意了,它匹配的是字符串子串而不是词。这跟大多数全文检索引擎的“分词+词项匹配”不一样,好处是不用管分词(中文友好),坏处是没法做词形还原、同义词这些。

$regex /$not_regex

基于正则表达式进行匹配,例如:

print("\n--- 匹配以“退”开头的记录 ---")
res = col.get(where_document={"$regex": "^退"})
show(res)

print("\n--- 匹配不以“退”开头的记录 ---")
res = col.get(where_document={"$not_regex": "^退"})
show(res)

print("\n--- 匹配包含“refund”或“invoice”的记录 ---")
res = col.get(where_document={"$regex": "refund|invoice"})
show(res)

运行示例,输出如下:

--- 匹配以“退”开头的记录 ---
id=r1, document=退款流程 refund, metadata={'is_public': True, 'score': 0.9, 'tags': ['a', 'b'], 'year': 2020, 'cat': '售后'}
id=r4, document=退货政策, metadata={'score': 0.3, 'is_public': False, 'cat': '售后', 'year': 2024, 'tags': ['b', 'd']}

--- 匹配不以“退”开头的记录 ---
id=r2, document=发票 invoice, metadata={'is_public': False, 'cat': '财务', 'tags': ['c'], 'year': 2022, 'score': 0.5}
id=r3, document=物流 logistics, metadata={'tags': ['a', 'd'], 'is_public': False, 'cat': '物流', 'score': 0.7, 'year': 2024}

--- 匹配包含“refund”或“invoice”的记录 ---
id=r1, document=退款流程 refund, metadata={'tags': ['a', 'b'], 'is_public': True, 'cat': '售后', 'score': 0.9, 'year': 2020}
id=r2, document=发票 invoice, metadata={'is_public': False, 'year': 2022, 'tags': ['c'], 'score': 0.5, 'cat': '财务'}

使用正则,还能轻松匹配邮箱地址和手机号,例如:

# 准备测试数据
col.add(
    ids=["r1", "r2", "r3", "r4"],
    embeddings=[[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]],
    documents=[
        "退款流程 refund",
        "发票 invoice",
        "物流 logistics",
        "退货政策,邮箱地址 demo@163.com,手机号码 15186772233" # 构造测试数据
    ],
    metadatas=[
        {"cat": "售后", "year": 2020, "score": 0.9, "is_public":True, "tags": ["a", "b"]},
        {"cat": "财务", "year": 2022, "score": 0.5, "is_public":False, "tags": ["c"]},
        {"cat": "物流", "year": 2024, "score": 0.7, "is_public":False, "tags": ["a", "d"]},
        {"cat": "售后", "year": 2024, "score": 0.3, "is_public":False, "tags": ["b", "d"]},
    ],
)


# 后续代码直接在这里进行编写即可
# 注意,后续示例仅给出查询部分代码,数据准备和打印查询结果参考这里的代码
print("\n--- 匹配邮箱地址 ---")
EMAIL = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
res = col.get(where_document={"$regex": EMAIL})
show(res)

print("\n--- 匹配手机号码 ---")
PHONE = r"1[3-9]\d{9}"
res = col.get(where_document={"$regex": PHONE})
show(res)

运行代码,输出如下:

--- 匹配邮箱地址 ---
id=r4, document=退货政策,邮箱地址 demo@163.com,手机号码 15186772233, metadata={'tags': ['b', 'd'], 'year': 2024, 'is_public': False, 'score': 0.3, 'cat': '售后'}

--- 匹配手机号码 ---
id=r4, document=退货政策,邮箱地址 demo@163.com,手机号码 15186772233, metadata={'cat': '售后', 'year': 2024, 'is_public': False, 'tags': ['b', 'd'], 'score': 0.3}

注意,Chroma 底层用的是 SQLite 的 FTS5 + 正则,中文正则实测可用。分两步走:

(1)先用 FTS5 索引(MATCH)做粗筛,快速把候选文档 ID 集合缩小(用来减少后面正则扫描量,提升性能)。

(2)拿到候选文档之后,取出原始 document 文本,走 Rust/Python 层正则(标准 PCRE/Rust regex)校验。

  

说说我的看法
全部评论()
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号