mirror of
https://github.com/OpenSPG/openspg.git
synced 2025-12-25 06:06:10 +00:00
fix(reasoner): fix qlexpress keyword (#164)
Co-authored-by: FishJoy <chengqiang.cq@antgroup.com> Co-authored-by: peilong <peilong.zpl@antgroup.com> Co-authored-by: kejian <wangshaofei.wsf@antgroup.com>
This commit is contained in:
parent
3f9fadb22c
commit
8c8074f92f
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2023 OpenSPG Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied.
|
||||
*/
|
||||
package com.antgroup.openspg.reasoner.common.utils;
|
||||
/**
|
||||
* @author peilong.zpl
|
||||
* @version $Id: FunctionUtils.java, v 0.1 2024-03-19 21:42 peilong.zpl Exp $$
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JavaFunctionCaller<T, R> {
|
||||
R apply(T t);
|
||||
}
|
||||
@ -15,13 +15,21 @@ package com.antgroup.openspg.reasoner.lube.utils.transformer.impl
|
||||
|
||||
import com.antgroup.openspg.reasoner.common.trees.Transform
|
||||
import com.antgroup.openspg.reasoner.common.types.KTString
|
||||
import com.antgroup.openspg.reasoner.common.utils.JavaFunctionCaller
|
||||
import com.antgroup.openspg.reasoner.lube.common.expr._
|
||||
import com.antgroup.openspg.reasoner.lube.common.graph.IRNode
|
||||
import com.antgroup.openspg.reasoner.lube.common.rule.Rule
|
||||
import com.antgroup.openspg.reasoner.lube.utils.ExprUtils
|
||||
import com.antgroup.openspg.reasoner.lube.utils.transformer.ExprTransformer
|
||||
|
||||
class Expr2QlexpressTransformer extends ExprTransformer[String] {
|
||||
|
||||
class Expr2QlexpressTransformer(
|
||||
fieldNameTransFunc: JavaFunctionCaller[String, String]
|
||||
= new JavaFunctionCaller[String, String] {
|
||||
override def apply(t: String): String = t
|
||||
}
|
||||
)
|
||||
extends ExprTransformer[String] {
|
||||
|
||||
val binaryOpSetTrans: PartialFunction[BinaryOpSet, String] = {
|
||||
case BAdd => " + "
|
||||
@ -50,7 +58,7 @@ class Expr2QlexpressTransformer extends ExprTransformer[String] {
|
||||
case Abs => "abs(%s)"
|
||||
case Floor => "floor(%s)"
|
||||
case Ceil => "ceil(%s)"
|
||||
case GetField(fieldName) => "%s." + fieldName
|
||||
case GetField(fieldName) => "%s." + fieldNameTransFunc(fieldName)
|
||||
}
|
||||
|
||||
def lambdaFuncParse(curVariableSet: Set[String], lambdaFunc: Expr): (String, String) = {
|
||||
|
||||
@ -25,6 +25,7 @@ import com.antgroup.openspg.reasoner.lube.common.pattern.Pattern;
|
||||
import com.antgroup.openspg.reasoner.lube.logical.PathVar;
|
||||
import com.antgroup.openspg.reasoner.lube.logical.PropertyVar;
|
||||
import com.antgroup.openspg.reasoner.lube.logical.Var;
|
||||
import com.antgroup.openspg.reasoner.udf.rule.RuleRunner;
|
||||
import com.antgroup.openspg.reasoner.utils.RunnerUtil;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
@ -93,13 +94,16 @@ public class SelectRowImpl implements Serializable {
|
||||
|
||||
private Object getSelectValue(String alias, String propertyName, Map<String, Object> context) {
|
||||
if (Constants.PROPERTY_JSON_KEY.equals(propertyName)) {
|
||||
Object propertyMap = context.get(alias);
|
||||
Object propertyMap = RunnerUtil.recoverContextKeys(context.get(alias));
|
||||
return JSON.toJSONString(
|
||||
propertyMap,
|
||||
SerializerFeature.PrettyFormat,
|
||||
SerializerFeature.DisableCircularReferenceDetect,
|
||||
SerializerFeature.SortField);
|
||||
} else if (Constants.GET_PATH_KEY.equals(propertyName)) {
|
||||
for (Map.Entry<String, Object> entry : context.entrySet()) {
|
||||
RunnerUtil.recoverContextKeys(entry.getValue());
|
||||
}
|
||||
return JSON.toJSONString(
|
||||
context,
|
||||
SerializerFeature.PrettyFormat,
|
||||
@ -107,6 +111,6 @@ public class SelectRowImpl implements Serializable {
|
||||
SerializerFeature.SortField);
|
||||
}
|
||||
Map<String, Object> propertyMap = (Map<String, Object>) context.get(alias);
|
||||
return propertyMap.get(propertyName);
|
||||
return propertyMap.get(RuleRunner.convertPropertyName(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import scala.Tuple2;
|
||||
import scala.collection.JavaConversions;
|
||||
@ -425,7 +426,7 @@ public class RunnerUtil {
|
||||
IProperty property = vertex.getValue();
|
||||
if (null != property) {
|
||||
for (String key : property.getKeySet()) {
|
||||
vertexProperty.put(key, property.get(key));
|
||||
vertexProperty.put(RuleRunner.convertPropertyName(key), property.get(key));
|
||||
}
|
||||
}
|
||||
vertexProperty.put(Constants.CONTEXT_LABEL, getVertexType(vertex));
|
||||
@ -477,7 +478,7 @@ public class RunnerUtil {
|
||||
IProperty property = edge.getValue();
|
||||
if (null != property) {
|
||||
for (String key : property.getKeySet()) {
|
||||
edgeProperty.put(key, property.get(key));
|
||||
edgeProperty.put(RuleRunner.convertPropertyName(key), property.get(key));
|
||||
}
|
||||
}
|
||||
edgeProperty.put(Constants.CONTEXT_LABEL, edgeType);
|
||||
@ -502,7 +503,7 @@ public class RunnerUtil {
|
||||
IProperty property = edge.getValue();
|
||||
if (null != property) {
|
||||
for (String key : property.getKeySet()) {
|
||||
edgeProperty.put(key, property.get(key));
|
||||
edgeProperty.put(RuleRunner.convertPropertyName(key), property.get(key));
|
||||
}
|
||||
}
|
||||
edgeProperty.put(Constants.REPEAT_EDGE_FLAG, true);
|
||||
@ -540,7 +541,7 @@ public class RunnerUtil {
|
||||
IProperty property = optionalEdge.getValue();
|
||||
if (null != property) {
|
||||
for (String key : property.getKeySet()) {
|
||||
edgeProperty.put(key, property.get(key));
|
||||
edgeProperty.put(RuleRunner.convertPropertyName(key), property.get(key));
|
||||
}
|
||||
}
|
||||
edgeProperty.put(Constants.OPTIONAL_EDGE_FLAG, true);
|
||||
@ -567,6 +568,31 @@ public class RunnerUtil {
|
||||
return vertexProperty;
|
||||
}
|
||||
|
||||
/** recover context keys */
|
||||
public static Map<String, Object> recoverContextKeys(Map<String, Object> context) {
|
||||
Map<String, Object> conflictKey = new HashMap<>();
|
||||
Iterator<Map.Entry<String, Object>> it = context.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, Object> entry = it.next();
|
||||
if (!RuleRunner.isConflictPropertyName(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
it.remove();
|
||||
conflictKey.put(RuleRunner.recoverPropertyName(entry.getKey()), entry.getValue());
|
||||
}
|
||||
if (MapUtils.isNotEmpty(conflictKey)) {
|
||||
context.putAll(conflictKey);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static Object recoverContextKeys(Object context) {
|
||||
if (!(context instanceof Map)) {
|
||||
return context;
|
||||
}
|
||||
return recoverContextKeys((Map<String, Object>) context);
|
||||
}
|
||||
|
||||
public static final String FLATTEN_SEPARATOR = ".";
|
||||
|
||||
/**
|
||||
|
||||
@ -163,7 +163,8 @@ public class RuleRunnerTest {
|
||||
RuleExprParser parser = new RuleExprParser();
|
||||
|
||||
Expr expr = parser.parse("\"\"");
|
||||
Expr2QlexpressTransformer transformer = new Expr2QlexpressTransformer();
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(expr)));
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
@ -402,7 +403,8 @@ public class RuleRunnerTest {
|
||||
+ "and "
|
||||
+ "not contains_any(s.status, [\"无\", \"不\", \"未见\"])");
|
||||
|
||||
Expr2QlexpressTransformer transformer = new Expr2QlexpressTransformer();
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(e)));
|
||||
@ -427,7 +429,8 @@ public class RuleRunnerTest {
|
||||
RuleExprParser ruleExprParser = new RuleExprParser();
|
||||
Expr e = ruleExprParser.parse("contains_any(s.entity, '包膜') and contains_any(s.entity, a)");
|
||||
|
||||
Expr2QlexpressTransformer transformer = new Expr2QlexpressTransformer();
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(e)));
|
||||
@ -447,6 +450,39 @@ public class RuleRunnerTest {
|
||||
Assert.assertFalse(rst);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeywordConvert() {
|
||||
RuleExprParser ruleExprParser = new RuleExprParser();
|
||||
Expr e = ruleExprParser.parse("A.alias == B.alias && A.when == B.id");
|
||||
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(e)));
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put(
|
||||
"A",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put(RuleRunner.convertPropertyName("alias"), "alias_value");
|
||||
put(RuleRunner.convertPropertyName("when"), "id_value");
|
||||
}
|
||||
});
|
||||
|
||||
context.put(
|
||||
"B",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put(RuleRunner.convertPropertyName("alias"), "alias_value");
|
||||
put(RuleRunner.convertPropertyName("id"), "id_value");
|
||||
}
|
||||
});
|
||||
|
||||
boolean rst = RuleRunner.getInstance().check(context, rules, "");
|
||||
Assert.assertTrue(rst);
|
||||
}
|
||||
|
||||
private Map<String, Object> getRepeatTestContext() {
|
||||
Map<String, Set<IVertex<IVertexId, IProperty>>> alias2VertexMap = new HashMap<>();
|
||||
alias2VertexMap.put(
|
||||
@ -535,7 +571,8 @@ public class RuleRunnerTest {
|
||||
Assert.assertTrue(aliasSet.contains("A"));
|
||||
Assert.assertTrue(aliasSet.contains("B"));
|
||||
Assert.assertTrue(aliasSet.contains("e"));
|
||||
Expr2QlexpressTransformer transformer = new Expr2QlexpressTransformer();
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(e)));
|
||||
Assert.assertEquals(
|
||||
@ -550,7 +587,8 @@ public class RuleRunnerTest {
|
||||
@Test
|
||||
public void testRepeatReduce2() {
|
||||
Expr e = ruleExprParser.parse("e.edges().reduce((pre, cur) => cur.rate * pre, 1)");
|
||||
Expr2QlexpressTransformer transformer = new Expr2QlexpressTransformer();
|
||||
Expr2QlexpressTransformer transformer =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
List<String> rules =
|
||||
Lists.newArrayList(JavaConversions.asJavaCollection(transformer.transform(e)));
|
||||
Assert.assertEquals(
|
||||
|
||||
@ -31,9 +31,13 @@ import com.ql.util.express.DefaultContext;
|
||||
import com.ql.util.express.ExpressRunner;
|
||||
import com.ql.util.express.Operator;
|
||||
import com.ql.util.express.exception.QLCompileException;
|
||||
import com.ql.util.express.parse.KeyWordDefine4Java;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -42,11 +46,39 @@ import scala.Tuple2;
|
||||
public class RuleRunner {
|
||||
private static final Logger log = LoggerFactory.getLogger(RuleRunner.class);
|
||||
|
||||
private static Cache<String, Map<String, Object>> contextCache =
|
||||
private static final Cache<String, Map<String, Object>> contextCache =
|
||||
CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(24, TimeUnit.HOURS).build();
|
||||
|
||||
private final ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
|
||||
private static final Set<String> keywordSet = new HashSet<>();
|
||||
|
||||
static {
|
||||
KeyWordDefine4Java keyWordDefine4Java = new KeyWordDefine4Java();
|
||||
keywordSet.addAll(Arrays.asList(keyWordDefine4Java.keyWords));
|
||||
}
|
||||
|
||||
private static final String CONFLICT_KEY_PREFIX = "__ConflictKey_";
|
||||
/** convert vertex or edge property name to prevent keyword conflicts */
|
||||
public static String convertPropertyName(String propertyName) {
|
||||
if (keywordSet.contains(propertyName)) {
|
||||
return CONFLICT_KEY_PREFIX + propertyName;
|
||||
}
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/** recover property name */
|
||||
public static String recoverPropertyName(String propertyName) {
|
||||
if (!propertyName.startsWith(CONFLICT_KEY_PREFIX)) {
|
||||
return propertyName;
|
||||
}
|
||||
return propertyName.substring(CONFLICT_KEY_PREFIX.length());
|
||||
}
|
||||
|
||||
public static boolean isConflictPropertyName(String propertyName) {
|
||||
return propertyName.startsWith(CONFLICT_KEY_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* set running context
|
||||
*
|
||||
|
||||
@ -22,6 +22,7 @@ import com.antgroup.openspg.reasoner.lube.common.rule.Rule;
|
||||
import com.antgroup.openspg.reasoner.lube.utils.RuleUtils;
|
||||
import com.antgroup.openspg.reasoner.lube.utils.transformer.ExprTransformer;
|
||||
import com.antgroup.openspg.reasoner.lube.utils.transformer.impl.Expr2QlexpressTransformer;
|
||||
import com.antgroup.openspg.reasoner.udf.rule.RuleRunner;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -35,7 +36,8 @@ import scala.collection.immutable.Set;
|
||||
|
||||
public class WareHouseUtils {
|
||||
|
||||
private static final ExprTransformer<String> EXPR_TRANSFORMER = new Expr2QlexpressTransformer();
|
||||
private static final ExprTransformer<String> EXPR_TRANSFORMER =
|
||||
new Expr2QlexpressTransformer(RuleRunner::convertPropertyName);
|
||||
|
||||
/**
|
||||
* get vertex rule string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user