# Tumbling Window Product TopN Ranking (FlinkSQL)

## Prompt
I need you to write a Flink SQL that uses the built-in datagen connector to simulate an order data source, aggregates product sales over a 10-minute tumbling window, and then uses the `ROW_NUMBER` window function to retrieve the top 5 products by sales within each window, outputting the results to the console.

**Business Background and Objective**: Simulate an order stream using a datagen built-in table, generating massive order data. Group by a 10-minute tumbling window to compute the total sales amount and order count per product within each window, and finally use `ROW_NUMBER` ranking to retrieve the top 5 products by sales amount within each window.

**Source Table Definition**:
- `order_source` (order stream, datagen connector):
  - `order_id BIGINT`: Order ID, randomly generated in the range 1–10,000,000
  - `product_id INT`: Product ID, randomly generated in the range 1–200
  - `amount DOUBLE`: Order amount, randomly generated in the range 0–500
  - `event_time`: Uses `LOCALTIMESTAMP` to generate event time, with a WATERMARK delay of 5 seconds
  - Generation rate: `rows-per-second = 8000`

**Output Table Definition**:
- `console_output` (print connector):
  - `window_start TIMESTAMP(3)`: Tumbling window start time
  - `product_id INT`: Product ID
  - `sales DOUBLE`: Total sales amount of the product within the window
  - `order_cnt BIGINT`: Number of orders for the product within the window
  - `rn BIGINT`: Sales ranking within the window

**SQL Logic**:
- Apply `TUMBLE(event_time, INTERVAL '10' MINUTE)` tumbling window on `order_source`
- Group by `window_start`, `window_end`, `product_id`
- Aggregate `SUM(amount) AS sales` and `COUNT(*) AS order_cnt`
- Use `ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY sales DESC) AS rn`
- Outer query filter: `WHERE rn <= 5`
- Final SELECT: `window_start`, `product_id`, `sales`, `order_cnt`, `rn`

**Output Requirements**:
- Use `INSERT INTO console_output` to output the results.
- Output field order: `window_start`, `product_id`, `sales`, `order_cnt`, `rn`

## Reference Solution
-- flinksql_011: 滚动窗口商品 TopN 排行
-- 10-min TUMBLE + SUM(amount) + COUNT(*) + ROW_NUMBER Top-5

-- 1. 订单源 datagen 表
CREATE TABLE order_source (
    order_id BIGINT,
    product_id INT,
    amount DOUBLE,
    event_time AS LOCALTIMESTAMP,
    WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
    'connector' = 'datagen',
    'rows-per-second' = '8000',
    'fields.order_id.kind' = 'random',
    'fields.order_id.min' = '1',
    'fields.order_id.max' = '10000000',
    'fields.product_id.kind' = 'random',
    'fields.product_id.min' = '1',
    'fields.product_id.max' = '200',
    'fields.amount.kind' = 'random',
    'fields.amount.min' = '0',
    'fields.amount.max' = '500'
);

-- 2. Console 输出表
CREATE TABLE console_output (
    window_start TIMESTAMP(3),
    product_id INT,
    sales DOUBLE,
    order_cnt BIGINT,
    rn BIGINT
) WITH (
    'connector' = 'print'
);

-- 3. TUMBLE 窗口聚合 + ROW_NUMBER Top-5
INSERT INTO console_output
SELECT
    window_start,
    product_id,
    sales,
    order_cnt,
    rn
FROM (
    SELECT
        window_start,
        window_end,
        product_id,
        sales,
        order_cnt,
        ROW_NUMBER() OVER (
            PARTITION BY window_start, window_end
            ORDER BY sales DESC
        ) AS rn
    FROM (
        SELECT
            TUMBLE_START(event_time, INTERVAL '10' MINUTE) AS window_start,
            TUMBLE_END(event_time, INTERVAL '10' MINUTE) AS window_end,
            product_id,
            SUM(amount) AS sales,
            COUNT(*) AS order_cnt
        FROM order_source
        GROUP BY
            TUMBLE(event_time, INTERVAL '10' MINUTE),
            product_id
    )
)
WHERE rn <= 5;