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

无需预定义模型,如何实现类OData $filter的URI查询参数分词?

类OData $filter无实体依赖的简易分词方案指导

一、轻量解析方案选型

  • ANTLR4自定义语法:用ANTLR4定义简化版OData $filter语法(仅保留核心运算符:eq/ne/gt/lt/ge/le、and/or、括号、基础数据类型),生成词法/语法解析器,直接输出可用于构建SQL的分词节点(例如把Name eq 'Alice'解析为{type: 'comparison', left: 'Name', op: '=', right: "'Alice'"}),完全无需实体元数据,只做语法结构解析。
  • 手写递归下降解析器:针对简易需求,手写解析成本极低,核心分两步:
    1. 词法拆分:将$filter字符串拆分为tokens(字段名、运算符、值、逻辑符、括号),比如Age gt 18 and (Status eq 'Active' or Status eq 'Pending')会被拆成['Age', 'gt', '18', 'and', '(', 'Status', 'eq', "'Active'", 'or', 'Status', 'eq', "'Pending'", ')']
    2. 语法解析:按优先级(括号>比较运算>逻辑运算)递归构建抽象语法树(AST),最后遍历AST生成SQL条件片段。

二、简化版$filter语法约束(降低解析复杂度)

先限定支持的语法子集,减少开发量:

  • 仅支持字段名(字母、数字、下划线)、基础数据类型(字符串用单引号包裹、数字、布尔值true/false)
  • 核心运算符映射:比较运算符eq/ne/gt/lt/ge/le对应SQL的=/>/</>=/<=/!=;逻辑运算符and/or直接对应SQL的AND/OR;支持括号改变优先级
  • 暂不支持函数(如contains、startswith)、导航属性,后续按需扩展

三、示例实现思路(Python)

1. 词法拆分函数

def tokenize_filter(filter_str):
    # 给括号、运算符添加空格分隔,方便拆分
    processed = filter_str.replace('(', ' ( ').replace(')', ' ) ')
    processed = processed.replace('eq', ' eq ').replace('ne', ' ne ')
    processed = processed.replace('gt', ' gt ').replace('lt', ' lt ')
    processed = processed.replace('ge', ' ge ').replace('le', ' le ')
    processed = processed.replace('and', ' and ').replace('or', ' or ')
    # 拆分并过滤空字符串
    tokens = [t.strip() for t in processed.split() if t.strip()]
    return tokens

调用后,Age gt 18 and Status eq 'Active'会得到['Age', 'gt', '18', 'and', 'Status', 'eq', "'Active'"]

2. 语法解析与SQL生成

基于tokens递归解析,先处理括号内的子表达式,再处理比较运算,最后处理逻辑运算,直接生成SQL条件:

def parse_tokens(tokens):
    if not tokens:
        return ""
    
    # 处理括号包裹的子表达式
    if tokens[0] == '(':
        close_idx = tokens.index(')')
        inner_sql = parse_tokens(tokens[1:close_idx])
        remaining = tokens[close_idx+1:]
        if remaining:
            return f"({inner_sql}) {parse_tokens(remaining)}"
        return f"({inner_sql})"
    
    # 处理比较运算
    if len(tokens) >=3 and tokens[1] in ['eq','ne','gt','lt','ge','le']:
        field = tokens[0]
        op_map = {'eq':'=', 'ne':'!=', 'gt':'>', 'lt':'<', 'ge':'>=', 'le':'<='}
        op = op_map[tokens[1]]
        value = tokens[2]
        remaining = tokens[3:]
        if remaining:
            return f"{field} {op} {value} {parse_tokens(remaining)}"
        return f"{field} {op} {value}"
    
    # 处理逻辑运算符
    if tokens[0] in ['and','or']:
        return f" {tokens[0].upper()} {parse_tokens(tokens[1:])}"
    
    return ""

调用示例:

filter_str = "Age gt 18 and (Status eq 'Active' or Status eq 'Pending')"
tokens = tokenize_filter(filter_str)
sql_where = parse_tokens(tokens)
# 输出结果:Age > 18 AND (Status = 'Active' OR Status = 'Pending')

四、安全注意事项

  • 字段名白名单验证:解析出的字段名必须与目标表的实际字段匹配,防止恶意注入(比如用户输入1=1作为字段名)
  • 值的转义处理:字符串值要做SQL转义(比如把单引号'转成''),避免注入风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:15:51