blob: 3f6d153fdeb8a7609e030d4b951e89234726939c [file] [view]
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# 快速上手 - C++
## 安装
C/C++ 2.5.0 提供预编译运行库、开发包和 CLI,**不必先用 Maven 编译 TsFile**。
开发应用需要 C/C++ 编译器。安装包提供的 CMake 配置支持 CMake 3.11+;选择 Windows 运行时需要 CMake 3.15+。只运行 CLI 不需要编译工具链。
完整下载链接和校验步骤见[下载与安装页面](../../../Download/README.md#cpp-packages)。
### 选择安装方式
| 平台 | 开发 C/C++ 应用 | 说明 |
| --- | --- | --- |
| Ubuntu 22.04 / 24.04 | `tsfile` + `tsfile-dev` | [DEB 下载、校验和安装](../../../Download/README.md#cpp-ubuntu) |
| AlmaLinux 9 | `tsfile` + `tsfile-devel` | [RPM 下载、校验和安装](../../../Download/README.md#cpp-rpm) |
| macOS | Homebrew Formula,或 SDK 压缩包 | [Homebrew 安装](../../../Download/README.md#cpp-homebrew),包含库、头文件和 CLI |
| Linux / macOS | 完整 SDK 压缩包 | 适合不修改系统目录的安装,示例见下文 |
| Windows | 对应架构的 SDK/CLI ZIP | [Windows 安装](../../../Download/README.md#cpp-windows),保留 DLL 与 `bin/` 布局 |
`tsfile-dev` / `tsfile-devel` 是开发文件包,不是开发版发行;CLI 位于 `tsfile-tools`。
下载并校验 DEB/RPM 后,可直接安装本地运行库与开发包,例如:
```bash
# Ubuntu amd64;arm64 使用对应文件名
sudo apt install ./tsfile_2.5.0-1_amd64.deb ./tsfile-dev_2.5.0-1_amd64.deb
```
```bash
# AlmaLinux 9 x86_64;aarch64 使用对应文件名
sudo dnf install ./tsfile-2.5.0-1.el9.x86_64.rpm ./tsfile-devel-2.5.0-1.el9.x86_64.rpm
```
### 解压安装 SDK(Linux / macOS)
在空目录执行下例。Apple Silicon Mac 使用 `macos12-arm64`;Intel Mac 使用 `macos12-x86_64`;
Linux 根据架构使用 `manylinux_2_28-x86_64` 或 `manylinux_2_28-aarch64`。
```bash
VERSION=2.5.0
PLATFORM=macos12-arm64
ARCHIVE="tsfile-sdk-${PLATFORM}-${VERSION}.tar.gz"
URL="https://packages.apache.org/artifactory/tsfile/sdk/release/versions/${VERSION}/${PLATFORM}/${ARCHIVE}"
curl --fail --location "$URL" --output "$ARCHIVE"
SHA256="$(curl --fail --silent --show-error "$URL.sha256")"
if command -v sha256sum >/dev/null 2>&1; then
printf '%s %s\n' "$SHA256" "$ARCHIVE" | sha256sum -c - || exit 1
else
printf '%s %s\n' "$SHA256" "$ARCHIVE" | shasum -a 256 -c - || exit 1
fi
mkdir tsfile-sdk
tar -xzf "$ARCHIVE" -C tsfile-sdk --strip-components=1
export TSFILE_HOME="$PWD/tsfile-sdk"
export PATH="$TSFILE_HOME/bin:$PATH"
tsfile-cli --version
```
若使用 Homebrew,先按下载页导入 Formula,再设置 `TSFILE_HOME="$(brew --prefix local/tsfile250/tsfile)"`。
SDK 包含 `include/`、`lib/`、`lib/cmake/TsFile/`、`lib/pkgconfig/`、`bin/` 和 `share/`;保留其相对布局。
### CMake 集成
在项目的 `CMakeLists.txt` 中使用安装包导出的 target,而不是只用 `find_library` 查找单个库文件:
```cmake
cmake_minimum_required(VERSION 3.11)
project(tsfile_example LANGUAGES CXX)
find_package(TsFile 2.5.0 CONFIG REQUIRED)
add_executable(tsfile_example main.cpp)
target_link_libraries(tsfile_example PRIVATE TsFile::tsfile)
```
```bash
cmake -S . -B build -DCMAKE_PREFIX_PATH="$TSFILE_HOME"
cmake --build build --config Release
```
在系统标准目录安装 DEB/RPM 后,通常无需设置 `CMAKE_PREFIX_PATH`。导出的 target 会传递所需头文件目录和编译定义。
Windows 使用匹配架构的 MSVC 和 CMake 3.15+,选择包要求的 Release `/MT` 运行时:
```powershell
cmake -S . -B build -DCMAKE_PREFIX_PATH="$env:TSFILE_HOME" `
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
cmake --build build --config Release
```
### pkg-config(Linux / macOS)
SDK 或 Homebrew 安装可通过前缀定位元数据;系统包通常可以直接查询:
```bash
export PKG_CONFIG_PATH="$TSFILE_HOME/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
pkg-config --modversion libtsfile
pkg-config --cflags --libs libtsfile
```
### 可选:从源码构建
只有需要修改 TsFile 或定制构建选项时才需要源码构建。此时需 JDK 17+、CMake、C++11 编译器和 Make/Ninja;
Maven 可使用仓库自带的 wrapper。源码构建版本取决于检出的分支或 commit,不等同于上面的 2.5.0 二进制包。
```bash
git clone https://github.com/apache/tsfile.git
cd tsfile
./mvnw clean package -P with-cpp -Dbuild.test=OFF
cmake --install cpp/target/build --prefix "$PWD/tsfile-sdk"
```
Windows 使用 `mvnw.cmd`。随后将 `CMAKE_PREFIX_PATH` 指向安装后的 `tsfile-sdk`;
不要将源码树内部的头文件与另一个版本的已安装库混用。CLI 的安装与使用另见 [TsFile CLI](../Tools/Tsfile-CLI.md)。
## 写入流程
### 构造 TsFileWriter
```cpp
std::string file_name = "test.tsfile";
storage::libtsfile_init();
std::string table_name = "table1";
// Create a file with specify path to write tsfile.
storage::WriteFile file;
int flags = O_WRONLY | O_CREAT | O_TRUNC;
#ifdef _WIN32
flags |= O_BINARY;
#endif
mode_t mode = 0666;
file.create("test_cpp.tsfile", flags, mode);
// Create table schema to describe a table in a tsfile.
auto* schema = new storage::TableSchema(
table_name,
{
common::ColumnSchema("id1", common::STRING, common::UNCOMPRESSED,
common::PLAIN, common::ColumnCategory::TAG),
common::ColumnSchema("id2", common::STRING, common::UNCOMPRESSED,
common::PLAIN, common::ColumnCategory::TAG),
common::ColumnSchema("s1", common::INT64, common::UNCOMPRESSED,
common::PLAIN, common::ColumnCategory::FIELD),
});
// Create a file with specify path to write tsfile.
auto* writer = new storage::TsFileTableWriter(&file, schema);
```
### 写入数据
```cpp
// Create tablet to insert data.
storage::Tablet tablet(
table_name, {"id1", "id2", "s1"},
{common::STRING, common::STRING, common::INT64},
{common::ColumnCategory::TAG, common::ColumnCategory::TAG,
common::ColumnCategory::FIELD},
10);
for (int row = 0; row < 5; row++) {
long timestamp = row;
tablet.add_timestamp(row, timestamp);
tablet.add_value(row, "id1", "id1_filed_1");
tablet.add_value(row, "id2", "id1_filed_2");
tablet.add_value(row, "s1", static_cast<int64_t>(row));
}
// Write tablet data.
writer->write_table(tablet);
// Flush data
writer->flush();
```
### 关闭文件
```cpp
writer->close()
```
### 示例代码
使用这些接口的示例代码可以在以下链接中找到 <https://github.com/apache/tsfile/blob/develop/cpp/examples/cpp_examples/demo_write.cpp>
## 查询流程
### 构造 TsFileReader
```cpp
int code = 0;
storage::libtsfile_init();
std::string table_name = "table1";
// Create tsfile reader and open tsfile with specify path.
storage::TsFileReader reader;
reader.open("test_cpp.tsfile");
```
### 构造 Query Request
```cpp
// Query data with tsfile reader.
storage::ResultSet* temp_ret = nullptr;
std::vector<std::string> columns;
columns.emplace_back("id1");
columns.emplace_back("id2");
columns.emplace_back("s1");
auto table_schema = reader.get_table_schema(table_name);
storage::Filter* tag_filter1 = storage::TagFilterBuilder(table_schema.get()).eq("id1", "id1_filed_1");
storage::Filter* tag_filter2 = storage::TagFilterBuilder(table_schema.get()).eq("id2", "id1_filed_2");
storage::Filter* tag_filter = storage::TagFilterBuilder(table_schema.get()).and_filter(tag_filter1, tag_filter2);
// Column vector contains the columns you want to select.
reader.query(table_name, columns, 0, 100, temp_ret, tag_filter);
```
### 查询数据
```cpp
// Get query handler.
auto ret = dynamic_cast<storage::TableResultSet*>(temp_ret);
// Metadata in query handler.
auto metadata = ret->get_metadata();
int column_num = metadata->get_column_count();
for (int i = 1; i <= column_num; i++) {
std::cout << "column name: " << metadata->get_column_name(i)
<< std::endl;
std::cout << "column type: "
<< std::to_string(metadata->get_column_type(i)) << std::endl;
}
// Check and get next data.
bool has_next = false;
while ((code = ret->next(has_next)) == common::E_OK && has_next) {
// Timestamp at column 1 and column index begin from 1.
Timestamp timestamp = ret->get_value<Timestamp>(1);
for (int i = 1; i <= column_num; i++) {
if (ret->is_null(i)) {
std::cout << "null" << std::endl;
} else {
switch (metadata->get_column_type(i)) {
case common::BOOLEAN:
std::cout << ret->get_value<bool>(i) << std::endl;
break;
case common::INT32:
std::cout << ret->get_value<int32_t>(i) << std::endl;
break;
case common::INT64:
std::cout << ret->get_value<int64_t>(i) << std::endl;
break;
case common::FLOAT:
std::cout << ret->get_value<float>(i) << std::endl;
break;
case common::DOUBLE:
std::cout << ret->get_value<double>(i) << std::endl;
break;
case common::STRING:
std::cout << ret->get_value<common::String*>(i)
->to_std_string()
<< std::endl;
break;
default:;
}
}
}
}
```
### 关闭文件
```cpp
// Close query result set.
ret->close();
// Close reader.
reader.close();
```
### 示例代码
使用这些接口的示例代码可以在以下链接中找到 <https://github.com/apache/tsfile/blob/develop/cpp/examples/cpp_examples/demo_read.cpp>
> 注意:以上读写示例均基于表模型接口,接口定义介绍可见[C++ 接口定义](./InterfaceDefinition/InterfaceDefinition-CPP.md)。若需了解树模型相关内容,请联系我们。