Backend Development 13 min read

Rule Engine Definition, Execution, and Its Implementation in ZhiZhuan Risk Control

This article explains the concept and execution methods of rule engines, describes the forward‑link inference approach used by ZhiZhuan’s risk‑control engine, and details the evolution from hard‑coded rules to feature‑engineered expressions using the Aviator expression engine, highlighting configuration, data sources, and practical examples.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Rule Engine Definition, Execution, and Its Implementation in ZhiZhuan Risk Control

Preface

Risk control is responsible for limiting business risk. During risk identification, massive user behavior and information must be evaluated to reach a decision. Maintaining large amounts of business logic in code is costly and risky, so separating business code from complex logic becomes urgent.

Definition of a Rule Engine

A rule engine, evolved from inference engines, is a component embedded in applications that separates business decisions from application code and allows decisions to be written using predefined semantic modules. It receives data input, interprets business rules, and makes decisions based on those rules.

The diagram below shows the components of a rule engine:

1) Feature set: the current input data (e.g., user object zzuser)

2) Condition: logical judgment

3) Rule: logical judgment on features that yields a conclusion

4) Rule set: a collection of multiple rules

Rule engine inference methods are of two types:

Forward‑link inference: data‑driven, derives conclusions from user behavior and basic information.

Backward‑link inference: goal‑driven, starts from a hypothesized conclusion and infers which user behaviors and information satisfy it.

Execution of a Rule Engine

Rule engine execution can be interpreted, compiled, or custom.

Interpreted Execution

Expressions are converted to target code line by line and executed sequentially.

Compiled Execution

Expressions are dynamically compiled into bytecode in one step and then executed.

Custom Execution

Before introducing an expression engine, custom parsing was used.

Example:

Feature a, feature b, feature c → compute feature d

d = (a+b) / c  – a simple arithmetic expression.

Computers find such expressions difficult, so they are transformed into Reverse Polish Notation (RPN) for easier evaluation.

The RPN for the above expression is: ab+c/

This allows the computer to compute the expression value straightforwardly.

ZhiZhuan Risk‑Control Rule Engine

The ZhiZhuan risk‑control rule engine is a forward‑link inference engine driven by data to infer conclusions. For example, to detect prohibited items, a model score greater than 0.9 can indicate a violation.

Feature: model score

Operator: greater than

Threshold: 0.9

These three parts constitute a rule.

The ZhiZhuan rule engine has three development stages:

Stage 1: Hard‑coded phase – all rules are written in code, resulting in poor maintainability and extensibility.

Stage 2: Rule‑engine phase – abstract business logic into a configurable platform, greatly improving rule agility. The diagram below shows a use‑case of rule execution: Features (by type) User features: nickname, age, registration time, etc. Product features: content, title, etc. Order features: amount, category, etc. Operators Operators include greater than, less than, equal, sensitive‑word match, user tags, etc. Result Rule hit or not hit. The following diagram shows an actual rule configuration (whether the current price of a product is ≤ 30000 cents):

Stage 3: Feature‑engineering phase – reduces the effort of developing and deploying features.

Introduction of an Expression Engine

1) Choosing an Expression Engine

Aviator

Fel

Execution speed

Fast

Fast

Jar size

70kB

200kB

Community activity

Very active

Average

Execution mode

Dynamic compile / interpret

Dynamic compile / interpret

Both performed similarly, but Aviator was chosen for its smaller size and more active community.

2) Aviator Expression Features

Supports most operators (arithmetic, relational, logical, bitwise, regex (=~), ternary (?:)), operator precedence, assignment, short‑circuit logic, rich types (nil, numbers, strings, regex, dates, variables) with automatic conversion, lambda functions, closures, a powerful standard library, custom functions, operator overloading, BigInteger/BigDecimal, and is lightweight and high‑performance.

3) Practical Use of Aviator in Feature Engineering

(1) Basic feature values – e.g., orderFeature.price, infoFeature.title, userFeature.nickname (where orderFeature, infoFeature, userFeature are entity objects).

(2) Basic arithmetic on features – e.g., compute the proportion of phone products: long(infoFeature.phoneTotalCount)*100/long(infoFeature.totalInfoCount)

(3) Built‑in functions – e.g., string length: string.length(infoFeature.title)

(4) Custom functions – e.g., retrieve a Redis value: jodisFeature('price_median', infoFeature.cateChildId)

(5) Lambda expressions – e.g., transform an order flow list to compute delivery‑to‑confirmation time: seq.get(map(filter(orderFeature.orderFlow,lambda(x)->(x.status==5)end),lambda(y)->y.latestOpTime end),0)-order.deliverTime

Feature Data Sources

After introducing the expression engine, features depend on data sources, which can be a bottleneck. Data sources come from either request parameters or service calls.

1) Feature Mapping

Feature mapping converts business parameters into required features. A custom function paramget('uid') fetches the user ID from the parameter map.

To handle inconsistent field names across MQ messages (e.g., uid vs userId), a mapping layer normalizes fields before rule evaluation.

2) Configurable Interface Calls

Configurable interface calls allow the risk engine to obtain data from other services. By configuring service name, class, method, parameters, and values, the engine can retrieve needed data, such as the number of accounts linked to a user's unionid.

The configuration table includes service name, fully‑qualified class name, interface name, parameters, and parameter values. The response example is {"code":0,"body":3}. Using commonfeature(13) to call the service and jsongain(..., 'body') to extract the value demonstrates the workflow.

Conclusion

This article introduced the definition and execution methods of rule engines, and detailed how a rule engine is applied in risk control to make business data sources and risk logic configurable, dramatically reducing development and maintenance costs.

rule enginefeature engineeringbackend developmentexpression-enginerisk control
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.