本文中的 Mem0 源码片段来自 Mem0 官方 GitHub 仓库,并使用了AI工具进行学习,仅用于个人学习与源码阅读记录。源码链接参见:mem0/mem0 at main · mem0ai/mem0 · GitHub
python
# 定义一个实例方法,用于处理 metadata_filters(元数据过滤条件)
# self 表示当前类实例
# metadata_filters 的类型是 Dict[str, Any],也就是键为字符串、值可以是任意类型的字典
# 返回值也是一个 Dict[str, Any] 类型的字典
def _process_metadata_filters(
self,
metadata_filters: Dict[str, Any]
) -> Dict[str, Any]:
# 方法的文档字符串,用于说明这个方法的功能
"""
Process enhanced metadata filters and convert them to vector store compatible format.
Args:
metadata_filters: Enhanced metadata filters with operators
Returns:
Dict of processed filters compatible with vector store
"""
# 创建一个空字典,用来保存最终处理完成的过滤条件
processed_filters = {}
# 定义内部函数 process_condition
# key 表示元数据字段名,例如 "age"、"category"
# condition 表示这个字段对应的过滤条件
# 返回值是处理完成后的字典
def process_condition(key: str, condition: Any) -> Dict[str, Any]:
# 判断 condition 是否不是字典
# 如果不是字典,说明这是最简单的"等值查询"
# 例如:{"category": "python"}
if not isinstance(condition, dict):
# 如果条件值是星号 "*",则表示通配符
if condition == "*":
# 将该字段的过滤条件原样保存为 "*"
# 具体 "*" 如何解释,要看后面的向量数据库实现
return {key: "*"}
# 普通情况下直接返回 key:value
# 例如 key="category",condition="python"
# 返回 {"category": "python"}
return {key: condition}
# 创建空字典,用来保存当前字段处理后的条件
result = {}
# 遍历 condition 字典中的每一个操作符以及对应的值
# 例如:
# condition = {"gte": 18, "lte": 30}
# 第一次 operator="gte",value=18
# 第二次 operator="lte",value=30
for operator, value in condition.items():
# 定义操作符映射表
# 左侧是平台接收到的操作符
# 右侧是内部统一使用的操作符
operator_map = {
# eq 表示 equal,即"等于"
"eq": "eq",
# ne 表示 not equal,即"不等于"
"ne": "ne",
# gt 表示 greater than,即"大于"
"gt": "gt",
# gte 表示 greater than or equal,即"大于等于"
"gte": "gte",
# lt 表示 less than,即"小于"
"lt": "lt",
# lte 表示 less than or equal,即"小于等于"
"lte": "lte",
# in 表示字段值位于某个集合中
"in": "in",
# nin 表示 not in,即字段值不在某个集合中
"nin": "nin",
# contains 表示"包含"
"contains": "contains",
# icontains 一般表示忽略大小写的"包含"
"icontains": "icontains"
}
# 判断当前传入的操作符是否属于系统支持的操作符
if operator in operator_map:
# result.setdefault(key, {}):
# 如果 result 中不存在 key,就创建一个空字典
# 如果已经存在 key,就直接取得已有的字典
#
# [operator_map[operator]] = value:
# 将转换后的操作符和值写入字段条件中
#
# 例如:
# key = "age"
# operator = "gte"
# value = 18
#
# 最终可能得到:
# {
# "age": {
# "gte": 18
# }
# }
result.setdefault(key, {})[operator_map[operator]] = value
# 如果传入的操作符不在 operator_map 中
else:
# 主动抛出 ValueError 异常
# 告诉调用者当前 metadata filter 使用了不支持的操作符
raise ValueError(
f"Unsupported metadata filter operator: {operator}"
)
# 返回当前字段处理完成后的过滤条件
return result
# 定义一个内部函数 merge_filters
# 用于把 source 中的过滤条件合并到 target 中
# 函数本身不需要返回值,所以返回类型标记为 None
def merge_filters(
target: Dict[str, Any],
source: Dict[str, Any]
) -> None:
# 函数文档字符串
# 说明对于同一个字段的操作符字典,需要进行深一层的合并
"""Merge source into target, deep-merging nested operator dicts for the same key."""
# 遍历 source 字典中的所有键和值
for key, value in source.items():
# 判断是否满足三个条件:
# 1. key 已经存在于 target 中
# 2. target[key] 是字典
# 3. 当前 source 中的 value 也是字典
#
# 如果三个条件同时成立,说明两个过滤条件属于同一个字段,
# 并且都包含操作符,需要把操作符合并起来
if (
key in target
and isinstance(target[key], dict)
and isinstance(value, dict)
):
# 使用 update 将新的操作符条件合并进原有字典
#
# 例如:
# target = {"age": {"gte": 18}}
# value = {"lte": 30}
#
# 合并后:
# target = {
# "age": {
# "gte": 18,
# "lte": 30
# }
# }
target[key].update(value)
# 如果不是同一个字段的嵌套字典
else:
# 直接把 key:value 写入 target
target[key] = value
# 遍历用户传入的所有 metadata_filters
# key 可能是普通字段,例如 "age"
# 也可能是逻辑操作符,例如 "AND"、"OR"、"NOT"
for key, value in metadata_filters.items():
# 判断当前 key 是否为逻辑 AND
if key == "AND":
# AND 后面应该跟一个条件列表
# 如果 value 不是 list,则说明参数格式错误
if not isinstance(value, list):
# 抛出异常,告诉调用者 AND 必须接收一个条件列表
raise ValueError(
"AND operator requires a list of conditions"
)
# 遍历 AND 中的每一个条件
# 例如:
# [
# {"age": {"gte": 18}},
# {"age": {"lte": 30}}
# ]
for condition in value:
# 遍历当前条件中的字段名和字段条件
for sub_key, sub_value in condition.items():
# 先调用 process_condition 对当前条件进行标准化处理
# 然后再调用 merge_filters 合并到 processed_filters 中
merge_filters(
processed_filters,
process_condition(sub_key, sub_value)
)
# 如果当前 key 是 OR,表示逻辑"或"
elif key == "OR":
# 判断 value 是否是列表
# 同时使用 not value 判断列表是否为空
if not isinstance(value, list) or not value:
# OR 必须传入一个非空条件列表,否则抛出异常
raise ValueError(
"OR operator requires a non-empty list of conditions"
)
# 在 processed_filters 中创建 "$or"
# 使用列表保存所有 OR 分支
#
# 最终结构类似:
# {
# "$or": [
# {...},
# {...}
# ]
# }
processed_filters["$or"] = []
# 遍历 OR 中的每一个条件分支
for condition in value:
# 为当前 OR 分支创建一个空字典
or_condition = {}
# 遍历当前 OR 条件中的字段及对应条件
for sub_key, sub_value in condition.items():
# 先标准化当前字段条件
# 再将结果合并到当前 OR 分支中
merge_filters(
or_condition,
process_condition(sub_key, sub_value)
)
# 当前 OR 分支处理完成后
# 将它加入 "$or" 对应的列表中
processed_filters["$or"].append(or_condition)
# 如果当前 key 是 NOT,表示逻辑"非"
elif key == "NOT":
# NOT 后面同样必须是一个非空列表
if not isinstance(value, list) or not value:
# 如果不是列表或者列表为空,则抛出异常
raise ValueError(
"NOT operator requires a non-empty list of conditions"
)
# 创建 "$not" 列表
# 用于存放所有需要取反的条件
processed_filters["$not"] = []
# 遍历 NOT 中的每一个条件
for condition in value:
# 创建一个空字典
# 用于保存当前 NOT 条件处理后的结果
not_condition = {}
# 遍历当前 NOT 条件中的字段和条件
for sub_key, sub_value in condition.items():
# 对当前字段条件进行标准化
# 然后合并进当前 not_condition 中
merge_filters(
not_condition,
process_condition(sub_key, sub_value)
)
# 将当前处理好的 NOT 条件加入 "$not" 列表
processed_filters["$not"].append(not_condition)
# 如果 key 既不是 AND,也不是 OR,更不是 NOT
# 那么就认为它是普通的 metadata 字段
else:
# 调用 process_condition 处理普通字段条件
# 再通过 merge_filters 合并到最终结果中
merge_filters(
processed_filters,
process_condition(key, value)
)
# 所有过滤条件处理完成后,返回最终的过滤条件字典
return processed_filters
可以把
_process_metadata_filters()理解成一个 过滤条件翻译器 / 格式转换器。
整个函数可以理解成下面这条流水线:metadata_filters
↓
判断是普通字段还是 AND / OR / NOT
↓
process_condition()
处理单个字段的 eq、gte、contains 等操作符
↓
merge_filters()
合并同一个字段的多个条件
↓
processed_filters
↓
返回给 Vector Store
这段代码实际上分成了 3 层职责:_process_metadata_filters()
│
├── process_condition()
│ └── 负责:处理"一个字段"的过滤条件
│
├── merge_filters()
│ └── 负责:合并重复字段的过滤条件
│
└── 主循环
└── 负责:处理 AND / OR / NOT / 普通字段
python
# 定义一个私有方法,用来判断 filters 中是否包含"高级操作符"
# self 表示当前类实例
# filters: Dict[str, Any] 表示 filters 应该是一个字典:
# key 通常是字符串,value 可以是任意类型
# -> bool 表示这个方法最终返回 True 或 False
def _has_advanced_operators(self, filters: Dict[str, Any]) -> bool:
# 方法的文档字符串,用来说明这个方法的用途
"""
Check if filters contain advanced operators that need special processing.
Args:
filters: Dictionary of filters to check
Returns:
bool: True if advanced operators are detected
"""
# 先判断 filters 是不是字典类型
# isinstance(对象, 类型) 用于判断某个对象是否属于指定类型
if not isinstance(filters, dict):
# 如果 filters 不是字典,就无法按照后面的过滤器规则进行解析
# 因此直接返回 False,表示没有检测到高级操作符
return False
# 遍历 filters 字典中的每一个键值对
# key 表示字段名或逻辑操作符
# value 表示这个字段对应的过滤条件
for key, value in filters.items():
# 判断当前 key 是否是平台风格的逻辑操作符
# AND 表示"并且"
# OR 表示"或者"
# NOT 表示"非"
if key in ["AND", "OR", "NOT"]:
# 只要发现 AND、OR、NOT 中的任意一个
# 就说明当前 filters 使用了高级逻辑操作符
return True
# 判断当前 value 是否是一个字典
# 例如:
# {
# "age": {
# "gt": 18
# }
# }
#
# 此时 value 就是 {"gt": 18}
if isinstance(value, dict):
# 遍历 value 这个字典中的所有 key
# 这里的 op 是 operator(操作符)的缩写
# 比如 gt、eq、in 等
for op in value.keys():
# 判断操作符是否属于系统支持的高级比较操作符
#
# eq = equal,等于
# ne = not equal,不等于
# gt = greater than,大于
# gte = greater than or equal,大于等于
# lt = less than,小于
# lte = less than or equal,小于等于
# in = 在指定集合中
# nin = not in,不在指定集合中
# contains = 包含,通常区分大小写
# icontains = 忽略大小写的包含判断
if op in [
"eq",
"ne",
"gt",
"gte",
"lt",
"lte",
"in",
"nin",
"contains",
"icontains"
]:
# 如果检测到上面的任意一个比较操作符
# 就说明 filters 中存在高级操作符
return True
# 判断 value 是否等于通配符 "*"
# "*" 一般可以表示"任意值"或者"匹配全部"
if value == "*":
# 出现通配符,也认为当前过滤条件属于高级过滤
return True
# 如果整个 filters 都遍历完了
# 既没有 AND / OR / NOT
# 也没有高级比较操作符
# 也没有 "*" 通配符
# 那么返回 False
return False
整个函数可以概括成下面这个流程:
收到 filters
↓
是不是 dict?
↓
不是 → False
↓
是
↓
遍历每一个 key/value
↓
key 是 AND / OR / NOT?
↓ 是
True
↓ 否
value 是 dict?
↓ 是
检查里面有没有 gt / gte / in 等操作符
↓ 有
True
↓ 没有
value 是 "*"?
↓ 是
True
↓ 否
继续遍历
↓
全部检查完都没有
↓
False