SearchFilters 与时序查询
搜索过滤器与时序查询
相关源文件
本章引用的主要源码文件:
examples/podcast/podcast_runner.pygraphiti_core/search/search.pygraphiti_core/search/search_config.pygraphiti_core/search/search_config_recipes.pygraphiti_core/search/search_filters.pygraphiti_core/search/search_utils.pytests/test_graphiti_int.py
本文档记录了 SearchFilters Pydantic 模型及其所有关联的过滤器类型、运算符和 graphiti_core/search/search_filters.py 中的查询构造工具。它解释了如何通过节点标签、边类型、特定边 UUID、属性值和时序范围(事实有效时间、创建时间和过期时间)来限定搜索范围。
有关搜索架构的整体概述(包括搜索方法、重排序器和 SearchConfig),请参见第 4.3 页。有关调整搜索配置选项,请参见第 10.2 页。有关作为时序过滤基础的双时序数据模型,请参见第 3.2 页。
概述
Graphiti 中的每个搜索调用都接受一个 SearchFilters 实例,该实例会贯穿所有底层搜索方法(BM25 全文搜索、余弦相似度、BFS 遍历)。过滤器会在数据库查询执行前转换为 Cypher WHERE 子句。不同的图数据库提供商(Neo4j、FalkorDB、Kuzu、Neptune)会收到略有不同的语法。
数据模型图:SearchFilters 及其组件
来源:graphiti_core/search/search_filters.py:55-67
ComparisonOperator
ComparisonOperator 是一个 Python Enum,其值为 Cypher 运算符字符串。
| 成员 | Cypher 值 | 说明 |
|---|---|---|
equals | = | 精确匹配 |
not_equals | <> | 不相等 |
greater_than | > | 严格晚于/大于 |
less_than | < | 严格早于/小于 |
greater_than_equal | >= | 在或晚于/大于等于 |
less_than_equal | <= | 在或早于/小于等于 |
is_null | IS NULL | 属性必须不存在/为空 |
is_not_null | IS NOT NULL | 属性必须存在且非空 |
当使用 is_null 或 is_not_null 时,DateFilter 上的 date 字段(或 PropertyFilter 上的 property_value 字段)会被忽略——不会向查询中发出参数。
来源:graphiti_core/search/search_filters.py:27-35
DateFilter
DateFilter 将一个 datetime 值与一个 ComparisonOperator 配对。它始终在 SearchFilters 的 list[list[DateFilter]] 字段内使用——从不单独使用。
class DateFilter(BaseModel):
date: datetime | None = Field(default=None, description='用于过滤的日期时间')
comparison_operator: ComparisonOperator = Field(
description='日期过滤器的比较运算符'
)
来源:graphiti_core/search/search_filters.py:38-42
PropertyFilter
PropertyFilter 允许对任意边或节点属性值进行过滤。
class PropertyFilter(BaseModel):
property_name: str = Field(description='属性名称')
property_value: str | int | float | None = Field(
default=None, description='要匹配的属性值'
)
comparison_operator: ComparisonOperator = Field(
description='属性的比较运算符'
)
来源:graphiti_core/search/search_filters.py:45-52
SearchFilters
SearchFilters 是一个 Pydantic BaseModel,它将所有过滤条件聚合到一个单一对象中,并传递给每个搜索函数。它包含一个针对 node_labels 的验证器,以防止 Cypher 注入。
| 字段 | 类型 | 适用范围 | 描述 |
|---|---|---|---|
node_labels | list[str] | None | 节点和边 | 限制为带有这些标签的节点。对于边搜索,源节点(n)和目标节点(m)都必须具有该标签。 |
edge_types | list[str] | None | 仅边 | 匹配 e.name——关系名称/类型。 |
edge_uuids | list[str] | None | 仅边 | 限制为特定的边 UUID。 |
valid_at | list[list[DateFilter]] | None | 仅边 | 过滤 e.valid_at——事实在现实世界中为真的时间。 |
invalid_at | list[list[DateFilter]] | None | 仅边 | 过滤 e.invalid_at——事实变为假的时间。 |
created_at | list[list[DateFilter]] | None | 仅边 | 过滤 e.created_at——边被入库的时间。 |
expired_at | list[list[DateFilter]] | None | 仅边 | 过滤 e.expired_at——边被取代的时间。 |
property_filters | list[PropertyFilter] | None | 节点和边 | 自定义属性过滤器。 |
来源:graphiti_core/search/search_filters.py:55-73
时序过滤逻辑:AND / 或嵌套
所有四个时序字段(valid_at、invalid_at、created_at、expired_at)都接受 list[list[DateFilter]]。这种嵌套编码了一种析取范式(DNF):
- 内部列表(
list[DateFilter])——条件通过AND组合。 - 外部列表(
list[list[DateFilter]])——分组通过OR组合。
图:时序过滤器字段的 DNF 结构
来自集成测试 tests/test_graphiti_int.py:63-70 的示例生成的 Cypher 子句等效于: (e.created_at IS NULL) OR (e.created_at < $created_at_0) OR (e.created_at IS NOT NULL)
要表达一个范围(例如,在两个时间戳之间创建的边),请将两个 DateFilter 实例放在同一个内部列表中:
created_at=[
[
DateFilter(date=start_dt, comparison_operator=ComparisonOperator.greater_than_equal),
DateFilter(date=end_dt, comparison_operator=ComparisonOperator.less_than),
]
]
# 生成:(e.created_at >= $created_at_0 AND e.created_at < $created_at_1)
来源:graphiti_core/search/search_filters.py:149-262,tests/test_graphiti_int.py:63-70
查询构造函数
图:过滤器构造和搜索管线
来源:graphiti_core/search/search_filters.py:86-262,graphiti_core/search/search_utils.py:185-294,graphiti_core/search/search_utils.py:440-573
node_search_filter_query_constructor
graphiti_core/search/search_filters.py:86-104
处理 node_labels。返回一个 (list[str], dict) 元组,包含 Cypher WHERE 片段及其绑定的参数。它对标签执行深度防御验证 graphiti_core/search/search_filters.py:95。
| 提供商 | 生成的子句 |
|---|---|
| Neo4j / FalkorDB / Neptune | n:Label1|Label2 |
| Kuzu | list_has_all(n.labels, $labels) |
edge_search_filter_query_constructor
graphiti_core/search/search_filters.py:120-262
处理所有适用于边的过滤器字段。处理顺序:
edge_types→e.name in $edge_typesedge_uuids→e.uuid in $edge_uuidsnode_labels→n:<labels> AND m:<labels>(两个端点)valid_at、invalid_at、created_at、expired_at→ DNF 子句。
所有生成的子句被收集到一个列表中,并在 search_utils.py 的调用点通过 AND 连接。
date_filter_query_constructor
graphiti_core/search/search_filters.py:107-117
构建一个单一的日期比较字符串,例如 (e.valid_at < $valid_at_0)。对于 is_null 和 is_not_null 运算符,不会发出参数占位符。
SearchFilters 如何与搜索集成
图:SearchFilters 从 Graphiti.search_ 到数据库的流程
来源:graphiti_core/search/search.py:98-108,graphiti_core/search/search_utils.py:185-294,graphiti_core/search/search_utils.py:440-573
提供商特定行为
| 特性 | Neo4j / FalkorDB | Kuzu | Neptune |
|---|---|---|---|
| 节点标签过滤 | n:A|B | list_has_all(n.labels, $labels) | n:A|B |
| 时序过滤 | Cypher WHERE 子句 | 相同的 Cypher 子句 | Cypher WHERE 子句 |
| OpenSearch 运算符映射 | 不适用 | 不适用 | 全文搜索使用 cypher_to_opensearch_operator() |
cypher_to_opensearch_operator 函数 graphiti_core/search/search_filters.py:76-83 将 ComparisonOperator 值映射到 OpenSearch 范围查询关键字(gt、lt、gte、lte),用于 Neptune 后端。对于 Neo4j,_build_neo4j_fulltext_query graphiti_core/driver/neo4j/operations/search_ops.py:54-73 处理全文查询的构建,包括分组 ID 过滤。
实际示例
仅过滤活动(未过期)的边
from graphiti_core.search.search_filters import SearchFilters, DateFilter, ComparisonOperator
search_filter = SearchFilters(
expired_at=[
[DateFilter(date=None, comparison_operator=ComparisonOperator.is_null)]
]
)
过滤当前有效的边(时间点查询)
from graphiti_core.utils.datetime_utils import utc_now
now = utc_now()
search_filter = SearchFilters(
valid_at=[
[DateFilter(date=now, comparison_operator=ComparisonOperator.less_than_equal)]
],
invalid_at=[
[DateFilter(date=None, comparison_operator=ComparisonOperator.is_null)],
[DateFilter(date=now, comparison_operator=ComparisonOperator.greater_than)]
]
)
将 SearchFilters 传递给搜索
SearchFilters 直接传递给 Graphiti.search_():
results = await graphiti.search_(
query='Who is Tania',
search_filter=search_filter,
)
search_filter 参数通过 search.py 中的 search() 函数 graphiti_core/search/search.py:103 向下传递,并通过 edge_search_filter_query_constructor graphiti_core/search/search_filters.py:120-123 等工具用于构建最终的数据库查询。
来源:tests/test_graphiti_int.py:63-75,graphiti_core/search/search.py:98-108,graphiti_core/search/search_utils.py:185-195