5 Áp dụng Fuzzy Logic vào vấn đề tưới tiêu trong nông nghiệp
5.3.3 Thu thập và lưu trữ dữ liệu
Dữ liệu cảm biến được thu thập và gửi về Server ThingsBoard. Tại đây, Server Spark đóng vai trò làm Server xử lý trung tâm, chịu trách nhiệm lưu trữ dữ liệu cho ứng dụng, và sử dụng dữ liệu cho các bài toán cụ thể. Spark nhận các gói tin dữ liệu bằng cách đăng kí topic của kafka, sử dụng thư viện Spark Streaming
HÌNH5.10: Thu thập và lưu trữ dữ liệu
Ở Server Spark, khởi chạy một ứng dụng có tên SparkStream. Khai báo một dataframe có nhiệm vụ nhận dữ liệu gửi về từ Kafka. Ứng dụng đăng ký topic tên "gateway7" ở server ThingsBoard có địa chỉ "10.1.8.80:9092"
o b j e c t SparkStream {
def main ( args : Array [ String ] ) : Unit = { val conf = new SparkConf ;
Chương 5. Áp dụng Fuzzy Logic vào vấn đề tưới tiêu trong nông nghiệp 73 val sc = new SparkContext ( conf )
val spark = SparkSession . builder ( ) . appName( " SparkStream " ) . getOrCreate ( )
val df = spark
. readStream
. format ( " kafka " )
. option ( " kafka . bootstrap . servers " , " 1 0 . 1 . 8 . 8 0 : 9 0 9 2 " )
. option ( " subscribe " , " gateway7 " ) . load ( )
Khai báo schema cho dataframe gồm các trường sau:
• Gateway: Tên gateway
• temperature: Giá trị cảm biến nhiệt độ
• solar: Giá trị cảm biên ánh sáng
• soil: Giá trị cảm biến độ ẩm đất
• latitude: Giá trị vĩ độ
• longitude: Giá trị kinh độ
• deviceName: Tên thiết bị
• deviceType: Loại thiết bị
• ts: Giá trị timestamp
val schema = new StructType ( ) . add ( " Gateway " , StringType ) . add ( " temperature " , DoubleType ) . add ( " s o l a r " , DoubleType )
. add ( " s o i l " , DoubleType ) . add ( " l a t i t u d e " , DoubleType ) . add ( " longitude " , DoubleType ) . add ( " deviceName " , StringType ) . add ( " deviceType " , StringType )
Chương 5. Áp dụng Fuzzy Logic vào vấn đề tưới tiêu trong nông nghiệp 74 . add ( " t s " , StringType )
val valueDF = df
. selectExpr ( "CAST( value AS STRING) " )
. s e l e c t( from_json ( col ( " value " ) , schema ) . as ( " data " ) ) . s e l e c t( " data .* " )
Sử dụng module writeStream của Spark Streaming để nhận dữ liệu từ kafka. Với mỗi gói tin nhận được sẽ được gán tự động vào biến batchDF. Trong hàm foreachBatch, có thể tùy chỉnh hoặc tiền xử lý dữ liệu trước khi lưu HDFS.
valueDF . writeStream . foreachBatch {
( batchDF : DataFrame , batchId : Long)= >{
val format ="E dd−MMMM−yyyy HH:mm: ss . SSSS " val name_ts = " time "
val partition_format = "HH−dd−MMMM−yyyy " val p a r t i t i o n = " p a r t i t i o n "
// modify batchDF val df= batchDF
. withColumn ( name_ts , to_timestamp ( col ( " t s " )/1000)) . withColumn ( p a r t i t i o n ,
date_format ( col ( name_ts ) , partition_format ) )
. withColumn ( name_ts ,
date_format ( col ( name_ts ) , format ) )
// re−define the name of column
. s e l e c t ( col ( " temperature " ) . as ( " temp " ) , col ( " s o l a r " ) , col ( " s o i l " ) , col ( name_ts ) , col ( " t s " ) , col ( p a r t i t i o n ) ) // save hdfs df . coalesce ( 1 ) . write
. mode( SaveMode . Append) . partitionBy ( p a r t i t i o n )
Chương 5. Áp dụng Fuzzy Logic vào vấn đề tưới tiêu trong nông nghiệp 75 . csv ( "/user/spark/ i r r i g a t i o n _ c s v " ) } } . s t a r t ( ) . awaitTermination ( )
Ứng dụng có tính chất đọc dữ liệu theo giờ. Quá trình ghi dữ liệu được thiết kế theo kiểu partition. Sau khi nhận được batchDF sẽ tiến hành biến đổi và thêm 1 cột partition. Cột partition có định dạng giờ-ngày-tháng-năm tương ứng "HH-dd- MMMM-yyyy". Vì thế khi write HDFS sẽ tự động partition thành các Folder theo định dạng đó.
HÌNH5.11: Lưu dữ liệu theo partition