SnEL 表达式的转换
SnEL 在解析表达式后,会形成一个抽象语法树(AST)。基于 AST 可以中转解析为新的语法,或者处理代码,或代码结构。
比如,转换为 Sql,Redis,ElasticSearch filter..
1、中转打印
String expression = "(((age > 18 AND salary < 5000) OR (NOT isMarried)) AND label IN ['aa','bb'] AND title NOT IN ['cc','dd']) OR vip=='l3'";
//解析出表达式
Expression root = SnEL.parse(expression);
//打印表达式树
PrintUtil.printTree(root);
2、Transformer<S,T>
接口中
为了转换更具规范性,我们定义了转换的专用接口
public interface Transformer<S,T> {
/**
* 转换
*/
T transform(Expression<S> source);
}
参考:打印语法树工具 PrintUtil
public class PrintUtil {
public static void printTree(Expression node) {
printTreeDo(node, 0);
}
static void printTreeDo(Expression node, int level) {
if (node instanceof VariableNode) {
System.out.println(prefix(level) + "Field: " + ((VariableNode) node).getName());
} else if (node instanceof ConstantNode) {
Object value = ((ConstantNode) node).getValue();
if (value instanceof String) {
System.out.println(prefix(level) + "Value: '" + value + "'");
} else {
System.out.println(prefix(level) + "Value: " + value);
}
} else if (node instanceof ComparisonNode) {
ComparisonNode compNode = (ComparisonNode) node;
System.out.println(prefix(level) + "Comparison: " + compNode.getOperator());
printTreeDo(compNode.getLeft(), level + 1);
printTreeDo(compNode.getRight(), level + 1);
} else if (node instanceof LogicalNode) {
LogicalNode opNode = (LogicalNode) node;
System.out.println(prefix(level) + "Logical: " + opNode.getOperator());
printTreeDo(opNode.getLeft(), level + 1);
printTreeDo(opNode.getRight(), level + 1);
}
}
static String prefix(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(" ");
}
return sb.toString();
}
}
参考:转为 milvus 过滤表达式
String filter = FilterTransformer.getInstance(root);
public class FilterTransformer implements Transformer<Boolean, String> {
private static FilterTransformer instance = new FilterTransformer();
public static FilterTransformer getInstance() {
return instance;
}
@Override
public String transform(Expression<Boolean> filterExpression) {
StringBuilder buf = new StringBuilder();
parseFilterExpression(filterExpression, buf);
return buf.toString();
}
private void parseFilterExpression(Expression<Boolean> filterExpression, StringBuilder buf) {
if (filterExpression instanceof VariableNode) {
buf.append("metadata[\"").append(((VariableNode) filterExpression).getName()).append("\"]");
} else if (filterExpression instanceof ConstantNode) {
Object value = ((ConstantNode) filterExpression).getValue();
// 判断是否为Collection类型
if (((ConstantNode) filterExpression).isCollection()) {
buf.append("[");
for (Object item : (Iterable<?>) value) {
if (item instanceof String) {
buf.append("\"").append(item).append("\"");
} else {
buf.append(item);
}
buf.append(", ");
}
if (buf.length() > 1) {
buf.setLength(buf.length() - 1);
}
buf.append("]");
} else if (value instanceof String) {
buf.append("\"").append(value).append("\"");
} else {
buf.append(value);
}
} else if (filterExpression instanceof ComparisonNode) {
ComparisonNode compNode = (ComparisonNode) filterExpression;
buf.append("(");
parseFilterExpression(compNode.getLeft(), buf);
buf.append(" ").append(compNode.getOperator().getCode().toLowerCase()).append(" ");
parseFilterExpression(compNode.getRight(), buf);
buf.append(")");
} else if (filterExpression instanceof LogicalNode) {
LogicalNode opNode = (LogicalNode) filterExpression;
buf.append("(");
if (opNode.getRight() != null) {
parseFilterExpression(opNode.getLeft(), buf);
buf.append(" ").append(opNode.getOperator().getCode().toLowerCase()).append(" ");
parseFilterExpression(opNode.getRight(), buf);
} else {
buf.append(opNode.getOperator().getCode()).append(" ");
parseFilterExpression(opNode.getLeft(), buf);
}
buf.append(")");
}
}
}
参考:转为 redis 过滤表达式
String filter = FilterTransformer.getInstance(root);
public class FilterTransformer implements Transformer<Boolean, String> {
private static FilterTransformer instance = new FilterTransformer();
public static FilterTransformer getInstance() {
return instance;
}
@Override
public String transform(Expression<Boolean> filterExpression) {
if (filterExpression == null) {
return "*";
}
try {
StringBuilder buf = new StringBuilder();
parseFilterExpression(filterExpression, buf);
if (buf.length() == 0) {
return "*";
}
return buf.toString();
} catch (Exception e) {
System.err.println("Error processing filter expression: " + e.getMessage());
return "*";
}
}
/**
* 解析QueryCondition中的filterExpression,转换为Redis Search语法
*
* @param filterExpression
* @param buf
*/
private void parseFilterExpression(Expression<Boolean> filterExpression, StringBuilder buf) {
if (filterExpression == null) {
return;
}
if (filterExpression instanceof VariableNode) {
// 变量节点,获取字段名 - 为Redis添加@前缀
String name = ((VariableNode) filterExpression).getName();
buf.append("@").append(name);
} else if (filterExpression instanceof ConstantNode) {
ConstantNode node = (ConstantNode) filterExpression;
// 常量节点,获取值
Object value = node.getValue();
if (node.isCollection()) {
// 集合使用Redis的OR语法 {val1|val2|val3}
buf.append("{");
boolean first = true;
for (Object item : (Collection<?>) value) {
if (!first) {
buf.append("|"); // Redis 使用 | 分隔OR条件
}
buf.append(item);
first = false;
}
buf.append("}");
} else if (value instanceof String) {
// 字符串值使用大括号
buf.append("{").append(value).append("}");
} else {
buf.append(value);
}
} else if (filterExpression instanceof ComparisonNode) {
ComparisonNode node = (ComparisonNode) filterExpression;
ComparisonOp operator = node.getOperator();
Expression left = node.getLeft();
Expression right = node.getRight();
// 比较节点
switch (operator) {
case eq:
parseFilterExpression(left, buf);
buf.append(":");
parseFilterExpression(right, buf);
break;
case neq:
buf.append("-");
parseFilterExpression(left, buf);
buf.append(":");
parseFilterExpression(right, buf);
break;
case gt:
parseFilterExpression(left, buf);
buf.append(":[");
parseFilterExpression(right, buf);
buf.append(" +inf]");
break;
case gte:
parseFilterExpression(left, buf);
buf.append(":[");
parseFilterExpression(right, buf);
buf.append(" +inf]");
break;
case lt:
parseFilterExpression(left, buf);
buf.append(":[-inf ");
parseFilterExpression(right, buf);
buf.append("]");
break;
case lte:
parseFilterExpression(left, buf);
buf.append(":[-inf ");
parseFilterExpression(right, buf);
buf.append("]");
break;
case in:
parseFilterExpression(left, buf);
buf.append(":");
parseFilterExpression(right, buf);
break;
case nin:
buf.append("-");
parseFilterExpression(left, buf);
buf.append(":");
parseFilterExpression(right, buf);
break;
default:
parseFilterExpression(left, buf);
buf.append(":");
parseFilterExpression(right, buf);
break;
}
} else if (filterExpression instanceof LogicalNode) {
LogicalNode node = (LogicalNode) filterExpression;
LogicalOp operator = node.getOperator();
Expression left = node.getLeft();
Expression right = node.getRight();
buf.append("(");
if (right != null) {
// 二元操作符 (AND, OR)
parseFilterExpression(left, buf);
switch (operator) {
case AND:
buf.append(" "); // Redis Search 使用空格表示 AND
break;
case OR:
buf.append(" | "); // Redis Search 使用 | 表示 OR
break;
default:
// 其他操作符,默认用空格
buf.append(" ");
break;
}
parseFilterExpression(right, buf);
} else {
// 一元操作符 (NOT)
switch (operator) {
case NOT:
buf.append("-"); // Redis Search 使用 - 表示 NOT
break;
default:
// 其他一元操作符,不添加前缀
break;
}
parseFilterExpression(left, buf);
}
buf.append(")");
}
}
}
参考:转为 elasticsearch 过滤对象
Map<String, Object> filter = FilterTransformer.getInstance(root);
public class FilterTransformer implements Transformer<Boolean, Map<String, Object>> {
private static FilterTransformer instance = new FilterTransformer();
public static FilterTransformer getInstance() {
return instance;
}
/**
* 将过滤表达式转换为Elasticsearch查询
*
* @param filterExpression 过滤表达式
* @return Elasticsearch查询对象
*/
@Override
public Map<String, Object> transform(Expression<Boolean> filterExpression) {
if (filterExpression == null) {
return null;
}
if (filterExpression instanceof VariableNode) {
// 变量节点,获取字段名
String fieldName = ((VariableNode) filterExpression).getName();
Map<String, Object> exists = new HashMap<>();
Map<String, Object> field = new HashMap<>();
field.put("field", fieldName);
exists.put("exists", field);
return exists;
} else if (filterExpression instanceof ConstantNode) {
// 常量节点,根据值类型和是否为集合创建不同的查询
ConstantNode node = (ConstantNode) filterExpression;
Object value = node.getValue();
Boolean isCollection = node.isCollection();
if (Boolean.TRUE.equals(value)) {
Map<String, Object> matchAll = new HashMap<>();
matchAll.put("match_all", new HashMap<>());
return matchAll;
} else if (Boolean.FALSE.equals(value)) {
Map<String, Object> boolQuery = new HashMap<>();
Map<String, Object> mustNot = new HashMap<>();
mustNot.put("match_all", new HashMap<>());
boolQuery.put("must_not", mustNot);
return boolQuery;
}
return null;
} else if (filterExpression instanceof ComparisonNode) {
// 比较节点,处理各种比较运算符
ComparisonNode node = (ComparisonNode) filterExpression;
ComparisonOp operator = node.getOperator();
Expression left = node.getLeft();
Expression right = node.getRight();
// 获取字段名和值
String fieldName = null;
Object value = null;
if (left instanceof VariableNode && right instanceof ConstantNode) {
fieldName = ((VariableNode) left).getName();
value = ((ConstantNode) right).getValue();
} else if (right instanceof VariableNode && left instanceof ConstantNode) {
fieldName = ((VariableNode) right).getName();
value = ((ConstantNode) left).getValue();
// 反转操作符
operator = reverseOperator(operator);
} else {
// 不支持的比较节点结构
return null;
}
// 根据操作符构建相应的查询
switch (operator) {
case eq:
return createTermQuery(fieldName, value);
case neq:
return createMustNotQuery(createTermQuery(fieldName, value));
case gt:
return createRangeQuery(fieldName, "gt", value);
case gte:
return createRangeQuery(fieldName, "gte", value);
case lt:
return createRangeQuery(fieldName, "lt", value);
case lte:
return createRangeQuery(fieldName, "lte", value);
case in:
if (value instanceof Collection) {
return createTermsQuery(fieldName, (Collection<?>) value);
}
return createTermQuery(fieldName, value);
case nin:
if (value instanceof Collection) {
return createMustNotQuery(createTermsQuery(fieldName, (Collection<?>) value));
}
return createMustNotQuery(createTermQuery(fieldName, value));
default:
return null;
}
} else if (filterExpression instanceof LogicalNode) {
// 逻辑节点,处理AND, OR, NOT
LogicalNode node = (LogicalNode) filterExpression;
LogicalOp operator = node.getOperator();
Expression left = node.getLeft();
Expression right = node.getRight();
if (right != null) {
// 二元逻辑运算符 (AND, OR)
Map<String, Object> leftQuery = transform(left);
Map<String, Object> rightQuery = transform(right);
if (leftQuery == null || rightQuery == null) {
return null;
}
Map<String, Object> boolQuery = new HashMap<>();
List<Map<String, Object>> conditions = new ArrayList<>();
conditions.add(leftQuery);
conditions.add(rightQuery);
switch (operator) {
case AND:
boolQuery.put("must", conditions);
break;
case OR:
boolQuery.put("should", conditions);
break;
default:
return null;
}
Map<String, Object> result = new HashMap<>();
result.put("bool", boolQuery);
return result;
} else if (left != null) {
// 一元逻辑运算符 (NOT)
Map<String, Object> operandQuery = transform(left);
if (operandQuery == null) {
return null;
}
if (operator == LogicalOp.NOT) {
return createMustNotQuery(operandQuery);
}
}
}
return null;
}
/**
* 反转比较运算符
*
* @param op 原运算符
* @return 反转后的运算符
*/
private ComparisonOp reverseOperator(ComparisonOp op) {
switch (op) {
case gt:
return ComparisonOp.lt;
case gte:
return ComparisonOp.lte;
case lt:
return ComparisonOp.gt;
case lte:
return ComparisonOp.gte;
default:
return op;
}
}
/**
* 创建term查询
*
* @param field 字段名
* @param value 值
* @return 查询对象
*/
private Map<String, Object> createTermQuery(String field, Object value) {
Map<String, Object> termValue = new HashMap<>();
termValue.put("value", value);
Map<String, Object> term = new HashMap<>();
term.put(field, termValue);
Map<String, Object> result = new HashMap<>();
result.put("term", term);
return result;
}
/**
* 创建terms查询(适用于集合)
*
* @param field 字段名
* @param values 值集合
* @return 查询对象
*/
private Map<String, Object> createTermsQuery(String field, Collection<?> values) {
Map<String, Object> terms = new HashMap<>();
terms.put(field, new ArrayList<>(values));
Map<String, Object> result = new HashMap<>();
result.put("terms", terms);
return result;
}
/**
* 创建范围查询
*
* @param field 字段名
* @param operator 操作符(gt, gte, lt, lte)
* @param value 值
* @return 查询对象
*/
private Map<String, Object> createRangeQuery(String field, String operator, Object value) {
Map<String, Object> rangeValue = new HashMap<>();
rangeValue.put(operator, value);
Map<String, Object> range = new HashMap<>();
range.put(field, rangeValue);
Map<String, Object> result = new HashMap<>();
result.put("range", range);
return result;
}
/**
* 创建must_not查询(NOT操作)
*
* @param query 要否定的查询
* @return 查询对象
*/
private Map<String, Object> createMustNotQuery(Map<String, Object> query) {
if (query == null) {
return null;
}
Map<String, Object> boolQuery = new HashMap<>();
List<Map<String, Object>> mustNot = new ArrayList<>();
mustNot.add(query);
boolQuery.put("must_not", mustNot);
Map<String, Object> result = new HashMap<>();
result.put("bool", boolQuery);
return result;
}
}