Flink's Complex Event Processing (CEP) library lets you dynamically process complex event streams, detect specific event patterns in real time, and trigger alerts. In e-commerce marketing, you can use Flink CEP to monitor user behavior and transaction data in real time, identify abnormal or key events, and send timely alerts.
Background
As the e-commerce industry expands, the volume of user behavior and transaction data is increasing exponentially. Traditional batch processing methods are too slow to identify and respond to abnormal behavior, system risks, and user churn. In contrast, a dynamic Complex Event Processing (CEP) engine can model and analyze multi-stage user behavior to automatically detect complex event patterns and trigger alerts at the first sign of risk. This is the core advantage of dynamic CEP in real-time business operations. It has the following three key features:
Low latency: Enables millisecond-level responses and supports in-process alerting rather than post-event analysis for rapid decision-making.
Flexible and configurable rules: Supports dynamic rule updates to adapt quickly to business changes without service restarts.
Powerful complex event detection: Supports advanced logic matching, such as multi-event sequences, time windows, and combined conditions, to accurately capture complex business scenarios.
In the e-commerce industry, typical use cases for dynamic CEP include:
Scenario | Description |
Cross-selling and up-selling opportunities | When browsing products, users often show interest across categories, such as viewing a phone and then looking at headphones or power banks. This behavior presents cross-selling and up-selling opportunities. By precisely recommending complementary products (like phone cases or headphones) or offering bundled deals (such as "Phone + Headphones Combo Discount"), the platform can increase the purchase rate of additional items, raise the average order value, and improve the user experience. This enhances user stickiness and drives business growth. |
High-value product purchase conversion | A high-value conversion occurs when a user adds a high-value product to the cart and completes the purchase. By identifying this conversion path in real time, the platform can analyze user decision-making characteristics, optimize product recommendation strategies, and increase the repurchase rate and average order value for high-value products. |
High-intent user identification | A user who browses the same product multiple times in a short period indicates high purchase intent. By identifying this behavior and triggering personalized marketing (such as exclusive coupons or stock reminders), the platform can accelerate the user's decision-making process, improve conversion rates, and enhance the user experience, thereby driving sales growth. |
Price-sensitive user engagement | Price-sensitive users often repeatedly browse a product and only add it to the cart when the price drops. By analyzing this behavior, the platform can send notifications or targeted offers (such as "The item you're watching is now on sale!") when the price changes. This improves conversion rates and optimizes user engagement efficiency. |
Churn risk alert | A user who frequently browses products but does not make a purchase for an extended period may be at risk of churning. By identifying such behavior and taking recovery actions (such as sending exclusive coupons or recommending popular products), the platform can effectively reduce the churn rate, extend the user's lifecycle, and increase both user retention and platform revenue. |
Solution architecture
Flink CEP is a library in Apache Flink for processing complex event patterns. By defining complex event patterns, Flink CEP monitors an event stream in real time, identifies matching event sequences, and outputs the results. The solution architecture can be summarized as follows:

Event Stream
An event stream is the input source for CEP. It is typically a continuous data stream that contains a series of time-ordered events. Each event can have multiple attributes for subsequent pattern matching.
Pattern and Rule Definitions
You define event patterns and rules that describe the desired event sequences or combinations. Patterns can include event order, time constraints, and filter conditions. For example, you can define a pattern for "Event A is followed by Event B within 10 seconds."
CEP Engine Analysis
The CEP engine receives the event stream and analyzes it based on the defined patterns and rules. The engine continuously monitors the event stream and matches incoming events against the defined patterns. During the matching process, the engine considers event order, attribute conditions, and time window constraints.
CEP Matching Outputs
When an event sequence in the event stream matches a defined pattern, the CEP engine generates an output. This output can be the matched event sequence, an action triggered by a rule, or another user-defined output format. The matching results can be used for subsequent processing, such as alerting, decision-making, or storage.
Prerequisites
You have activated Realtime Compute for Apache Flink. For more information, see Activate Realtime Compute for Apache Flink.
You have activated Message Queue for Apache Kafka. For more information, see Deploy a Message Queue for Apache Kafka instance.
You have activated ApsaraDB RDS for MySQL. For more information, see Create an ApsaraDB RDS for MySQL instance.
Realtime Compute for Apache Flink, ApsaraDB RDS for MySQL, and Message Queue for Apache Kafka must be in the same VPC. If they are in different VPCs, you must first establish a network connection between the VPCs or use public endpoints to access them. For more information, see How do I access other services across VPCs? and How do I access the Internet?.
If you access resources as a RAM user or by using a RAM role, you must have the required permissions.
Step 1: Prepare the environment
Create an RDS for MySQL instance and data source
Create an ApsaraDB RDS for MySQL database. For more information, see Create a database.
Create a database named
ecommercefor the target instance.Prepare the MySQL CDC data source.
On the instance details page, click Log On To Database at the top.
In the DMS page that appears, enter the username and password for the database account, and then click Log On.
After you log on, double-click the
ecommercedatabase in the left-side pane to switch to it.In the SQL Console, enter the following DDL and INSERT statements.
-- Create rule table 1 CREATE TABLE rds_demo1 ( `id` VARCHAR(64), `version` INT, `pattern` VARCHAR(4096), `function` VARCHAR(512) ); -- Create rule table 2 CREATE TABLE rds_demo2 ( `id` VARCHAR(64), `version` INT, `pattern` VARCHAR(4096), `function` VARCHAR(512) ); -- Create rule table 3 CREATE TABLE rds_demo3 ( `id` VARCHAR(64), `version` INT, `pattern` VARCHAR(4096), `function` VARCHAR(512) ); -- Create rule table 4 CREATE TABLE rds_demo4 ( `id` VARCHAR(64), `version` INT, `pattern` VARCHAR(4096), `function` VARCHAR(512) ); -- Create rule table 5 CREATE TABLE rds_demo5 ( `id` VARCHAR(64), `version` INT, `pattern` VARCHAR(4096), `function` VARCHAR(512) ); -- Create source tables CREATE TABLE `click_stream1` ( id bigint not null primary key auto_increment, -- Auto-incrementing primary key eventTime timestamp, eventType varchar(50), productId varchar(50), categoryId varchar(50), categoryCode varchar(80), brand varchar(50), price decimal(10, 2), userId varchar(50), userSession varchar(50) ); CREATE TABLE `click_stream2` ( id bigint not null primary key auto_increment, -- Auto-incrementing primary key eventTime timestamp, eventType varchar(50), productId varchar(50), categoryId varchar(50), categoryCode varchar(80), brand varchar(50), price decimal(10, 2), userId varchar(50), userSession varchar(50) ); CREATE TABLE `click_stream3` ( id bigint not null primary key auto_increment, -- Auto-incrementing primary key eventTime timestamp, eventType varchar(50), productId varchar(50), categoryId varchar(50), categoryCode varchar(80), brand varchar(50), price decimal(10, 2), userId varchar(50), userSession varchar(50) ); CREATE TABLE `click_stream4` ( id bigint not null primary key auto_increment, -- Auto-incrementing primary key eventTime timestamp, eventType varchar(50), productId varchar(50), categoryId varchar(50), categoryCode varchar(80), brand varchar(50), price decimal(10, 2), userId varchar(50), userSession varchar(50) ); CREATE TABLE `click_stream5` ( id bigint not null primary key auto_increment, -- Auto-incrementing primary key eventTime timestamp, eventType varchar(50), productId varchar(50), categoryId varchar(50), categoryCode varchar(80), brand varchar(50), price decimal(10, 2), userId varchar(50), userSession varchar(50) );Click Execute and then click Execute Directly.
Create Kafka topics and a consumer group
Create the following Kafka resources by following the instructions in Create resources:
Group: clickstream.consumer.
Topics: click_stream1, click_stream2, click_stream3, click_stream4, and click_stream5.
When you create the topics, we recommend that you set the number of partitions to 1. Otherwise, the sample data may not match the expected results in some scenarios.

Step 2: Synchronize data from MySQL to Kafka
Synchronizing user clickstream events from MySQL to Kafka reduces the load from multiple jobs on the database.
Create a MySQL catalog. For more information, see Create a MySQL catalog.
In this example, the catalog is named
mysql-catalog, and the default database isecommerce.Create a Kafka catalog. For more information, see Manage Kafka JSON catalogs.
In this example, the catalog is named
kafka-catalog.On the page, create a new SQL stream job and copy the following code into the SQL editor.
CREATE TEMPORARY TABLE `clickstream1` ( `key_id` BIGINT, `value_eventTime` BIGINT, `value_eventType` STRING, `value_productId` STRING, `value_categoryId` STRING, `value_categoryCode` STRING, `value_brand` STRING, `value_price` DECIMAL(10, 2), `value_userId` STRING, `value_userSession` STRING, -- Define the primary key. PRIMARY KEY (`key_id`) NOT ENFORCED, ts AS TO_TIMESTAMP_LTZ(value_eventTime, 3), WATERMARK FOR ts AS ts - INTERVAL '2' SECOND -- Define a watermark. ) WITH ( 'connector'='upsert-kafka', 'topic' = 'click_stream1', 'properties.bootstrap.servers' = 'alikafka-pre-cn-w******02-1-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-2-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-3-vpc.alikafka.aliyuncs.com:9092', 'key.format' = 'json', 'value.format' = 'json', 'key.fields-prefix' = 'key_', 'value.fields-prefix' = 'value_', 'value.fields-include' = 'EXCEPT_KEY' ); CREATE TEMPORARY TABLE `clickstream2` ( `key_id` BIGINT, `value_eventTime` BIGINT, `value_eventType` STRING, `value_productId` STRING, `value_categoryId` STRING, `value_categoryCode` STRING, `value_brand` STRING, `value_price` DECIMAL(10, 2), `value_userId` STRING, `value_userSession` STRING, -- Define the primary key. PRIMARY KEY (`key_id`) NOT ENFORCED, ts AS TO_TIMESTAMP_LTZ(value_eventTime, 3), WATERMARK FOR ts AS ts - INTERVAL '2' SECOND -- Define a watermark. ) WITH ( 'connector'='upsert-kafka', 'topic' = 'click_stream2', 'properties.bootstrap.servers' = 'alikafka-pre-cn-w******02-1-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-2-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-3-vpc.alikafka.aliyuncs.com:9092', 'key.format' = 'json', 'value.format' = 'json', 'key.fields-prefix' = 'key_', 'value.fields-prefix' = 'value_', 'value.fields-include' = 'EXCEPT_KEY' ); CREATE TEMPORARY TABLE `clickstream3` ( `key_id` BIGINT, `value_eventTime` BIGINT, `value_eventType` STRING, `value_productId` STRING, `value_categoryId` STRING, `value_categoryCode` STRING, `value_brand` STRING, `value_price` DECIMAL(10, 2), `value_userId` STRING, `value_userSession` STRING, -- Define the primary key. PRIMARY KEY (`key_id`) NOT ENFORCED, ts AS TO_TIMESTAMP_LTZ(value_eventTime, 3), WATERMARK FOR ts AS ts - INTERVAL '2' SECOND -- Define a watermark. ) WITH ( 'connector'='upsert-kafka', 'topic' = 'click_stream3', 'properties.bootstrap.servers' = 'alikafka-pre-cn-w******02-1-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-2-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-3-vpc.alikafka.aliyuncs.com:9092', 'key.format' = 'json', 'value.format' = 'json', 'key.fields-prefix' = 'key_', 'value.fields-prefix' = 'value_', 'value.fields-include' = 'EXCEPT_KEY' ); CREATE TEMPORARY TABLE `clickstream4` ( `key_id` BIGINT, `value_eventTime` BIGINT, `value_eventType` STRING, `value_productId` STRING, `value_categoryId` STRING, `value_categoryCode` STRING, `value_brand` STRING, `value_price` DECIMAL(10, 2), `value_userId` STRING, `value_userSession` STRING, -- Define the primary key. PRIMARY KEY (`key_id`) NOT ENFORCED, ts AS TO_TIMESTAMP_LTZ(value_eventTime, 3), WATERMARK FOR ts AS ts - INTERVAL '2' SECOND -- Define a watermark. ) WITH ( 'connector'='upsert-kafka', 'topic' = 'click_stream4', 'properties.bootstrap.servers' = 'alikafka-pre-cn-w******02-1-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-2-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-3-vpc.alikafka.aliyuncs.com:9092', 'key.format' = 'json', 'value.format' = 'json', 'key.fields-prefix' = 'key_', 'value.fields-prefix' = 'value_', 'value.fields-include' = 'EXCEPT_KEY' ); CREATE TEMPORARY TABLE `clickstream5` ( `key_id` BIGINT, `value_eventTime` BIGINT, `value_eventType` STRING, `value_productId` STRING, `value_categoryId` STRING, `value_categoryCode` STRING, `value_brand` STRING, `value_price` DECIMAL(10, 2), `value_userId` STRING, `value_userSession` STRING, -- Define the primary key. PRIMARY KEY (`key_id`) NOT ENFORCED, ts AS TO_TIMESTAMP_LTZ(value_eventTime, 3), WATERMARK FOR ts AS ts - INTERVAL '2' SECOND -- Define a watermark. ) WITH ( 'connector'='upsert-kafka', 'topic' = 'click_stream5', 'properties.bootstrap.servers' = 'alikafka-pre-cn-w******02-1-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-2-vpc.alikafka.aliyuncs.com:9092,alikafka-pre-cn-w******02-3-vpc.alikafka.aliyuncs.com:9092', 'key.format' = 'json', 'value.format' = 'json', 'key.fields-prefix' = 'key_', 'value.fields-prefix' = 'value_', 'value.fields-include' = 'EXCEPT_KEY' ); BEGIN STATEMENT SET; INSERT INTO `clickstream1` SELECT id, UNIX_TIMESTAMP(eventTime) * 1000 as eventTime, eventType, productId, categoryId, categoryCode, brand, price, `userId`, userSession FROM `mysql-catalog`.`ecommerce`.`click_stream1`; INSERT INTO `clickstream2` SELECT id, UNIX_TIMESTAMP(eventTime) * 1000 as eventTime, eventType, productId, categoryId, categoryCode, brand, price, `userId`, userSession FROM `mysql-catalog`.`ecommerce`.`click_stream2`; INSERT INTO `clickstream3` SELECT id, UNIX_TIMESTAMP(eventTime) * 1000 as eventTime, eventType, productId, categoryId, categoryCode, brand, price, `userId`, userSession FROM `mysql-catalog`.`ecommerce`.`click_stream3`; INSERT INTO `clickstream4` SELECT id, UNIX_TIMESTAMP(eventTime) * 1000 as eventTime, eventType, productId, categoryId, categoryCode, brand, price, `userId`, userSession FROM `mysql-catalog`.`ecommerce`.`click_stream4`; INSERT INTO `clickstream5` SELECT id, UNIX_TIMESTAMP(eventTime) * 1000 as eventTime, eventType, productId, categoryId, categoryCode, brand, price, `userId`, userSession FROM `mysql-catalog`.`ecommerce`.`click_stream5`; END; -- Required when you write data to multiple sinks.In the upper-right corner, click Deploy to deploy the job.
In the left-side navigation pane, click . In the Actions column for the target job, click Start. Then, select Stateless Start and click Start.
Step 3: Develop, deploy, and start the CEP job
This topic describes how to deploy the cep-demo-1.0-SNAPSHOT-jar-with-dependencies.jar job, which consumes user clickstream events from Kafka, processes them, and prints alert information to the Realtime Compute for Apache Flink development console. You can adjust the code to suit your business architecture and select an appropriate downstream connector for different data output scenarios. For more information about supported connectors, see Supported connectors.
1. Code development
This section provides only the core code and a description of its functionality.
2. Job deployment
On the page, click to deploy five separate stream jobs.

Parameter description:
Parameter | Description | Example |
Deployment mode | Stream processing | Streaming mode |
Deployment name | The name of the JAR job. |
|
Engine version | The Flink engine version used by the current job. The SDK for the code in this topic uses JDK 11. You must select a version that contains | vvr-8.0.11-jdk11-flink-1.17 |
JAR URI | Click the upload icon | oss://xxx/artifacts/namespaces/xxx/cep-demo-1.0-SNAPSHOT-jar-with-dependencies.jar |
Entry point class | The entry point class of the program. | com.alibaba.ververica.cep.demo.CepDemo |
Entry point main arguments | You can pass parameters here and call them in the main method. For this example, you need to configure the following parameters:
|
|
For more information about deployment, see Deploy a JAR job.
3. Job startup
On the Job O&M page, click Start in the Actions column for the target job. Select Stateless Start and then click Start. Sequentially start the jobs for all five scenarios: EcommerceCEPRunner1, EcommerceCEPRunner2, EcommerceCEPRunner3, EcommerceCEPRunner4, and EcommerceCEPRunner5.
For more information about start configurations, see Start a job.
on the right to upload the 








