扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
This passage discusses how to integrate a provided drools package into datastream application.
创新互联2013年至今,先为洮南等服务建站,洮南等地企业,进行企业商务咨询服务。为洮南企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。Packaging:
If a maven project is provided by customer. In this case, you need to ensure that the pom file contains the following:
org.drools
drools-bom
pom
xxx
import
org.kie
kie-api
org.drools
drools-compiler
runtime
other dependencies
org.kie
kie-maven-plugin
xxx
true
In addition, a file kmodule.xml
must be added to src\main\resources\META-INF
folder. A minimum kmodule.xml likes like the following.
The default stateless ksession is mandatory.
Rule files can be put in main/resources as normal
The command to create jar file is still mvn package
as normal. However, the jar created is a bit different. Here is a screenshot
Note that there is knowledge base cache file and kmodule file in META-INF. Two rule files in main/resources are shifted out into the root folder.
What if the customer does not provide a maven project? I guess the best strategy is to create a maven project by ourselves. If source code is provided, we just import source code into the maven project, otherwise, use customer provided jar as a maven dependency?
Note that kie module is introduced only after drools 6. So I don't think this will work for drools 5 and below. Also, for drools integration in streamtau, we are using the latest version 7.2.1. So whether earlier version like 6.x is fully compatible still remains a question.
Invocation:
Load rules:
First create a KieServices singleton instance.private final KieServices kieServices = KieServices.Factory.get();
Load the drools package into system:
protected DroolsDataHolder doLoadDroolsModule(DroolsLoadParam droolsLoadParam) {
DroolsParameters origParams = droolsLoadParam.getDroolsParam();
String moduleName = origParams.getModuleName();
try {
InputStream is = droolsDataLoader.getDroolsModuleAsStream(droolsLoadParam);
KieContainer curContainer = DroolsUtils.buildContainer(kieServices, is);
return new DroolsDataHolder(curContainer);
}
catch (Exception ex) {
logger.error("Error loading drools " + moduleName, ex);
}
return null;
}
DroolsDataLoader is an interface that is designed to loads drools package as stream (via either file system or restful interface)
DroolsUtils is the utility class that builds a KieContainer from stream.
public static KieContainer buildContainer(KieServices kieServices, InputStream stream) throws Exception {
Resource wrapped = kieServices.getResources().newInputStreamResource(stream);
KieModule curModule = kieServices.getRepository().addKieModule(wrapped);
ReleaseId releaseId = curModule.getReleaseId();
logger.info("Release id generated for module: {}", releaseId);
KieContainer kContainer = kieServices.newKieContainer(releaseId, DroolsUtils.class.getClassLoader());
return kContainer;
}
The returned DroolsDataHolder is merely a wrapper of KieContainer
public class DroolsDataHolder {
private final KieContainer kieContainer;
public DroolsDataHolder(KieContainer kieContainer) {
this.kieContainer = kieContainer;
}
public KieContainer getKieContainer() {
return kieContainer;
}
public void destroy() {
kieContainer.dispose();
}
}
The loaded DroolsDataHolder will be cached unless rule is changed, which triggers a reload operation
public DroolsDataHolder getOrLoadDroolsModule(DroolsLoadParam droolsLoadParam) {
DroolsParameters origParams = droolsLoadParam.getDroolsParam();
String moduleName = origParams.getModuleName();
dataLock.readLock().lock();
try {
DroolsDataHolder curHolder = containers.get(moduleName);
if (curHolder != null) {
return curHolder;
}
dataLock.readLock().unlock();
dataLock.writeLock().lock();
try {
return doUpdateDroolsModule(droolsLoadParam);
}
finally {
dataLock.readLock().lock();
dataLock.writeLock().unlock();
}
}
finally {
dataLock.readLock().unlock();
}
}
Invoke the drools module:
In stream environment, only stateless drools knowledge session is supported for now. The main reason is that stream is executed in a distributed environment. The session will be created on multiple JVMS, so it is virtually hard to share all the facts globally. Evaluating the rule is quite simple, it is composed of 3 steps:
public Class> getRulePojoClass(DroolsLoadParam droolsLoadParam, String inputPojoClassName) {
DroolsParameters origParams = droolsLoadParam.getDroolsParam();
String moduleName = origParams.getModuleName();
DroolsDataHolder curDataHolder = this.getOrLoadDroolsModule(droolsLoadParam);
if (curDataHolder == null) {
throw new IllegalArgumentException("No drools module found by name: " + moduleName);
}
try {
ClassLoader cl = curDataHolder.getKieContainer().getClassLoader();
Class> inputPojoClass = cl.loadClass(inputPojoClassName);
return inputPojoClass;
} catch (Exception e) {
throw RtException.from(e);
}
}
The good thing about drools module is that it provides a self contained class loading environment. So third party jar dependencies are unlikely to cause conflict with the outside runtime environment. However, when we build an input event to drools engine, we need to use the KieContainer's class loader to find the input event class referenced in rule.
build a stateless kie session and invoke the rule
public List
Under the hood:
Drools class relations
Drools package loading
Things to note:
Drools package can be large and the current approach caches all loaded drools package in memory. The loading time and memory consumption might be a bottleneck of scalability. A better approach will be building a standalone rule server, where it manages rules and exposes a rest api to stream application.
Find out input metadata for rule: it is possible to find out java class of each rule variable. This is useful as a hint to map stream data to rule input.
public static Map> getRuleInputMeta(KieBase kieBase,
String rulePkgName, String ruleName) {
RuleImpl r = (RuleImpl)kieBase.getRule(rulePkgName, ruleName);
List elements = r.getLhs().getChildren();
Pattern curPattern = null;
String curId = null;
ObjectType curObjType = null;
Map> result = new HashMap>();
for (RuleConditionElement nextElem : elements) {
if (nextElem instanceof Pattern) {
curPattern = (Pattern)nextElem;
curObjType = curPattern.getObjectType();
curId = curPattern.getDeclaration().getIdentifier();
result.put(curId, curObjType.getValueType().getClassType());
}
}
return result;
}
Maven shade plugin and drools jar:
To use the drools java api, multiple jars need to be included as maven dependency.
However, the special thing about drools jars is that each one contains a file kie.conf
(Eg. drools-core.jar, kie-internal.jar). The default behavior of maven shade plugin is that kie.conf will overwrite each other and causes a runtime error when deploying the shaded jar to flink. Mitigation to this problem is to configure maven shadow plugin parameters properly so that the content of each kie.conf will be appended to the combined file instead of overwritten.
org.apache.maven.plugins
maven-shade-plugin
package
shade
META-INF/kie.conf
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流