Flink Connector

Updated at:
Copy as MD

StarRocks provides an Apache Flink connector, hereafter referred to as the Flink Connector, to import data from Flink into StarRocks tables. The StarRocks Flink Connector delivers better performance and stability than Flink's built-in flink-connector-jdbc, which makes it ideal for large-scale data import scenarios.

Background information

The StarRocks Flink Connector caches mini-batches of data in memory and uses StarRocks' Stream Load feature for batch imports. It supports the DataStream API, Table API & SQL, and Python API, which significantly improves data import efficiency.

Prerequisites

  • You have created a cluster with the Flink service enabled.

    This topic uses a DataFlow cluster with the Flink service created on EMR on ECS, hereafter referred to as a Flink cluster, as an example. For more information, see Create a cluster.

  • You have created an EMR Serverless StarRocks instance. For more information, see Create an instance.

Limits

  • Ensure that the machine running Flink can access the http_port (default 8030) and query_port (default 9030) of the FE nodes, and the be_http_port (default 8040) of the BE nodes in the StarRocks instance.

  • To use the Flink Connector to import data into StarRocks, you need `SELECT` and `INSERT` permissions on the target table.

  • The Flink Connector has the following compatibility requirements with Java, Scala, and Flink versions.

    Connector

    Flink

    StarRocks

    Java

    Scala

    1.2.9

    1.15–1.18

    2.1 and later

    8

    2.11, 2.12

    1.2.8

    1.13–1.17

    2.1 and later

    8

    2.11, 2.12

    1.2.7

    1.11–1.15

    2.1 and later

    8

    2.11, 2.12

Configuration

This section describes StarRocks parameter settings and data type mapping. For more information, see Continuously load data from Apache Flink® | StarRocks.

Parameter description

Parameter

Required

Default value

Description

connector

Yes

NONE

Specifies the connector as StarRocks. Set this parameter to starrocks.

jdbc-url

Yes

NONE

Used to execute queries in StarRocks.

Example: jdbc:mysql://fe-c-9b354c83e891**-internal.starrocks.aliyuncs.com:9030. Here, fe-c-9b354c83e891**-internal.starrocks.aliyuncs.com is the private network address of the FE node in your EMR Serverless StarRocks instance.

Note

For information about how to obtain the private network address of the FE node in your EMR Serverless StarRocks instance, see View instance list and details.

load-url

Yes

NONE

Specifies the private network address and HTTP port of the FE node in the format private network address of the FE node in your EMR Serverless StarRocks instance:8030.

Example: fe-c-9b354c83e891****-internal.starrocks.aliyuncs.com:8030.

database-name

Yes

NONE

Name of the StarRocks database.

table-name

Yes

NONE

Name of the StarRocks table.

username

Yes

NONE

Username for your StarRocks instance. For example, the default username is admin.

To use the Flink Connector to import data into StarRocks, you need SELECT and INSERT permissions on the target table. If your user account lacks these permissions, grant them first. For more information, see Manage users and data authorization.

password

Yes

NONE

Password for your StarRocks instance.

sink.semantic

No

at-least-once

Defines the semantic guarantee level of the sink to ensure reliability and consistency when writing data to the target system. Valid values:

  • at-least-once: Ensures data is written at least once. Duplicate data may occur.

  • exactly-once: Ensures data is written exactly once with no duplicates or loss.

sink.version

No

AUTO

Specifies the data import interface. This parameter is supported starting from Flink Connector 1.2.4.

  • V1: Uses the Stream Load interface to import data. Flink Connector versions earlier than 1.2.4 support only this mode.

  • V2: Uses the Stream Load transactional interface to import data. Requires StarRocks 2.4 or later. We recommend V2 because it reduces memory usage and provides a more stable exactly-once implementation.

  • AUTO: Automatically selects V2 if your StarRocks version supports the Stream Load transactional interface. Otherwise, selects V1.

sink.label-prefix

No

NONE

Specifies the prefix for Stream Load labels. If you use Flink Connector 1.2.8 or later and require exactly-once semantics, we recommend configuring a label prefix.

sink.buffer-flush.max-bytes

No

94371840 (90 MB)

Maximum size of data buffered in memory before it is imported into StarRocks via Stream Load in one batch. A larger value improves import performance but may increase import latency.

Valid range: [64 MB, 10 GB].

Note
  • This parameter takes effect only when sink.semantic is set to at-least-once.

  • When sink.semantic is set to exactly-once, data in memory is flushed only when a Flink checkpoint is triggered. In this case, the sink.buffer-flush.max-bytes parameter has no effect because data is not automatically flushed based on size thresholds.

sink.buffer-flush.max-rows

No

500000

Maximum number of rows buffered in memory before they are imported into StarRocks via Stream Load in one batch.

Valid range: [64000, 5000000].

Note

This parameter takes effect only when sink.version is set to V1 and sink.semantic is set to at-least-once.

sink.buffer-flush.interval-ms

No

300000

Interval (in milliseconds) for sending data, which controls the latency of writing data to StarRocks.

Valid range: [1000, 3600000].

Note

This parameter takes effect only when sink.semantic is set to at-least-once.

sink.max-retries

No

3

Maximum number of retries after a Stream Load failure. If this limit is exceeded, the data import task fails.

Valid range: [0, 10].

Note

This parameter takes effect only when sink.version is set to V1.

sink.connect.timeout-ms

No

30000

Timeout (in milliseconds) for establishing an HTTP connection with the FE node.

Valid range: [100, 60000].

In Flink Connector versions earlier than 1.2.9, the default value is 1000.

sink.socket.timeout-ms

No

-1

Supported starting from Flink Connector 1.2.10. Timeout (in milliseconds) for the HTTP client to wait for data. The default value -1 means no timeout.

sink.wait-for-continue.timeout-ms

No

10000

Supported starting from Flink Connector 1.2.7. Timeout (in milliseconds) for waiting for the FE HTTP 100-continue response.

Valid range: [3000, 60000].

sink.ignore.update-before

No

TRUE

Supported starting from Flink Connector 1.2.8. When importing data into a primary key table, specifies whether to ignore UPDATE_BEFORE records from Flink. If set to false, such records are treated as DELETE operations in the primary key table.

sink.parallelism

No

NONE

Parallelism for writes. Applies only to Flink SQL. If not set, the Flink planner determines the parallelism. In multi-parallelism scenarios, ensure data is written in the correct order.

sink.properties.*

No

NONE

Parameters for Stream Load that control import behavior.

sink.properties.format

No

csv

Data format for Stream Load imports. The Flink Connector converts in-memory data to the specified format before importing it into StarRocks via Stream Load. Valid values: CSV or JSON.

sink.properties.column_separator

No

\t

Column delimiter for CSV data.

sink.properties.row_delimiter

No

\n

Row delimiter for CSV data.

sink.properties.max_filter_ratio

No

0

Maximum error tolerance ratio for the import job. This is the maximum proportion of data rows that can be filtered out due to poor data quality.

Valid range: 0–1.

sink.properties.partial_update

No

false

Specifies whether to enable partial updates. Valid values: TRUE and FALSE (default).

sink.properties.partial_update_mode

No

row

Specifies the partial update mode. Valid values:

  • row (default): Uses row-based partial updates. Suitable for real-time update scenarios with many columns and small batches.

  • column: Uses column-based partial updates. Suitable for batch update scenarios with few columns and large numbers of rows. Enabling column mode significantly improves update performance in such scenarios.

sink.properties.strict_mode

No

false

Specifies whether to enable strict mode for Stream Load. Strict mode affects import behavior when invalid rows (such as those with inconsistent column values) are encountered.

Valid values: true and false.

sink.properties.compression

No

NONE

Supported starting from Flink Connector 1.2.10. Specifies the compression algorithm for Stream Load. Currently, only JSON format supports compression.

Valid value: lz4_frame.

Note

Only StarRocks 3.2.7 and later support JSON compression.

Data type mapping

Flink data type

StarRocks data type

BOOLEAN

BOOLEAN

TINYINT

TINYINT

SMALLINT

SMALLINT

INTEGER

INTEGER

BIGINT

BIGINT

FLOAT

FLOAT

DOUBLE

DOUBLE

DECIMAL

DECIMAL

BINARY

INT

CHAR

STRING

VARCHAR

STRING

STRING

STRING

DATE

DATE

TIMESTAMP_WITHOUT_TIME_ZONE(N)

DATETIME

TIMESTAMP_WITH_LOCAL_TIME_ZONE(N)

DATETIME

ARRAY<T>

ARRAY<T>

MAP<KT,VT>

JSON STRING

ROW<arg T...>

JSON STRING

Preparations

Obtain the Flink Connector JAR and upload it to your Flink cluster

  1. You can obtain the Flink Connector JAR file using one of the following methods.

    Method 1: Direct download

    You can download different versions of the Flink Connector JAR file from the Maven Central Repository.

    Method 2: Maven dependency

    Add the Flink Connector as a dependency to the pom.xml file of your Maven project in the following format.

    • For Flink Connectors compatible with Flink 1.15 and later:

      <dependency>
          <groupId>com.starrocks</groupId>
          <artifactId>flink-connector-starrocks</artifactId>
          <version>${connector_version}_flink-${flink_version}</version>
      </dependency>
    • For Flink Connectors compatible with Flink versions earlier than 1.15:

      <dependency>
          <groupId>com.starrocks</groupId>
          <artifactId>flink-connector-starrocks</artifactId>
          <version>${connector_version}_flink-${flink_version}_${scala_version}</version>
      </dependency>

    Method 3: Manual compilation

    1. Download the Flink Connector source code.

    2. Run the following command to compile the Flink Connector source code into a JAR file.

      sh build.sh <flink_version>

      For example, if your Flink version is 1.17, run the following command.

      sh build.sh 1.17
    3. After compilation, you can find the generated JAR file in the target/ directory.

      For example, the filename is typically in the format flink-connector-starrocks-1.2.7_flink-1.17-SNAPSHOT.jar.

      Note

      Unreleased Flink Connector versions include the SNAPSHOT suffix.

    The Flink Connector JAR filename follows these formats:

    • For Flink 1.15 and later: flink-connector-starrocks-${connector_version}_flink-${flink_version}.jar. For example, if you use Flink 1.17 and Flink Connector 1.2.8, the filename is flink-connector-starrocks-1.2.8_flink-1.17.jar.

    • For Flink versions earlier than 1.15: flink-connector-starrocks-${connector_version}_flink-${flink_version}_${scala_version}.jar. For example, if you use Flink 1.14, Scala 2.12, and Flink Connector 1.2.7, the filename is flink-connector-starrocks-1.2.7_flink-1.14_2.12.jar.

      Note

      Replace the following placeholders as needed:

      • flink_version: Your Flink version number.

      • scala_version: Your Scala version number.

      • connector_version: Your Flink Connector version number.

  2. Upload the Flink Connector JAR file that you obtained to the flink-{flink_version}/lib directory of your Flink cluster.

    For example, if you use an EMR cluster of version EMR-5.19.0, place the JAR file in the /opt/apps/FLINK/flink-current/lib directory.

Start the Flink cluster

  1. Log on to the master node of your Flink cluster. For more information, see Log on to a cluster.

  2. Run the following command to start the Flink cluster.

    /opt/apps/FLINK/flink-current/bin/start-cluster.sh

Examples

Write data using Flink SQL

  1. Create a database named test in StarRocks, and then create a primary key table named score_board in the database.

    CREATE DATABASE test;
    CREATE TABLE test.score_board(
        id int(11) NOT NULL COMMENT "",
        name varchar(65533) NULL DEFAULT "" COMMENT "",
        score int(11) NOT NULL DEFAULT "0" COMMENT ""
    )
    ENGINE=OLAP
    PRIMARY KEY(id)
    DISTRIBUTED BY HASH(id);
  2. Log on to the master node of your Flink cluster. For more information, see Log on to a cluster.

  3. Run the following command to start Flink SQL.

    /opt/apps/FLINK/flink-current/bin/sql-client.sh
  4. Run the following command to create a table named score_board and insert data into it.

    CREATE TABLE `score_board` (
        `id` INT,
        `name` STRING,
        `score` INT,
        PRIMARY KEY (id) NOT ENFORCED
    ) WITH (
        'connector' = 'starrocks',
        'jdbc-url' = 'jdbc:mysql://<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:9030',
        'load-url' = '<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:8030',
        'database-name' = 'test',
        'table-name' = 'score_board',
        'username' = 'admin',
        'password' = '<password>',
    );
    INSERT INTO `score_board` VALUES (1, 'starrocks', 100), (2, 'flink', 100);

    If you are importing data into a StarRocks primary key table, you must explicitly specify the primary key in the Flink table DDL. For other types of StarRocks tables, such as Duplicate Key tables, specifying a primary key is optional.

Write data using Flink DataStream

Write a Flink DataStream job based on the type of input records.

  • Write CSV-formatted string data

    If your input records are CSV-formatted strings, see the complete Flink DataStream job code in LoadCsvRecords.

    /**
     * Generate CSV-format records. Each record has three values separated by "\t". 
     * These values will be loaded to the columns `id`, `name`, and `score` in the StarRocks table.
     */
    String[] records = new String[]{
            "1\tstarrocks-csv\t100",
            "2\tflink-csv\t100"
    };
    DataStream<String> source = env.fromElements(records);
    /**
     * Configure the Flink connector with the required properties.
     * You also need to add properties "sink.properties.format" and "sink.properties.column_separator"
     * to tell the Flink connector the input records are CSV-format, and the column separator is "\t".
     * You can also use other column separators in the CSV-format records,
     * but remember to modify the "sink.properties.column_separator" correspondingly.
     */
    StarRocksSinkOptions options = StarRocksSinkOptions.builder()
            .withProperty("jdbc-url", jdbcUrl)
            .withProperty("load-url", loadUrl)
            .withProperty("database-name", "test")
            .withProperty("table-name", "score_board")
            .withProperty("username", "root")
            .withProperty("password", "")
            .withProperty("sink.properties.format", "csv")
            .withProperty("sink.properties.column_separator", "\t")
            .build();
    // Create the sink with the options.
    SinkFunction<String> starRockSink = StarRocksSink.sink(options);
    source.addSink(starRockSink);
  • Write JSON-formatted string data

    If your input records are JSON-formatted strings, see the complete Flink DataStream job code in LoadJsonRecords.

    /**
     * Generate JSON-format records. 
     * Each record has three key-value pairs corresponding to the columns id, name, and score in the StarRocks table.
     */
    String[] records = new String[]{
            "{\"id\":1, \"name\":\"starrocks-json\", \"score\":100}",
            "{\"id\":2, \"name\":\"flink-json\", \"score\":100}",
    };
    DataStream<String> source = env.fromElements(records);
    /** 
     * Configure the Flink connector with the required properties.
     * You also need to add properties "sink.properties.format" and "sink.properties.strip_outer_array"
     * to tell the Flink connector the input records are JSON-format and to strip the outermost array structure. 
     */
    StarRocksSinkOptions options = StarRocksSinkOptions.builder()
            .withProperty("jdbc-url", jdbcUrl)
            .withProperty("load-url", loadUrl)
            .withProperty("database-name", "test")
            .withProperty("table-name", "score_board")
            .withProperty("username", "root")
            .withProperty("password", "")
            .withProperty("sink.properties.format", "json")
            .withProperty("sink.properties.strip_outer_array", "true")
            .build();
    // Create the sink with the options.
    SinkFunction<String> starRockSink = StarRocksSink.sink(options);
    source.addSink(starRockSink);
  • Write custom Java object data

    If your input records are custom Java objects, see the complete Flink DataStream job code in LoadCustomJavaRecords.

    • In this example, a simple POJO class RowData is defined to represent each record.

      public static class RowData {
              public int id;
              public String name;
              public int score;
              public RowData() {}
              public RowData(int id, String name, int score) {
                  this.id = id;
                  this.name = name;
                  this.score = score;
              }
          }
      
    • The main code is as follows.

      // Generate records which use RowData as the container.
      RowData[] records = new RowData[]{
              new RowData(1, "starrocks-rowdata", 100),
              new RowData(2, "flink-rowdata", 100),
          };
      DataStream<RowData> source = env.fromElements(records);
      // Configure the Flink connector with the required properties.
      StarRocksSinkOptions options = StarRocksSinkOptions.builder()
              .withProperty("jdbc-url", jdbcUrl)
              .withProperty("load-url", loadUrl)
              .withProperty("database-name", "test")
              .withProperty("table-name", "score_board")
              .withProperty("username", "root")
              .withProperty("password", "")
              .build();
      /**
       * The Flink connector will use a Java object array (Object[]) to represent a row to be loaded into the StarRocks table,
       * and each element is the value for a column.
       * You need to define the schema of the Object[] which matches that of the StarRocks table.
       */
      TableSchema schema = TableSchema.builder()
              .field("id", DataTypes.INT().notNull())
              .field("name", DataTypes.STRING())
              .field("score", DataTypes.INT())
              // When the StarRocks table is a Primary Key table, you must specify notNull(), for example, DataTypes.INT().notNull(), for the primary key `id`.
              .primaryKey("id")
              .build();
      // Transform the RowData to the Object[] according to the schema.
      RowDataTransformer transformer = new RowDataTransformer();
      // Create the sink with the schema, options, and transformer.
      SinkFunction<RowData> starRockSink = StarRocksSink.sink(schema, options, transformer);
      source.addSink(starRockSink);
      

      The RowDataTransformer is defined as follows.

      private static class RowDataTransformer implements StarRocksSinkRowBuilder<RowData> {
          /**
           * Set each element of the object array according to the input RowData.
           * The schema of the array matches that of the StarRocks table.
           */
          @Override
          public void accept(Object[] internalRow, RowData rowData) {
              internalRow[0] = rowData.id;
              internalRow[1] = rowData.name;
              internalRow[2] = rowData.score;
              // When the StarRocks table is a Primary Key table, you need to set the last element to indicate whether the data loading is an UPSERT or DELETE operation.
              internalRow[internalRow.length - 1] = StarRocksSinkOP.UPSERT.ordinal();
          }
      }  

Synchronize data using Flink CDC 3.0

The Flink CDC 3.0 framework simplifies building streaming ELT pipelines from CDC data sources, such as MySQL or Kafka, to StarRocks. With this pipeline, you can:

  • Automatically create databases and tables

  • Synchronize full and incremental data

  • Synchronize schema changes

Starting from StarRocks Flink Connector v1.2.9, the connector is integrated into the Flink CDC 3.0 framework and renamed StarRocks Pipeline Connector. This connector supports all the preceding features. We recommend that you use it with StarRocks v3.2.1 or later to leverage the `fast_schema_evolution` feature, which further accelerates column additions and deletions and reduces resource consumption.

Best practices

Import into a primary key table

  1. Create a database named test in StarRocks, and then create a primary key table named score_board.

    CREATE DATABASE `test`;
    CREATE TABLE `test`.`score_board`
    (
        `id` int(11) NOT NULL COMMENT "",
        `name` varchar(65533) NULL DEFAULT "" COMMENT "",
        `score` int(11) NOT NULL DEFAULT "0" COMMENT ""
    )
    ENGINE=OLAP
    PRIMARY KEY(`id`)
    COMMENT "OLAP"
    DISTRIBUTED BY HASH(`id`);
  2. Insert data into the StarRocks table.

    INSERT INTO `test`.`score_board` VALUES (1, 'starrocks', 100), (2, 'flink', 100);
  3. Run the following command to start the Flink SQL client.

    /opt/apps/FLINK/flink-current/bin/sql-client.sh
  4. Update data.

    Partial update

    Partial update lets you update only specific columns, such as name, without affecting others, such as score.

    1. Create the score_board table in the Flink SQL client and enable partial updates.

      CREATE TABLE `score_board` (
          `id` INT,
          `name` STRING,
          PRIMARY KEY (id) NOT ENFORCED
      ) WITH (
          'connector' = 'starrocks',
          'jdbc-url' = 'jdbc:mysql://<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:9030',
          'load-url' = '<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:8030',
          'database-name' = 'test',
          'table-name' = 'score_board',
          'username' = 'admin',
          'password' = '<password>',
          'sink.properties.partial_update' = 'true',
          -- only for Flink connector version <= 1.2.7
          'sink.properties.columns' = 'id,name,__op'
      ); 
      • sink.properties.partial_update: Enables partial updates.

      • sink.properties.columns: Specifies the columns to update. If the Flink Connector version is 1.2.7 or earlier, you must also set the sink.properties.columns option to id,name,__op to inform the Flink connector which columns to update. Note that you must append the __op field at the end. The __op field indicates whether the import is an UPSERT or DELETE operation, and its value is automatically set by the Flink connector.

    2. Insert updated data.

      Insert two rows that have the same primary keys as existing data but with modified values in the name column.

      INSERT INTO score_board VALUES (1, 'starrocks-update'), (2, 'flink-update');
    3. Query the StarRocks table in the SQL Editor.

      SELECT * FROM `test`.`score_board`;

      You will see that only the values in the name column have changed, while the score column remains unchanged.

      The query returns two records: id=1, name=starrocks-update, score=100 and id=2, name=flink-update, score=100.

    Conditional update

    This example shows how to perform conditional updates based on the value of the score column. A row is updated only if the score value in the incoming data is greater than or equal to the current value in the StarRocks table.

    1. Create the score_board table in the Flink SQL client as follows.

      CREATE TABLE `score_board` (
          `id` INT,
          `name` STRING,
          `score` INT,
          PRIMARY KEY (id) NOT ENFORCED
      ) WITH (
          'connector' = 'starrocks',
          'jdbc-url' = 'jdbc:mysql://<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:9030',
          'load-url' = '<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:8030',
          'database-name' = 'test',
          'table-name' = 'score_board',
          'username' = 'admin',
          'password' = '<password>',
          'sink.properties.merge_condition' = 'score',
          'sink.version' = 'V1'
      );
      • sink.properties.merge_condition: Set to score. This specifies that the Flink Connector uses the score column as the update condition during data writes.

      • sink.version: Set to V1. This specifies that the Flink Connector uses the Stream Load interface to import data.

    2. Insert two rows of data into the table in the Flink SQL client.

      The rows have the same primary keys as existing rows in the StarRocks table. The first row has a smaller score value, and the second row has a larger score value.

      INSERT INTO `score_board` VALUES (1, 'starrocks-update', 99), (2, 'flink-update', 101);
    3. Query the StarRocks table in the SQL Editor.

      SELECT * FROM `test`.`score_board`;

      You will see that only the second row has changed, while the first row remains unchanged.

      The query returns two records: the first row id=1, name=starrocks, score=100 (unchanged) and the second row id=2, name=flink-update, score=101 (updated).

Import into a Bitmap column

The Bitmap data type is commonly used to accelerate exact distinct count scenarios, such as calculating unique visitors (UV). The following example shows how to import data into a Bitmap column of a StarRocks table using Flink SQL and query the UV count in StarRocks.

  1. Create a StarRocks aggregate table in the SQL Editor.

    Create an aggregate table named page_uv in the test database with the following specifications:

    • The visit_users column is defined as the BITMAP type and configured with the `BITMAP_UNION` aggregate function.

    • page_id and visit_date serve as aggregate keys (AGGREGATE KEY) for grouping and deduplication.

    CREATE TABLE `test`.`page_uv` (
      `page_id` INT NOT NULL COMMENT 'page ID',
      `visit_date` datetime NOT NULL COMMENT 'access time',
      `visit_users` BITMAP BITMAP_UNION NOT NULL COMMENT 'user ID'
    ) ENGINE=OLAP
    AGGREGATE KEY(`page_id`, `visit_date`)
    DISTRIBUTED BY HASH(`page_id`);
  2. Create a table in the Flink SQL client.

    Because Flink does not support the Bitmap type, you must implement column mapping and type conversion as follows:

    • In the Flink table, define the visit_user_id column as BIGINT to represent the visit_users column in the StarRocks table.

    • Use the sink.properties.columns configuration to convert the data in the visit_user_id column to the Bitmap type using the `to_bitmap` function.

    CREATE TABLE `page_uv` (
        `page_id` INT,
        `visit_date` TIMESTAMP,
        `visit_user_id` BIGINT
    ) WITH (
        'connector' = 'starrocks',
        'jdbc-url' = 'jdbc:mysql://<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:9030',
        'load-url' = '<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:8030',
        'database-name' = 'test',
        'table-name' = 'page_uv',
        'username' = 'admin',
        'password' = '<password>',
        'sink.properties.columns' = 'page_id,visit_date,visit_user_id,visit_users=to_bitmap(visit_user_id)'
    );
  3. Insert data in the Flink SQL client.

    Insert multiple rows into the page_uv table to simulate different users accessing pages at different times.

    visit_user_id is of the BIGINT type. Flink automatically converts it to the Bitmap type.
    INSERT INTO `page_uv` VALUES
       (1, CAST('2020-06-23 01:30:30' AS TIMESTAMP), 13),
       (1, CAST('2020-06-23 01:30:30' AS TIMESTAMP), 23),
       (1, CAST('2020-06-23 01:30:30' AS TIMESTAMP), 33),
       (1, CAST('2020-06-23 02:30:30' AS TIMESTAMP), 13),
       (2, CAST('2020-06-23 01:30:30' AS TIMESTAMP), 23);
  4. Query the UV count in the SQL Editor.

    Use the aggregation capability of StarRocks to calculate the unique visitor count (UV) per page with COUNT(DISTINCT visit_users).

    SELECT page_id, COUNT(DISTINCT visit_users) FROM page_uv GROUP BY page_id;

    For page_id 2, count(DISTINCT visit_users) is 1. For page_id 1, count(DISTINCT visit_users) is 3.

Import into an HLL column

HyperLogLog (HLL) is a data type used for approximate distinct counting and is suitable for calculating unique visitors (UV) in large-scale data scenarios. The following example shows how to import data into an HLL column of a StarRocks table using Flink SQL and query the UV count in StarRocks.

  1. Create a StarRocks aggregate table in the SQL Editor.

    Create an aggregate table named hll_uv in the test database with the following specifications:

    • The visit_users column is defined as the HLL type and configured with the `HLL_UNION` aggregate function.

    • page_id and visit_date serve as aggregate keys (AGGREGATE KEY) for grouping and deduplication.

    CREATE TABLE `test`.`hll_uv` (
      `page_id` INT NOT NULL COMMENT 'page ID',
      `visit_date` DATETIME NOT NULL COMMENT 'access time',
      `visit_users` HLL HLL_UNION NOT NULL COMMENT 'user ID'
    ) ENGINE=OLAP
    AGGREGATE KEY(`page_id`, `visit_date`)
    DISTRIBUTED BY HASH(`page_id`);
  2. Create a table in the Flink SQL client.

    Because Flink does not support the HLL type, you must implement column mapping and type conversion as follows:

    • In the Flink table, define the visit_user_id column as BIGINT to represent the visit_users column in the StarRocks table.

    • Use the sink.properties.columns configuration to map columns and convert the BIGINT-type visit_user_id data to the HLL type using the `hll_hash` function.

    CREATE TABLE `hll_uv` (
        `page_id` INT,
        `visit_date` TIMESTAMP,
        `visit_user_id` BIGINT
    ) WITH (
        'connector' = 'starrocks',
        'jdbc-url' = 'jdbc:mysql://<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:9030',
        'load-url' = '<fe-{srClusterId}-internal.starrocks.aliyuncs.com>:8030',
        'database-name' = 'test',
        'table-name' = 'hll_uv',
        'username' = 'admin',
        'password' = '<password>',
        'sink.properties.columns' = 'page_id,visit_date,visit_user_id,visit_users=hll_hash(visit_user_id)'
    );
  3. Insert data in the Flink SQL client.

    Insert multiple rows into the hll_uv table to simulate different users accessing pages at different times.

    visit_user_id is of the BIGINT type. Flink automatically converts it to the HLL type.
    INSERT INTO `hll_uv` VALUES
       (3, CAST('2023-07-24 12:00:00' AS TIMESTAMP), 78),
       (4, CAST('2023-07-24 13:20:10' AS TIMESTAMP), 2),
       (3, CAST('2023-07-24 12:30:00' AS TIMESTAMP), 674);
  4. Query the UV count in the SQL Editor.

    Use the aggregation capability of StarRocks to calculate the unique visitor count (UV) per page with COUNT(DISTINCT visit_users).

    SELECT `page_id`, COUNT(DISTINCT `visit_users`) FROM `hll_uv` GROUP BY `page_id`;

    The result is as follows.

      page_id  count(DISTINCT visit_users)
    0       4                            1
    1       3                            2