All Products
Search
Document Center

Lindorm:Interfaces

Last Updated:Mar 19, 2024

This topic describes how to use common interfaces provided by LindormTSDB SDK.

LindormTSDB SDK provide management interfaces, write interfaces, and a query interface.

Management interfaces

LindormTSDB allows you to execute SQL statements to perform Data Definition Language (DDL) and Data Control Language (DCL) operations. This section provides examples on how to submit SQL statements to perform DDL and DCL operations. LindormTSDB SDK allows you to use one of the following overload methods to submit SQL statements to LindormTSDB to perform DDL and DCL operations.

// Directly submit a SQL statement.
Result execute(String sql);

// Perform a DDL operation for a specified database. For example, you can perform a DDL operation to create a table in the database.
Result execute(String database, String sql);

The Result object contains the execution result of the SQL statement. For example, after you submit a SHOW DATABASES statement, you can obtain the list of existing databases from the Result object. The Result object consists of the columns, metadata, and rows fields. The columns field contains the names of all columns in the returned results. The metadata field contains the data types of the columns. The rows field contains the results that are returned by row.

public class Result {
    private List<String> columns;
    private List<String> metadata;
    private List<List<Object>> rows;
    
    ....
 }

Examples of database management and table management

You can perform DDL operations to create, delete, and query databases or tables. The following command can be used to set the schema constraint policy to weak constraint:

// 1. Query existing databases.
String showDatabase = "show databases";
Result result = lindormTSDBClient.execute(showDatabase);
System.out.println("before create, db list: " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

// 2. Create a database. In this example, a database named demo is created.
String createDatabase = "create database demo";
result = lindormTSDBClient.execute(createDatabase);
System.out.println("create database:" + result.isSuccessful());

// 3. Query existing databases.
result = lindormTSDBClient.execute(showDatabase);
System.out.println("after create, db list: " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

String database = "demo";

// 4. Query all existing tables.
String showTables = "show tables";
result = lindormTSDBClient.execute(database, showTables);
System.out.println("before create, table list: " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

// 5. Create a table.
String createTable = "CREATE TABLE sensor (device_id VARCHAR TAG,region VARCHAR TAG,time BIGINT,temperature DOUBLE,humidity DOUBLE,PRIMARY KEY(device_id))";
result = lindormTSDBClient.execute(database, createTable);
System.out.println("create table: " + result.isSuccessful());

// 6. Query existing tables to check whether the table sensor is created.
result = lindormTSDBClient.execute(database, showTables);
System.out.println("after create, table list: " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

// 7. Query the detailed information about a table.
String describeTable = "describe table sensor";
result = lindormTSDBClient.execute(database, describeTable);
System.out.println("------------ describe table -------------------");
List<String> columns = result.getColumns();
System.out.println("columns: " + columns);
List<String> metadata = result.getMetadata();
System.out.println("metadata: " + metadata);
List<List<Object>> rows = result.getRows();
for (int i = 0, size = rows.size(); i < size; i++) {
    List<Object> row = rows.get(i);
    System.out.println("column #" + i + " : " + row);
}

System.out.println("------------ describe table -------------------");
// 8. Delete a table.
String dropTable = "drop table sensor";
result = lindormTSDBClient.execute(database, dropTable);
System.out.println("drop table: " + result.isSuccessful());

// 9. Query existing tables to check whether the table is deleted.
result = lindormTSDBClient.execute(database, showTables);
System.out.println("after drop, table list: " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

// 10. Delete a database.
String dropDatabase = "drop database demo";
result = lindormTSDBClient.execute(dropDatabase);
System.out.println("drop database:" + result.isSuccessful());

// 11. Query existing databases to check whether the database is deleted.
result = lindormTSDBClient.execute(showDatabase);
System.out.println("after drop, db list : " +  result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));

Sample results:

before create, db list: [default]
create database:true
after create, db list: [default, demo]
before create, table list: []
create table: true
after create, table list: [sensor]
------------ describe table -------------------
columns: [columnName, typeName, columnKind]
metadata: [VARCHAR, VARCHAR, VARCHAR]
column #0 : [device_id, VARCHAR, TAG]
column #1 : [region, VARCHAR, TAG]
column #2 : [time, TIMESTAMP, TIMESTAMP]
column #3 : [temperature, DOUBLE, FIELD]
column #4 : [humidity, DOUBLE, FIELD]
------------ describe table -------------------
drop table: true
after drop, table list: []
drop database:true
after drop, db list : [default]
Note

Other management-related operations, such as DDL operations performed to create and delete continuous queries, are not described in this section. You can refer to the SQL syntax supported by LindormTSDB to perform these operations. For more information about the SQL statements supported by LindormTSDB, see SQL syntax.

Write interfaces

LindormTSDB SDK provides multiple write interfaces. These write interfaces are write methods whose names are the same but use different parameters. The write interfaces can be classified into the following types based on how the interfaces process write results: write interfaces that use the CompletableFuture<WriteResult> class to process write results, and write interfaces that use callback functions to process asynchronous write results.

By default, LindormTSDBClient uses the asynchronous batch write method to improve the efficiency of write operations. If you want to perform synchronous write operations, call the join method of the CompletableFuture<WriteResult> class returned by the write method.

Write operation records

LindormTSDB SDK uses a Record object to store the information about a row that is to be written into a table. You must specify the table name, timestamp, tags, field names, and field values in a Record object. The timestamp and tags are used to create indexes.

By default, LindormTSDB SDK verifies the validity of characters when you create a Record object. You can specify the parameter 'false' in the build() method.

Record record = Record
    // The name of the table.
    .table("sensor")
    // The timestamp that is accurate to milliseconds.
    .time(currentTime)
    // The tags.
    .tag("device_id", "F07A1260")
    .tag("region", "north-cn")
    // The field names and field values.
    .addField("temperature", 12.1)
    .addField("humidity", 45.0)
    .build();

Interfaces that use the CompletableFuture object to process write results

  • Submit only one write operation record each time.

// Write to the default database. 
CompletableFuture<WriteResult> future = lindormTSDBClient.write(record);

// Write data to a specified database.
String database = "demo";
CompletableFuture<WriteResult> future = lindormTSDBClient.write(database, record);
  • Submit multiple write operation records in a batch. We recommend that you use this method. You can use this method to reduce lock contention issues that occur in the pending tasks in the asynchronous queue when you use LindormTSDB SDK to submit tasks.

List<Record> records;
// Write data to the default database.
CompletableFuture<WriteResult> future = lindormTSDBClient.write(records);

// Write data to a specified database.
String database = "demo";
CompletableFuture<WriteResult> future = lindormTSDBClient.write(database, records);
  • Process the result returned by the CompletableFuture<WriteResult> object. The following code block shows an example. You can call other methods of the CompletableFuture object based on your business requirements.

CompletableFuture<WriteResult> future = lindormTSDBClient.write(records);
// Process asynchronous write results.
future.whenComplete((r, ex) -> {
    if (ex != null) { // A submission exception occurs. In most cases, the exception is returned because a write operation fails.
        System.out.println("Failed to write.");
        Throwable throwable = ExceptionUtils.getRootCause(ex);
        if (throwable instanceof LindormTSDBException) {
            LindormTSDBException e = (LindormTSDBException) throwable;
            System.out.println("Caught an LindormTSDBException, which means your request made it to Lindorm TSDB, "
                               + "but was rejected with an error response for some reason.");
            System.out.println("Error Code: " + e.getCode());
            System.out.println("SQL State:  " + e.getSqlstate());
            System.out.println("Error Message: " + e.getMessage());
        }  else {
            throwable.printStackTrace();
        }
    } else  { // The write operation is successful.
        if (r.isSuccessful()) {
            System.out.println("Write successfully.");
        } else {
            System.out.println("Write failure.");
        }
    }
});
Important

Do not use the whenComplete method of the CompletableFuture object to perform complex and time-consuming calculation. Otherwise, the calculation may become stuck. If you want to perform complex and time-consuming calculation, submit the calculation task to other independent thread pools. For more information about the error codes, see Common error codes.

Interfaces that use callback functions to process asynchronous write results

  • The following code block shows a write callback. The result parameter in the onCompletion method indicates the write result, the records parameter indicates the write operation record that corresponds to the callback, and the e parameter indicates the exception that is thrown when a write operation failure occurs.

public interface Callback {
    void onCompletion(WriteResult result, List<Record> records, Throwable e);
}

The following example shows how to use a callback to process write results:

Callback callback =  new Callback() {
    @Override
    public void onCompletion(WriteResult result, List<Record> list,
                             Throwable throwable) {
        if (throwable != null) { // Write operation failure.
            if (throwable instanceof LindormTSDBException) {
                LindormTSDBException ex = (LindormTSDBException) throwable;
                System.out.println("errorCode: " + ex.getCode());
                System.out.println("sqlstate: " + ex.getSqlstate());
                System.out.println("message: " + ex.getMessage());
            } else {
                // Other errors.
                throwable.printStackTrace();
            }
        } else {
            if (result.isSuccessful()) {
                System.out.println("Write successfully.");
            } else {
                System.out.println("Write failure.");
            }
        }
    }
};
Important

Do not use the onCompletion method of the callback to perform complex and time-consuming calculation. Otherwise, the calculation may become stuck. If you want to perform complex and time-consuming calculation, submit the calculation task to other independent thread pools. For more information about the error codes, see Common error codes.

  • Submit only one write operation record each time.

// Write data to the default database. 
lindormTSDBClient.write(record, callback);

// Write data to a specified database.
String database = "demo";
lindormTSDBClient.write(database, record, callback);
  • Submit multiple write operation records in a batch. We recommend that you use this method. You can use this method to reduce lock contention issues that occur in the pending tasks in the asynchronous queue when you use LindormTSDB SDK to submit tasks.

List<Record> records;
// Write data to the default database.
lindormTSDBClient.write(records, callback);

// Write data to a specified database.
String database = "demo";
lindormTSDBClient.write(database, records, callback);

Query operations

The query interface provided by LindormTSDB SDK allows you to use SQL statements to query data. For more information, see SQL syntax.

The following code block provides an example of the query interface provided by LindormTSDB SDK. You must configure the input parameters to specify the database that you want to query, the SQL statement that is used to query data, and the chunk size that specifies the number of rows to be returned in each batch.

ResultSet query(String database, String sql, int chunkSize);

The following code block shows the ResultSet interface that is used by LindormTSDB SDK to display the results of SQL statements:

public interface ResultSet extends Closeable {

    QueryResult next();

    void close();
}

You can use the next() method of the ResultSet interface to obtain the query results in a loop. If the QueryResult object returned by the next() method is null, all query results are obtained. After all query results are obtained, you can call the close method of the ResultSet interface to release the occupied input and output resources.

The QueryResult object consists of the columns, metadata, and rows fields. The columns field contains the names of all columns in the query results. The metadata field contains the data types of the columns. The rows field contains the query results that are returned by row. For more information about the data types supported by LindormTSDB, see Data types. The following example shows how to use ResultSet to process query results.

String sql = "select * from sensor";
int chunkSize = 100;
ResultSet resultSet = lindormTSDBClient.query("demo", sql, chunkSize);

// Process query results.
try {
    QueryResult result = null;
    // If the next() method of ResultSet returns null, all query results are obtained.
    while ((result = resultSet.next()) != null) {
        List<String> columns = result.getColumns();
        System.out.println("columns: " + columns);
        List<String> metadata = result.getMetadata();
        System.out.println("metadata: " + metadata);
        List<List<Object>> rows = result.getRows();
        for (int i = 0, size = rows.size(); i < size; i++) {
            List<Object> row = rows.get(i);
            System.out.println("row #" + i + " : " + row);
        }
    }
} finally {
    // After all query results are obtained, make sure that you call the close method of ResultSet to release the occupied input and output resources.
    resultSet.close();
}
Important

Regardless of whether a query is successful, you must explicitly call the close method of ResultSet to release input and output resources after the query is completed. Otherwise, a connection leak occurs.

LindormTSDB SDK also provides multiple implementations for overloading the query interface. You can choose one of the following implementations based on your business requirements.

// The SQL statement.
String sql = "xxxx";

// 1. Execute a SQL statement to query the default database. By default, 1,000 rows are returned in each batch.
ResultSet resultSet = lindormTSDBClient.query(sql);

String database = "demo";
// 2. Execute a SQL statement to query a specified database. By default, 1,000 rows are returned in each batch.
ResultSet resultSet = lindormTSDBClient.query(database, sql);