Apache Spark

1. Overview

IoTDB provides the Spark-IoTDB-Connector, a Spark connector for IoTDB‘s tree model, which supports reading and writing data from/to IoTDB’s tree model in Spark environments.

2. Compatibility Requirements

SoftwareVersion
Spark2.4.0-latest
Scala2.11, 2.12
  • The spark-iotdb-connector is compatible with Java, Scala-based Spark, and PySpark.

3. Deployment Methods

There are two usage scenarios for the spark-iotdb-connector: IDE development and spark-shell debugging.

3.1 IDE Development

For IDE development, simply add the following dependency to your pom.xml file.

<dependency>
      <groupId>org.apache.iotdb</groupId>
      <!-- spark-iotdb-connector_2.11 or spark-iotdb-connector_2.13 -->
      <artifactId>spark-iotdb-connector_2.12.10</artifactId>
      <version>${iotdb.version}</version>
    </dependency>

3.2 spark-shell Debugging

To use the spark-iotdb-connector in spark-shell, follow these steps:

  • Download the with-dependencies JAR package from the official website
  • Copy the JAR package to the ${SPARK_HOME}/jars directory using the following command:
cp spark-iotdb-connector_2.12.10-${iotdb.version}.jar $SPARK_HOME/jars/

To ensure Spark can connect to IoTDB via JDBC, perform the following steps:

  • Compile the IoTDB-JDBC connector by running:
mvn clean package -pl iotdb-client/jdbc -am -DskipTests -P get-jar-with-dependencies
  • The compiled JAR package will be located in the following directory:
$IoTDB_HOME/iotdb-client/jdbc/target/iotdb-jdbc-{version}-SNAPSHOT-jar-with-dependencies.jar
  • Copy the JAR package to the ${SPARK_HOME}/jars directory using the following command:
cp iotdb-jdbc-{version}-SNAPSHOT-jar-with-dependencies.jar $SPARK_HOME/jars/

4. Usage

4.1 Parameter Description

ParameterDescriptionDefault ValueUsage ScopeNullable
urlSpecifies the JDBC URL of IoTDBnullread, writeFALSE
userIoTDB usernamerootread, writeTRUE
passwordIoTDB passwordrootread, writeTRUE
sqlSpecifies the SQL query statementnullreadTRUE
numPartitionSpecifies the number of DataFrame partitions for read operations, and the write concurrency for write operations1read, writeTRUE
lowerBoundQuery start timestamp (inclusive)0readTRUE
upperBoundQuery end timestamp (inclusive)0readTRUE

4.2 Reading Data

  • Read data from IoTDB into a DataFrame
import org.apache.iotdb.spark.db._

val df = spark.read.format("org.apache.iotdb.spark.db")
  .option("user", "root")
  .option("password", "root")
  .option("url", "jdbc:iotdb://127.0.0.1:6667/")
  .option("sql", "select ** from root") // Query SQL
  .option("lowerBound", "0") // Timestamp lower bound
  .option("upperBound", "100000000") // Timestamp upper bound
  .option("numPartition", "5") // Number of partitions
  .load

df.printSchema()

df.show()

4.3 Writing Data

// Construct narrow table data
val df = spark.createDataFrame(List(
  (1L, "root.test.d0", 1, 1L, 1.0F, 1.0D, true, "hello"),
  (2L, "root.test.d0", 2, 2L, 2.0F, 2.0D, false, "world")))

val dfWithColumn = df.withColumnRenamed("_1", "Time")
  .withColumnRenamed("_2", "Device")
  .withColumnRenamed("_3", "s0")
  .withColumnRenamed("_4", "s1")
  .withColumnRenamed("_5", "s2")
  .withColumnRenamed("_6", "s3")
  .withColumnRenamed("_7", "s4")
  .withColumnRenamed("_8", "s5")

// Write narrow table data
dfWithColumn
  .write
  .format("org.apache.iotdb.spark.db")
  .option("url", "jdbc:iotdb://127.0.0.1:6667/")
  .save

// Construct wide table data
val df = spark.createDataFrame(List(
  (1L, 1, 1L, 1.0F, 1.0D, true, "hello"),
  (2L, 2, 2L, 2.0F, 2.0D, false, "world")))

val dfWithColumn = df.withColumnRenamed("_1", "Time")
  .withColumnRenamed("_2", "root.test.d0.s0")
  .withColumnRenamed("_3", "root.test.d0.s1")
  .withColumnRenamed("_4", "root.test.d0.s2")
  .withColumnRenamed("_5", "root.test.d0.s3")
  .withColumnRenamed("_6", "root.test.d0.s4")
  .withColumnRenamed("_7", "root.test.d0.s5")

// Write wide table data
dfWithColumn.write.format("org.apache.iotdb.spark.db")
  .option("url", "jdbc:iotdb://127.0.0.1:6667/")
  .option("numPartition", "10")
  .save

5. Wide Table vs Narrow Table

5.1 Data Format Example

Taking the TsFile structure as an example, assume there are three measurements in the TsFile schema: status, temperature, and hardware.

  • Basic information:
NameTypeEncoding
statusBooleanPLAIN
temperatureFloatRLE
hardwareTextPLAIN
  • Data:
    • d1:root.ln.wf01.wt01
    • d2:root.ln.wf02.wt02
timed1.statustimed1.temperaturetimed2.hardwaretimed2.status
1True12.22“aaa”1True
3True22.24“bbb”2False
5False32.16“ccc”4True
  • Wide table (default) format:
Timeroot.ln.wf02.wt02.temperatureroot.ln.wf02.wt02.statusroot.ln.wf02.wt02.hardwareroot.ln.wf01.wt01.temperatureroot.ln.wf01.wt01.statusroot.ln.wf01.wt01.hardware
1nulltruenull2.2truenull
2nullfalseaaa2.2nullnull
3nullnullnull2.1truenull
4nulltruebbbnullnullnull
5nullnullnullnullfalsenull
6nullnullcccnullnullnull
  • Narrow table format:
TimeDevicestatushardwaretemperature
1root.ln.wf01.wt01truenull2.2
1root.ln.wf02.wt02truenullnull
2root.ln.wf01.wt01nullnull2.2
2root.ln.wf02.wt02falseaaanull
3root.ln.wf01.wt01truenull2.1
4root.ln.wf02.wt02truebbbnull
5root.ln.wf01.wt01falsenullnull
6root.ln.wf02.wt02nullcccnull

Note: Corrected the device path typo in the original narrow table example (from root.ln.wf02.wt01 to root.ln.wf01.wt01) to match the data definition.

5.2 Data Conversion Example

  • Convert from wide table to narrow table
import org.apache.iotdb.spark.db._

val wide_df = spark.read.format("org.apache.iotdb.spark.db").option("url", "jdbc:iotdb://127.0.0.1:6667/").option("sql", "select * from root.** where time < 1100 and time > 1000").load
val narrow_df = Transformer.toNarrowForm(spark, wide_df)
  • Convert from narrow table to wide table
import org.apache.iotdb.spark.db._

val wide_df = Transformer.toWideForm(spark, narrow_df)