C++ 原生接口
C++ 原生接口
1. 依賴
- Java 8+
- Flex
- Bison 2.7+
- Boost 1.56+
- OpenSSL 1.0+
- GCC 4.8.5+
2. 安裝
2.1 安裝相關依賴
- MAC
安裝 Bison :
使用下面 brew 命令安裝 bison 版本:
brew install bison安裝 Boost :確保安裝最新的 Boost 版本。
brew install boost檢查 OpenSSL :確保 openssl 庫已安裝,默認的 openssl 頭文件路徑為"/usr/local/opt/openssl/include"
如果在編譯過程中出現找不到 openssl 的錯誤,嘗試添加
-Dopenssl.include.dir=""
Ubuntu 16.04+ 或其他 Debian 系列
使用以下命令安裝所賴:
sudo apt-get update sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-devCentOS 7.7+/Fedora/Rocky Linux 或其他 Red-hat 系列
使用 yum 命令安裝依賴:
sudo yum update sudo yum install gcc gcc-c++ boost-devel bison flex openssl-develWindows
構建編譯環境
- 安裝 MS Visual Studio(推薦安裝 2019+ 版本):安裝時需要勾選 Visual Studio C/C++ IDE and compiler(supporting CMake, Clang, MinGW)
- 下載安裝 CMake 。
下載安裝 Flex、Bison
- 下載 Win_Flex_Bison
- 下載后需要將可執行文件重命名為 flex.exe 和 bison.exe 以保證編譯時能夠被找到,添加可執行文件的目錄到 PATH 環境變量中
安裝 Boost 庫
- 下載 Boost
- 本地編譯 Boost :依次執行 bootstrap.bat 和 b2.exe
- 添加 Boost 安裝目錄到 PATH 環境變量中,例如
C:\Program Files (x86)\boost_1_78_0
安裝 OpenSSL
- 下載安裝 OpenSSL
- 添加 OpenSSL 下的 include 目錄到 PATH 環境變量中
2.2 執行編譯
從 git 克隆源代碼:
git clone https://github.com/apache/iotdb.git默認的主分支是 master 分支,如果你想使用某個發布版本,請切換分支 (如 1.3.2 版本):
git checkout rc/1.3.2在 IoTDB 根目錄下執行 maven 編譯:
Mac 或 glibc 版本 >= 2.32 的 Linux
./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cppglibc 版本 >= 2.31 的 Linux
./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOTglibc 版本 >= 2.23 的 Linux
./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOTglibc 版本 >= 2.17 的 Linux
./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-gcc4-SNAPSHOT使用 Visual Studio 2022 的 Windows
.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp使用 Visual Studio 2019 的 Windows
.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 16 2019" -Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT- 如果沒有將 Boost 庫地址加入 PATH 環境變量,在編譯命令中還需添加相關參數,例如:
-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"
- 如果沒有將 Boost 庫地址加入 PATH 環境變量,在編譯命令中還需添加相關參數,例如:
編譯成功后,打包好的庫文件位于 iotdb-client/client-cpp/target 中,同時可以在 example/client-cpp-example/target 下找到編譯好的示例程序。
2.3 編譯 Q&A
Q:Linux 上的環境有哪些要求呢?
A:
- 已知依賴的 glibc (x86_64 版本) 最低版本要求為 2.17,GCC 最低版本為 5.5
- 已知依賴的 glibc (ARM 版本) 最低版本要求為 2.31,GCC 最低版本為 10.2
- 如果不滿足上面的要求,可以嘗試自己本地編譯 Thrift
- 下載 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 這里的代碼
- 執行
./mvnw clean install - 回到 iotdb 代碼目錄執行
./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp
Q:Linux 編譯報錯undefined reference to '_libc_sinle_thread'如何處理?
A:
- 該問題是用于默認的預編譯 Thrift 依賴了過高的 glibc 版本導致的
- 可以嘗試在編譯的 maven 命令中增加
-Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT或者-Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT
Q:如果在 Windows 上需要使用 Visual Studio 2017 或更早版本進行編譯,要怎么做?
A:
- 可以嘗試自己本地編譯 Thrift 后再進行客戶端的編譯
- 下載 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 這里的代碼
- 執行
.\mvnw.cmd clean install - 回到 iotdb 代碼目錄執行
.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 15 2017"
3. 基本接口說明
下面將給出 Session 接口的簡要介紹和原型定義:
3.1 初始化
- 開啟 Session
void open();- 開啟 Session,并決定是否開啟 RPC 壓縮
void open(bool enableRPCCompression);注意: 客戶端的 RPC 壓縮開啟狀態需和服務端一致。
- 關閉 Session
void close();3.2 數據定義接口(DDL)
Database 管理
- 設置 database
void setStorageGroup(const std::string &storageGroupId);- 刪除單個或多個 database
void deleteStorageGroup(const std::string &storageGroup);
void deleteStorageGroups(const std::vector<std::string> &storageGroups);時間序列管理
- 創建單個或多個非對齊時間序列
void createTimeseries(const std::string &path, TSDataType::TSDataType dataType, TSEncoding::TSEncoding encoding,
CompressionType::CompressionType compressor);
void createMultiTimeseries(const std::vector<std::string> &paths,
const std::vector<TSDataType::TSDataType> &dataTypes,
const std::vector<TSEncoding::TSEncoding> &encodings,
const std::vector<CompressionType::CompressionType> &compressors,
std::vector<std::map<std::string, std::string>> *propsList,
std::vector<std::map<std::string, std::string>> *tagsList,
std::vector<std::map<std::string, std::string>> *attributesList,
std::vector<std::string> *measurementAliasList);- 創建對齊時間序列
void createAlignedTimeseries(const std::string &deviceId,
const std::vector<std::string> &measurements,
const std::vector<TSDataType::TSDataType> &dataTypes,
const std::vector<TSEncoding::TSEncoding> &encodings,
const std::vector<CompressionType::CompressionType> &compressors);- 刪除一個或多個時間序列
void deleteTimeseries(const std::string &path);
void deleteTimeseries(const std::vector<std::string> &paths);- 檢查時間序列是否存在
bool checkTimeseriesExists(const std::string &path);元數據模版
- 創建元數據模板
void createSchemaTemplate(const Template &templ);- 掛載元數據模板
void setSchemaTemplate(const std::string &template_name, const std::string &prefix_path);請注意,如果一個子樹中有多個孩子節點需要使用模板,可以在其共同父母節點上使用 setSchemaTemplate 。而只有在已有數據點插入模板對應的物理量時,模板才會被設置為激活狀態,進而被 show timeseries 等查詢檢測到。
- 卸載元數據模板
void unsetSchemaTemplate(const std::string &prefix_path, const std::string &template_name);注意:目前不支持從曾經在prefixPath路徑及其后代節點使用模板插入數據后(即使數據已被刪除)卸載模板。
- 在創建概念元數據模板以后,還可以通過以下接口增加或刪除模板內的物理量。請注意,已經掛載的模板不能刪除內部的物理量。
// 為指定模板新增一組對齊的物理量,若其父節點在模板中已經存在,且不要求對齊,則報錯
void addAlignedMeasurementsInTemplate(const std::string &template_name,
const std::vector<std::string> &measurements,
const std::vector<TSDataType::TSDataType> &dataTypes,
const std::vector<TSEncoding::TSEncoding> &encodings,
const std::vector<CompressionType::CompressionType> &compressors);
// 為指定模板新增一個對齊物理量, 若其父節點在模板中已經存在,且不要求對齊,則報錯
void addAlignedMeasurementsInTemplate(const std::string &template_name,
const std::string &measurement,
TSDataType::TSDataType dataType,
TSEncoding::TSEncoding encoding,
CompressionType::CompressionType compressor);
// 為指定模板新增一個不對齊物理量, 若其父節在模板中已經存在,且要求對齊,則報錯
void addUnalignedMeasurementsInTemplate(const std::string &template_name,
const std::vector<std::string> &measurements,
const std::vector<TSDataType::TSDataType> &dataTypes,
const std::vector<TSEncoding::TSEncoding> &encodings,
const std::vector<CompressionType::CompressionType> &compressors);
// 為指定模板新增一組不對齊的物理量, 若其父節在模板中已經存在,且要求對齊,則報錯
void addUnalignedMeasurementsInTemplate(const std::string &template_name,
const std::string &measurement,
TSDataType::TSDataType dataType,
TSEncoding::TSEncoding encoding,
CompressionType::CompressionType compressor);
// 從指定模板中刪除一個節點及其子樹
void deleteNodeInTemplate(const std::string &template_name, const std::string &path);- 對于已經創建的元數據模板,還可以通過以下接口查詢模板信息:
// 查詢返回目前模板中所有物理量的數量
int countMeasurementsInTemplate(const std::string &template_name);
// 檢查模板內指定路徑是否為物理量
bool isMeasurementInTemplate(const std::string &template_name, const std::string &path);
// 檢查在指定模板內是否存在某路徑
bool isPathExistInTemplate(const std::string &template_name, const std::string &path);
// 返回指定模板內所有物理量的路徑
std::vector<std::string> showMeasurementsInTemplate(const std::string &template_name);
// 返回指定模板內某前綴路徑下的所有物理量的路徑
std::vector<std::string> showMeasurementsInTemplate(const std::string &template_name, const std::string &pattern);3.3 數據操作接口(DML)
數據寫入
推薦使用 insertTablet 幫助提高寫入效率。
- 插入一個 Tablet,Tablet 是一個設備若干行數據塊,每一行的列都相同。
- 寫入效率高。
- 支持寫入空值:空值處可以填入任意值,然后通過 BitMap 標記空值。
void insertTablet(Tablet &tablet);- 插入多個 Tablet
void insertTablets(std::unordered_map<std::string, Tablet *> &tablets);- 插入一個 Record,一個 Record 是一個設備一個時間戳下多個測點的數據
void insertRecord(const std::string &deviceId, int64_t time, const std::vector<std::string> &measurements,
const std::vector<TSDataType::TSDataType> &types, const std::vector<char *> &values);- 插入多個 Record
void insertRecords(const std::vector<std::string> &deviceIds,
const std::vector<int64_t> ×,
const std::vector<std::vector<std::string>> &measurementsList,
const std::vector<std::vector<TSDataType::TSDataType>> &typesList,
const std::vector<std::vector<char *>> &valuesList);- 插入同屬于一個 device 的多個 Record
void insertRecordsOfOneDevice(const std::string &deviceId,
std::vector<int64_t> ×,
std::vector<std::vector<std::string>> &measurementsList,
std::vector<std::vector<TSDataType::TSDataType>> &typesList,
std::vector<std::vector<char *>> &valuesList);帶有類型推斷的寫入
服務器需要做類型推斷,可能會有額外耗時,速度較無需類型推斷的寫入慢。
void insertRecord(const std::string &deviceId, int64_t time, const std::vector<std::string> &measurements,
const std::vector<std::string> &values);
void insertRecords(const std::vector<std::string> &deviceIds,
const std::vector<int64_t> ×,
const std::vector<std::vector<std::string>> &measurementsList,
const std::vector<std::vector<std::string>> &valuesList);
void insertRecordsOfOneDevice(const std::string &deviceId,
std::vector<int64_t> ×,
std::vector<std::vector<std::string>> &measurementsList,
const std::vector<std::vector<std::string>> &valuesList);對齊時間序列寫入
對齊時間序列的寫入使用 insertAlignedXXX 接口,其余與上述接口類似:
- insertAlignedRecord
- insertAlignedRecords
- insertAlignedRecordsOfOneDevice
- insertAlignedTablet
- insertAlignedTablets
數據刪除
- 刪除一個或多個時間序列在某個時間范圍的數據
void deleteData(const std::string &path, int64_t endTime);
void deleteData(const std::vector<std::string> &paths, int64_t endTime);
void deleteData(const std::vector<std::string> &paths, int64_t startTime, int64_t endTime);3.4 IoTDB-SQL 接口
- 執行查詢語句
unique_ptr<SessionDataSet> executeQueryStatement(const std::string &sql);返回值 SessionDataSet 類主要提供如下方法:
| 方法名 | 描述 | 參數 | 返回值 |
|---|---|---|---|
| hasNext() | 判斷結果集中是否還有更多數據行。 | - | bool |
| next() | 獲取結果集中的下一行數據,封裝為一個 RowRecord 對象。 | - | std::shared_ptr |
| getIterator() | 獲取一個 DataIterator 迭代器,用于以更靈活的方式(按列)遍歷數據。 | - | SessionDataSet::DataIterator |
| getColumnNames() | 獲取結果集中所有列的名稱列表。 | - | const std::vector& |
| getColumnTypeList() | 獲取結果集中所有列的數據類型列表。 | - | const std::vector& |
| getFetchSize() | 獲取當前每次從服務器批量抓取數據的行數。 | - | int |
| setFetchSize(int fetchSize) | 設置每次從服務器批量抓取數據的行數。 | fetchSize: 批量抓取數據的行數 | void |
| closeOperationHandle(bool forceClose) | 關閉服務器端的查詢句柄,釋放資源。建議在數據集使用完畢后調用。 | forceClose: 是否強制關閉(默認為 false) | void |
- 執行非查詢語句
void executeNonQueryStatement(const std::string &sql);4. 示例代碼
示例工程源代碼:
example/client-cpp-example/src/SessionExample.cpp: SessionExampleexample/client-cpp-example/src/AlignedTimeseriesSessionExample.cpp(使用對齊時間序列) : AlignedTimeseriesSessionExample
編譯成功后,示例代碼工程位于 example/client-cpp-example/target
5. FAQ
5.1 Thrift 編譯相關問題
MAC:本地 Maven 編譯 Thrift 時如出現以下鏈接的問題,可以嘗試將 xcode-commandline 版本從 12 降低到 11.5
https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087Windows:Maven 編譯 Thrift 時需要使用 wget 下載遠端文件,可能出現以下報錯:
Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser解決方法:
- 嘗試刪除 ".m2\repository\.cache" 目錄并重試。
- 在添加 pom 文件對應的 download-maven-plugin 中添加 "<skipCache>true</skipCache>"