You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建可扩展Python布尔搜索解析器:生成抽象语法树及展开查询

哇,你已经完成了布尔搜索解析器里最硬核的AST构建部分,这可是绕不开的关键一步!接下来要实现复杂表达式的展开和更多运算符支持,咱们可以分模块来推进,思路清晰又不容易踩坑:

一、搞定AND分组的笛卡尔积展开

你要的把(A OR B) AND (C OR D) AND (E OR F)拆成所有AND组合的需求,本质是计算多个OR组的笛卡尔积。具体步骤可以这么做:

  • 遍历AST的顶层AND节点,把每个子项转换成表达式列表:如果是OR节点,提取它的所有子表达式;如果是单个表达式(比如纯关键词、NOT语句、邻近运算符),就当成只有一个元素的列表。
  • 用itertools.product计算这些列表的笛卡尔积,每个乘积结果拼接成一行简化的AND表达式。

举个实现片段:

import itertools

def expand_and_groups(processed_children):
    # 先把每个AND子项整理成可迭代的表达式列表
    groups = []
    for expr_list in processed_children:
        # 这里expr_list是子节点处理后得到的表达式列表(比如OR组会拆成多个元素)
        groups.append(expr_list)
    # 生成所有笛卡尔积组合,拼接成AND表达式
    for combo in itertools.product(*groups):
        yield " AND ".join(combo)
二、NOT运算符的特殊处理(含德摩根定律)

NOT的处理要分场景,尤其是嵌套在括号里的情况:

  • 如果是NOT (A OR B)这种形式,要应用德摩根定律转换成NOT A AND NOT B;如果是NOT (A AND B),则转换成NOT A OR NOT B。
  • 如果是(A OR NOT B)这种局部否定,直接把NOT B当成一个独立元素参与笛卡尔积即可。

可以写个专门处理德摩根转换的函数:

def apply_de_morgan(not_node):
    child = not_node.children[0]
    if child.type == "OR":
        # NOT (A OR B) → NOT A AND NOT B
        return Node(type="AND", children=[Node(type="NOT", children=[c]) for c in child.children])
    elif child.type == "AND":
        # NOT (A AND B) → NOT A OR NOT B
        return Node(type="OR", children=[Node(type="NOT", children=[c]) for c in child.children])
    else:
        # 单个表达式的否定,直接返回原节点
        return not_node
三、邻近运算符的独立处理

邻近运算符(比如NEAR/n、ADJ)是位置约束,不属于传统布尔逻辑,所以要把它们当成不可拆分的整体:

  • 在AST构建阶段,把邻近运算符识别为独立的节点类型(比如PROXIMITY),存储左右表达式和距离参数。
  • 序列化时输出成标准格式,比如X NEAR/5 Y。
  • 在展开AND组时,邻近节点直接作为单元素参与笛卡尔积,不要拆分它的左右部分。
四、递归处理任意层级括号

因为AST是树形结构,所有的展开和转换都要递归遍历每个子节点,先处理内层括号,再处理外层:

def process_ast(node):
    if node.type == "AND":
        # 递归处理每个AND子节点
        processed_children = [process_ast(child) for child in node.children]
        # 展开所有AND组合
        return list(expand_and_groups(processed_children))
    elif node.type == "OR":
        # OR节点的子节点结果直接扁平化合并
        processed_children = [process_ast(child) for child in node.children]
        return [item for sublist in processed_children for item in sublist]
    elif node.type == "NOT":
        # 先处理被否定的子节点,再应用德摩根定律
        processed_child = process_ast(node.children[0])
        # 这里需要把processed_child重新包装成AST节点再传入apply_de_morgan
        demorgan_node = apply_de_morgan(Node(type="NOT", children=[processed_child]))
        return process_ast(demorgan_node)
    elif node.type == "PROXIMITY":
        # 邻近节点直接返回序列化字符串的列表
        return [f"{node.left.value} NEAR/{node.distance} {node.right.value}"]
    else:
        # 基础关键词节点,返回自身字符串的列表
        return [node.value]
五、测试边界情况

别忘测试一些容易踩坑的场景:

  • 多层嵌套括号:比如((A OR B) AND NOT (C OR D)) AND (E NEAR/2 F),确保展开后生成4行正确的表达式。
  • 混合运算符:比如A AND (B OR NOT C) AND (D NEAR/1 E OR F),验证NOT和邻近运算符都正确保留。
  • 空表达式或无效输入:在展开阶段加个判断,避免生成AND AND这种无效字符串。

内容的提问来源于stack exchange,提问作者nrflaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:09:48