water8394/flink-recommandSystem-demo
water8394/flink-recommandSystem-demo has 4,477 GitHub stars and 1,476 forks. GitHot measured 0 stars in 24 hours and +2 in 7 days. Last checked 2026-11-09 13:33 UTC. Last push 2026-10-26.
:helicopter::rocket:基于Flink实现的商品实时推荐系统。flink统计商品热度,放入redis缓存,分析日志信息,将画像标签和实时记录放入Hbase。在用户发起推荐请求后,根据用户画像重排序热度榜,并结合协同过滤和标签两个推荐模块为新生成的榜单的每一个产品添加关联产品,最后返回新的用户列表。
Measured star growth
- in 24h
- 0
- in 7 days
- +2
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
README_EN.md
OriginalReal-time product recommendation demo
中文 · Contributing · Apache-2.0
Flink demo that turns product behavior logs into live recommendations. Kafka carries the logs. Flink jobs build user and product portraits, a hot list, and history for item-based collaborative filtering. Portraits and scores land in HBase. The hot list is cached in Redis. A Spring Boot site re-ranks that list for the caller and attaches related products.
Copyright 2019-2026 water8394 (XInZE). Licensed under the Apache License 2.0.
Modules
| Module | Role |
|---|---|
flink-2-hbase |
Six Flink jobs: browse history, interest, user portrait, product portrait, hot ranking, and raw log import. Offline helpers score product relatedness. |
web |
Storefront recommendations and an admin screen. MySQL holds the product catalog. |
The hot-rank job windows events by product, keeps a top list, and writes SET <rank> <productId> into Redis. Related-product scores use the portrait formula in Similarity.productPortraitScore and the item-CF formula in Similarity.itemCfScore.
Requirements
| Tool | Version |
|---|---|
| JDK | 11 or 17 to run jobs and the web app. A newer JDK can compile (maven.compiler.release is 11). Do not run the Flink 1.18 jobs on JDK 21. CI uses Temurin 17. |
| Maven | 3.8+ |
| Docker | Docker Engine and Compose v2 (docker compose, not the docker-compose binary). Only required for the bundled stack. |
| Memory | Leave at least 6 GB for the containers and the jobs. |
| Ports | 9092 Kafka, 2181 / 16000 / 16010 / 16020 / 16030 HBase, 6379 Redis, 3308 MySQL, 8081 Flink UI, 8082 web. |
Flink stays on 1.18, the newest 1.x line that still accepts the demo's DataStream calls (keyBy(String), timeWindow, TimeCharacteristic). Flink 1.19+ and Flink 2.0 remove those APIs.
You can point flink-2-hbase/src/main/resources/config.properties and web/src/main/resources/application.yml at Kafka, HBase, Redis, and MySQL you already run. The steps below use the compose file in this repo.
Quick start
The old README sent people to an external "article" (xinze.fun) for deployment. That URL now redirects to an unrelated site, so it is gone. The Jianshu and CSDN notes described a different, manual image setup and are not linked here either. This section is the deployment guide.
Chinese: README.md.
1. Start dependencies (one command)
From the repository root:
./scripts/bootstrap.sh
That runs docker compose -f resources/docker/docker-compose/docker-compose.yml up -d --build and waits until:
| Service | Address from the host | What the first boot does |
|---|---|---|
| Kafka 3.9.2 (KRaft) | localhost:9092 |
kafka-init creates topic con (1 partition). Inside the compose network the broker is kafka:19092. |
| HBase 2.6.7 | ZooKeeper port 2181, UI http://localhost:16010 |
Standalone, ZooKeeper embedded. hbase_ini.sql creates con, prod, user, u_history, p_history, ps, px, u_interest. The client quorum is 127.0.0.1. localhost often also resolves to ::1, the IPv6 connection is reset, and the client never comes up. ZooKeeper inside the container listens on 0.0.0.0 so the published port is reachable. |
| Redis 7.4 | localhost:6379 |
|
| MySQL 8.0 | localhost:3308 |
Database con, user root, password 123456. contact.sql loads contact, product, and user. The host port is 3308; inside the container MySQL still listens on 3306. |
| Flink 1.18.1 | UI http://localhost:8081 | JobManager and one TaskManager. |
There are no data volumes. docker compose down deletes the data; the next up initializes again. restart keeps it.
Kafka, Redis, and MySQL in the config files are localhost on the host. The HBase ZooKeeper address is 127.0.0.1 (see the table). Do not flink run the jobs into the compose TaskManager. Inside that container localhost is the container itself, so the job cannot see Kafka, HBase, Redis, or MySQL. The script in the next section runs the jobs on the host network instead. The Flink UI is still useful to see that the cluster process is up.
2. Build
mvn -B package
The reactor builds flink-2-hbase, then web. Unit tests for age buckets, log parsing, and the two scoring formulas run with the build. Older tests that open MySQL, Redis, or HBase are excluded. See CONTRIBUTING.md.
3. Start the six Flink jobs
Start the jobs before you produce logs. Consumers begin at the latest offset, so earlier messages are skipped.
./scripts/run-flink-jobs.sh
On Linux the script starts one flink:1.18.1 container with --network host (Java 11) and launches all six mains. On other systems, with JDK 11 or 17 installed, it uses java -cp on the host. Logs:
docker logs -f flink-demo-jobs
| Class | Role | Output |
|---|---|---|
com.demo.task.LogTask |
Raw logs | HBase con |
com.demo.task.UserHistoryTask |
User-product and product-user history | HBase u_history, p_history |
com.demo.task.UserInterestTask |
Interest | HBase u_interest |
com.demo.task.UserPortraitTask |
User portrait (reads MySQL product) |
HBase user |
com.demo.task.ProductProtaritTask |
Product portrait (reads MySQL user) |
HBase prod |
com.demo.task.TopProductTask |
60s sliding hot list, 5s slide | Redis keys 0..4 |
A log line is userId,productId,epochSeconds,action. action is 1 browse, 2 favorite, 3 purchase.
The hot list uses event time. A window is 60 seconds, so a handful of messages all stamped "now" will not fill a window. The default generator spreads timestamps across the last 100 seconds.
Related-product scores (px, ps) come from com.demo.scheduler.SchedulerJob, a local timer, not a Flink job. It reads p_history. Until it runs, the second and third columns on the page still list the hot products, without extra neighbors. Optional:
java -cp flink-2-hbase/target/flink-2-hbase-1.0-SNAPSHOT.jar com.demo.scheduler.SchedulerJob
Stop the streaming jobs with ./scripts/stop-flink-jobs.sh.
4. Generate logs
Wait until the job logs show the tasks starting (about half a minute), then:
./scripts/generate-logs.sh
That sends 200 messages. Product ids are concentrated on 11–15, which exist in both MySQL tables, and id 11 is the most frequent, so Redis key 0 should become 11. Continuous random logs:
./scripts/generate-logs.sh --follow
resources/docker/docker-compose/generator.sh is mounted into the Kafka container at /opt/generator.sh (MODE=follow loops, MODE=once sends one burst).
The browse / favorite / buy buttons call GET /log?id=&prod=&action=, and the web app publishes that line to topic con.
5. Fill the hot-list keys and open the site
TopProductTask writes Redis keys 0 through 4. The page reads 0 through 9. With fewer than 10 keys the page pads from the product table and then indexes into contact with that longer list. Product ids 1 and 2 have no contact row, and the page returns 500. The page also matches each id by position in the contact and product query results, and those queries return one row per id. A repeated id makes those lists shorter than Redis and throws IndexOutOfBoundsException. The script fills empty keys and replaces an id that already appears in an earlier rank (starting at 20, which exists in both tables). Ranks the hot-list job already wrote stay as they are:
./scripts/seed-hotlist.sh
./scripts/run-web.sh
run-web.sh prefers JDK 17 when JAVA_HOME is unset and that JDK is installed. Do not run mvn spring-boot:run from the repository root. The aggregator POM is not a Spring Boot project, so the plugin is missing, and invoking it with -am also targets flink-2-hbase, which has many main methods. The script installs the Flink module, then runs Spring Boot only on web.
Open:
- Recommendations: http://localhost:8082/recommand?userId=1
- Admin hot list: http://localhost:8082/index
The page has three columns (hot list, item-CF, product portrait) and product names. Picture URLs are old external links; a broken image does not mean the list failed.
./scripts/verify-demo.sh http://localhost:8082
After the hot-list job finishes, GET 0 in Redis should be 11, and HBase con should contain log rows.
Troubleshooting
- The old article redirects somewhere unrelated. Ignore it. Start at
./scripts/bootstrap.sh. docker compose upreturns, and the site has no data.up -ddoes not wait for the MySQL import or the HBase shell. Use the bootstrap script, or checkdocker pshealth anddocker logs mysql,docker logs hbase,docker logs kafka-init.- Port already allocated. MySQL is published on 3308, not 3306. Stop the other process using the port in the table above.
- HBase client times out, port
2181resets, or it dialslocalhost:9000. RPC and scanner timeouts inconfig.propertiesare 60s, the quorum is127.0.0.1, andhbase.rootdiris no longer aimed at a NameNode this stack does not run.echo ruok | nc -4 127.0.0.1 2181should printimok. The RegionServer advertiseslocalhost, so clients must run on the host (or with--network hoston Linux), not on the compose bridge network. - A job submitted in the Flink UI never prints anything.
localhost:9092inside the TaskManager is not the host's Kafka. Use./scripts/run-flink-jobs.sh. - Jobs exit immediately on JDK 21. Run them on JDK 11 or 17. Compiling with 21 is fine.
- Logs were sent, but Redis has no key
0. The jobs must be running before the producer. Timestamps must cover about 60 seconds of event time. Readdocker logs flink-demo-jobsfor Kafka or HBase errors. /recommandreturns 500 (IndexOutOfBoundsException, or a nullcontact). Run./scripts/seed-hotlist.sh. All 10 keys must be set, the ids must be unique, and each id must exist in bothproductandcontact(sample ids start at 3; the filler starts at 20)./recommandreturns 500 because Thymeleaf rejects string concatenation inth:onclick. Boot 2.7's Thymeleaf does not allow that in an event attribute. The buttons now usedata-*attributes and still call the samesendLog. Do not putth:onclick="'javascript:sendLog('+${userId}+..."back.- Names show, pictures do not. The image hosts are external and many of those URLs are dead.
- Edits to
contact.sqlor the HBase script did nothing. Init runs only on an empty data directory.docker compose -f resources/docker/docker-compose/docker-compose.yml down, then./scripts/bootstrap.sh. - A firewall or security group blocks the ports. Compose publishes the ports on
0.0.0.0. Open the ones you actually use. kafka-initnever exits, its logs stay empty, and the Flink UI shows no TaskManager. Containers cannot reach each other. Published host ports still answer, so this looks like a Kafka or Flink failure. On Linux check bothiptablesandiptables-legacyFORWARD. ADROPpolicy that only acceptsdocker0drops the compose bridge. Allow that bridge, thendocker restart kafka-init, and confirmdocker logs flink-taskmanagershows the worker registered.mvn spring-boot:runfails. The root POM has no such plugin. With full coordinates and-am, the plugin also runs onflink-2-hbaseand reports that it cannot pick a single main class. Use./scripts/run-web.sh.
What is intentionally unchanged
Recommendation rules, table layouts, and the web flows are the same. Dependency and connector upgrades are listed in the pull request that introduced this file. Spring Boot stays on 2.7 because Boot 3 switches the application to Jakarta EE. Scoring formulas still live in Similarity.productPortraitScore and Similarity.itemCfScore. The hot-rank sink still writes SET <rank> <productId> in Redis.
Explore related projects
codecrafters-io/build-your-own-x
Master programming by recreating your favorite technologies from scratch.
561,279 starspublic-apis/public-apis
A collective list of free APIs
497,539 starsmorluto/rea
Reverse engineer anything with agents, from app behavior down to native binaries.
446,086 starsopenclaw/openclaw
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
394,235 stars