<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>article Real-time Vehicle Fleet Analytics with Databricks Delta Live Tables in Technical Blog</title>
    <link>https://community.databricks.com/t5/technical-blog/real-time-vehicle-fleet-analytics-with-databricks-delta-live/ba-p/91422</link>
    <description>&lt;H1&gt;&lt;SPAN&gt;Introduction&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;Today’s modern vehicles generate large streams of data which can be harnessed in a data-driven manner to boost efficiency, optimize costs, and minimize our environmental impact in real-time. By leveraging this data across a fleet of vehicles at scale, we can achieve even greater benefits, enabling more effective fleet management and optimization.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;When it comes to building real-time streaming applications from IoT devices, including vehicle fleet telemetry and other edge devices&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://protobuf.dev/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Protobuf (Protocol Buffers)&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; has emerged as a popular choice for companies. Its compact, efficient binary format ensures low latency and high throughput, making it ideal for handling critical data, enabling real-time decision-making, and optimizing operations.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Traditional approaches to managing Protobuf events can often introduce a heavy burden on Data Engineering teams, requiring specialized skills that are rare and costly. This increases the ongoing expenses related to maintaining proto packages, system upgrades, and infrastructure. Additionally, data integrity issues during event replays add further complexity, making it challenging for businesses to manage streaming applications efficiently and cost-effectively. This highlights the need for a simple, reliable, and performant solution that minimizes the dependency on technical resources.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;This blog explores how you can harness the capabilities of &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/delta-live-tables/serverless-dlt.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Serverless Delta Live Tables (DLT)&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; pipelines to transform raw IoT telemetry data from fleets into powerful insights. With &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/structured-streaming/protocol-buffers.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;native support&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;, Databricks greatly simplifies the process of serializing and de-serializing Protobuf events to enable these insights. Furthermore, Serverless ensures your data teams can focus on high-value activities like extracting insights while Databricks efficiently manages compute resources, including optimizing and scaling compute for workloads.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="5"&gt;&lt;STRONG&gt;Table of Contents&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;LI-TOC indent="15" liststyle="disc" maxheadinglevel="2"&gt;&lt;/LI-TOC&gt;&lt;/P&gt;
&lt;H2&gt;&amp;nbsp;&lt;/H2&gt;
&lt;H1&gt;&lt;SPAN&gt;Use Case: Optimize operations for your entire vehicle fleet&amp;nbsp;&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;Company XYZ is a hypothetical logistics provider created to demonstrate real-time vehicle fleet analytics with Databricks Delta Live Tables. They operate thousands of vehicles across various routes daily, facing challenges in optimizing fuel efficiency and monitoring vehicle utilization. Excessive idle times and unmonitored fuel consumption can lead to higher operational costs.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;To address these challenges, they leverage real-time data analytics using &lt;A href="https://www.databricks.com/product/delta-live-tables" target="_blank" rel="noopener"&gt;Databricks Delta Live Tables (DLT)&lt;/A&gt; to gain actionable insights from their fleet telemetry data, enabling them to optimize vehicle usage and reduce fuel expenses effectively.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;IoT devices in vehicles can transmit telemetry data such as location, speed, fuel level, and engine status. These data points can power insights into fuel efficiency and vehicle utilization, which are essential metrics for optimizing fleet operations.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The high-level architecture diagram below illustrates the end-to-end implementation of a streaming solution using Kafka and the Databricks Serverless DLT pipeline.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="High-level Architecture.jpg" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11415i9EEB3BC3960C04C9/image-size/large?v=v2&amp;amp;px=999" role="button" title="High-level Architecture.jpg" alt="High-level Architecture.jpg" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;A data producer generates fleet telemetry events into a Kafka topic in the Protobuf format. In real-world architectures, this data producer is replaced by the vehicle fleet telemetry IoT devices, which send events to a centralized system such as gRPC Server. This system packages and compacts the individual events into batch messages before transmitting them to Kafka. The Serverless DLT pipeline continuously ingests those events from the Kafka topic, deserializes them using the &lt;/SPAN&gt;&lt;SPAN&gt;from_protobuf&lt;/SPAN&gt; &lt;SPAN&gt;function, and populates the following tables in the medallion architecture.&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events_raw&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; table stores the raw events received from the Kafka topic.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; table stores the deserialized Protobuf messages.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;silver_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; table is an SCD type-1 that handles event replays from edge devices to ensure data integrity.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;The gold materialized views &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;gold_fuel_efficiency&lt;/SPAN&gt;&lt;/FONT&gt; &lt;SPAN&gt;and&lt;/SPAN&gt; &lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;gold_vehicle_utilization&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;, aggregations built on top of the Silver table, are used for downstream reporting and analytics.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN&gt;These Gold materialized views are critical for downstream analytics. They provide insights into fuel efficiency and vehicle utilization, which are essential metrics for optimizing fleet operations.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="background-color: lightyellow; width: 100%;"&gt;
&lt;P&gt;&lt;STRONG&gt;Note!&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;This blog uses Kafka to efficiently manage real-time fleet telemetry data, ensuring reliable streaming and handling of Protobuf-serialized messages.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;&lt;SPAN&gt;Serverless Delta Live Tables&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;When you build your DLT pipeline, you will be presented with a graphical and visual representation of the flows and dependencies in a Directed Acyclic Graph (DAG). This helps track the flow of data from raw ingestion to the final stages of processing.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The Protobuf deserialization occurs while populating the &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;, which serves as a source for performing change data capture into the silver table &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;silver_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;. Refer to the detailed sections below for each table to understand the data flow within this pipeline.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="DLT-Pipeline-Graph.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11416iB370985B42FD7FF4/image-size/large?v=v2&amp;amp;px=999" role="button" title="DLT-Pipeline-Graph.png" alt="DLT-Pipeline-Graph.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Leveraging the Serverless option for Delta Live Tables offers several key advantages, making it an ideal choice for efficiently processing Protobuf data without the overhead of managing infrastructure. It provides an easy-to-use and simple experience and builds a performant, auto-optimized, and fully managed data pipeline that will decrease overall TCO. You can enable Serverless DLT by navigating to the pipeline settings and ticking the "Serverless" option.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="DLT-Pipeline-Settings.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11417i1155EF18A7495AC9/image-size/large?v=v2&amp;amp;px=999" role="button" title="DLT-Pipeline-Settings.png" alt="DLT-Pipeline-Settings.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;For more detailed insights on the benefits of using serverless DLT, including how it enables cost-effective, incremental ETL pipelines, refer to this latest blog: "&lt;/SPAN&gt;&lt;A href="https://www.databricks.com/blog/cost-effective-incremental-etl-serverless-compute-delta-live-tables-pipelines" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Cost-effective, incremental ETL with serverless compute for Delta Live Tables pipelines&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;".&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;&lt;SPAN&gt;The 'Raw' Protobuf Event Data&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;Protobuf messages are often transmitted in consolidated batches rather than as individual events in high-throughput scenarios. They are prone to data repetition due to replaying past events from edge devices.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Data is typically structured using a Protobuf schema defined in the&amp;nbsp;&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;.proto&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; file. An example of one is shown below. The schema includes two message types: &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevent&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevents&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;fleet_management.proto&lt;/STRONG&gt;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;syntax = "proto3";
package blog.fleet.tracking;
 
message fleetevent {
  string vehicle_id = 1;
  int64 timestamp = 2;
  double latitude = 3;
  double longitude = 4;
  double speed = 5;
  double fuel_level = 6;
  string engine_status = 7;
}
message fleetevents {
  repeated fleetevent records = 1;
}&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;To optimize data transmission, individual fleet events &lt;/SPAN&gt;&lt;SPAN&gt;(&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevent&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN&gt;are consolidated into batches &lt;/SPAN&gt;&lt;SPAN&gt;(&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevents&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;)&lt;/SPAN&gt;&lt;SPAN&gt;, meaning several events are combined into a single message and then serialized into the Protobuf format before sent to Kafka.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Here is an example of a raw Protobuf payload retrieved from the Kafka topic. This payload contains a batch of multiple events, each corresponding to individual telemetry readings from a vehicle.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;"records": [
	{
  	"vehicle_id": "vehicle-27",
  	"timestamp": "1726397972207",
  	"latitude": 38.495878,
  	"longitude": 139.568327,
  	"speed": 6.95,
  	"fuel_level": 59.42,
  	"engine_status": "SERVICE_REQUIRED"
	},
...
...
...

	{
  	"vehicle_id": "vehicle-27",
  	"timestamp": "1726397972212",
  	"latitude": -83.874246,
  	"longitude": 172.466784,
  	"speed": 88.32,
  	"fuel_level": 79.39,
  	"engine_status": "SERVICE_REQUIRED"
	}
  ]
}
&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;H2&gt;&amp;nbsp;&lt;/H2&gt;
&lt;H1&gt;&lt;SPAN&gt;Ingesting Raw Data into Bronze Layer&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;The raw Protobuf data is ingested into the Bronze layer in two steps:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events_raw&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; - the original Protobuf events in the binary format.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;FONT face="courier new,courier"&gt;bronze_fleet_events&lt;/FONT&gt;&lt;SPAN&gt; - the original events deserialized into the structured format.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Ingesting Protobuf Events into Databricks Incrementally&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;The Bronze raw streaming table is where raw fleet telemetry events are ingested from Kafka in Protobuf binary format and ready for further processing. In the DLT pipeline, raw events are ingested into the &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events_raw&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; using the Spark &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;readStream&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; method. This method continuously ingests streaming data from the Kafka topic in real time.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Streaming tables in DLT are stateful, incrementally computed, and only process data added since the last pipeline run. &lt;/SPAN&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;readStream&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; query that defines the &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events_raw&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; is provided in the corresponding function.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;# Bronze raw streaming table
@dlt.table(
 name="bronze_fleet_events_raw",
 comment="bronze (raw) table that ingests the protobuf events from the Kafka topic"
)
def bronze_fleet_events_raw():
 return (
   spark.readStream
     .format("kafka")
     .options(**kafka_read_options)
     .load()
 )&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sample result: &lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events_raw &lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;contains the raw Protobuf messages ingested from Kafka&amp;nbsp;in the &lt;FONT face="courier new,courier"&gt;value&lt;/FONT&gt; column.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bronze_fleet_events_raw.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11418iD74A8DB70F919734/image-size/large?v=v2&amp;amp;px=999" role="button" title="bronze_fleet_events_raw.png" alt="bronze_fleet_events_raw.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;DIV id="tinyMceEditorsrikanthkilari_3" class="mceNonEditable lia-copypaste-placeholder"&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;H2&gt;&lt;SPAN&gt;Deserializing Protobuf Binary Data&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Deserialization converts the Protobuf binary data into readable structured data that can be processed and queried within the pipeline. The function definition of the Bronze table &lt;FONT face="courier new,courier"&gt;bronze_fleet_events&lt;/FONT&gt; consists of the Protobuf deserialization logic using the &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;from_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; function.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;value&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; column (containing the payload) and &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;schema_registry_options&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; are passed as parameters to the &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;from_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; function, which deserializes the payload into a struct. The &lt;/SPAN&gt;&lt;SPAN&gt;explode&lt;/SPAN&gt;&lt;SPAN&gt; function is used here to flatten the batch messages (&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevents&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;) into the individual event (&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;fleetevent&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;) records for further processing. Kafka metadata fields such as &lt;FONT face="courier new,courier"&gt;key&lt;/FONT&gt;, &lt;FONT face="courier new,courier"&gt;partition&lt;/FONT&gt;, &lt;FONT face="courier new,courier"&gt;offset&lt;/FONT&gt;, and &lt;FONT face="courier new,courier"&gt;timestamp&lt;/FONT&gt; are retained in this table to maintain traceability from the raw Kafka data.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;# Bronze deserialized streaming table
@dlt.table(
 name="bronze_fleet_events",
 comment="bronze (deserialized) table that handles the deserialization of the protobuf using the from_protobuf function"
)
def bronze_fleet_events():
   return (
       dlt.read_stream("bronze_fleet_events_raw")
         .select("key","partition","offset","timestamp", # metadata fields
           from_protobuf("value", options = schema_registry_options).alias("batch_message")) #payload
         .select("key","partition","offset","timestamp",
           explode("batch_message.*").alias("event"))\
         .selectExpr(
           "event.vehicle_id",
           "event.timestamp as event_timestamp",
           "event.latitude",
           "event.longitude",
           "event.speed",
           "event.fuel_level",
           "event.engine_status",
           "key","partition","offset","timestamp"
       )
   )
&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sample result:&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;bronze_fleet_events &lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;contains the &lt;/SPAN&gt;&lt;SPAN&gt;deserialized data&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bronze_fleet_events.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11419i1784F98A8ACF4133/image-size/large?v=v2&amp;amp;px=999" role="button" title="bronze_fleet_events.png" alt="bronze_fleet_events.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;from_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; function by default uses &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;FAILFAST&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; parsing mode, which will immediately halt the pipeline and raise an error if any malformed records are encountered during the deserialization process.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN&gt;Refer to the Databricks &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/structured-streaming/protocol-buffers.html#supported-options-in-protobuf-functions" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;documentation&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; for more details.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Native Databricks Protobuf Functions&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P data-unlink="true"&gt;&lt;SPAN&gt;To use the &lt;A href="https://docs.databricks.com/en/structured-streaming/protocol-buffers.html#how-to-deserialize-and-serialize-protocol-buffers" target="_blank" rel="noopener"&gt;Protobuf functions&lt;/A&gt;&lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;&amp;nbsp;from_protobuf&amp;nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;and &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;to_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;, you must provide either a schema registry via the &lt;/SPAN&gt;&lt;SPAN&gt;options&lt;/SPAN&gt;&lt;SPAN&gt; argument or a descriptor file identified by the &lt;/SPAN&gt;&lt;SPAN&gt;descFilePath&lt;/SPAN&gt;&lt;SPAN&gt; argument.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;from_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;to_protobuf&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; functions are &lt;/SPAN&gt;available on Databricks Runtime 12.2 LTS and above. &lt;SPAN&gt;The basic syntax for these functions is as follows:&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;#Casts binary column to a struct
from_protobuf( data: 'ColumnOrName'
, messageName: Optional[str] = None
, descFilePath: Optional[str] = None
, options: Optional[Dict[str, str]] = None
)

#Casts a struct back to a binary
to_protobuf(	  data: 'ColumnOrName'
, messageName: Optional[str] = None
, descFilePath: Optional[str] = None
, options: Optional[Dict[str, str]] = None
)
&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;It is considered best practice to use a &lt;/SPAN&gt;&lt;A href="https://docs.confluent.io/platform/current/schema-registry/index.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Schema Registry&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; as it ensures centralized management and versioning of schemas. This provides a robust mechanism for maintaining consistency and compatibility across producers and consumers in the data pipeline. The functions simplify the serialization and deserialization processes by leveraging schema stored in the schema registry, eliminating the need to write the custom serialization and deserialization logic manually.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Sensitive information, such as credentials for Kafka brokers and the Schema Registry, can be securely managed using Databricks &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/security/secrets/secrets.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Secrets&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H1&gt;&amp;nbsp;&lt;/H1&gt;
&lt;H1&gt;&lt;SPAN&gt;Cleansing for Data Integrity in Silver Layer&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;silver_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; table handles event replays from edge devices and ensures data integrity by storing the latest event data using an SCD Type-1 approach. SCD Type-1 is used here to store only the latest version of events, ensuring that any replayed or previously sent events from edge devices are correctly updated in the table. The &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/delta-live-tables/cdc.html" target="_blank" rel="noopener"&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;apply_changes&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;SPAN&gt; function in the DLT pipeline simplifies the change data capture (CDC) process. This function requires specifying the source, target, keys, sequencing for the change feed, and SCD-Type.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Since edge devices can transmit previously sent events into the Kafka topic again, the Silver table &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;silver_fleet_events&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; is configured as an SCD type-1 table using the apply_changes function. When a previously sent event is ingested again into the DLT pipeline, the corresponding entry in the Silver table gets updated. This table excludes Kafka-specific metadata columns (&lt;FONT face="courier new,courier"&gt;key&lt;/FONT&gt;, &lt;FONT face="courier new,courier"&gt;partition&lt;/FONT&gt;, &lt;FONT face="courier new,courier"&gt;offset&lt;/FONT&gt;, and &lt;FONT face="courier new,courier"&gt;timestamp&lt;/FONT&gt;) and focuses on business-relevant event data for further processing.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;# Silver streaming table
dlt.create_target_table(
   name = "silver_fleet_events",
   comment = "Silver table (SCD type-1) that handles event replays from edge devices to ensure data integrity"
)


dlt.apply_changes(
   target = "silver_fleet_events",
   source = "bronze_fleet_events",
   keys = ["vehicle_id","event_timestamp"],
   except_column_list = ["key","partition","offset","timestamp"],
   sequence_by = col("event_timestamp"),
   stored_as_scd_type = 1
)
&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sample result:&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;silver_fleet_events &lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt;is an SCD Type-1 table that ensures only the latest fleet telemetry events are stored.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="silver_fleet_events.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11422iA7B0181574603BDB/image-size/large?v=v2&amp;amp;px=999" role="button" title="silver_fleet_events.png" alt="silver_fleet_events.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H1&gt;&amp;nbsp;&lt;/H1&gt;
&lt;H1&gt;&lt;SPAN&gt;Aggregating Insights in Gold Layer&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;Lastly, the Silver table is used to populate two Gold summary materialized views, all within the same DLT pipeline.&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;gold_fuel_efficiency&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; computes fuel efficiency as the distance traveled per unit of fuel consumed by the vehicle. The function&lt;/SPAN&gt; &lt;SPAN&gt;fuel_efficiency_summary&lt;/SPAN&gt;&lt;SPAN&gt; contains the view's aggregation logic.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;FONT face="courier new,courier"&gt;&lt;SPAN&gt;gold_vehicle_utilization&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN&gt; calculates the utilization rate of each vehicle by measuring how long the vehicle has been active based on its speed. The function &lt;/SPAN&gt;&lt;SPAN&gt;vehicle_utilisation_summary&lt;/SPAN&gt;&lt;SPAN&gt; contains the aggregation logic that underpins this view.&amp;nbsp;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;TABLE border="1" width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width="100%" style="border-style: hidden; width: 100%;"&gt;&lt;LI-CODE lang="python"&gt;# Gold materialized views
@dlt.table(
 name="gold_fuel_efficiency",
 comment="calculates fuel efficiency (distance per unit of fuel)"
)
def fuel_efficiency_summary():
 return (
   dlt.read("silver_fleet_events")
      .withColumn("prev_fuel_level", lag("fuel_level").over(window_spec))
      .withColumn("fuel_consumed", (col("prev_fuel_level") - col("fuel_level")).cast("double"))
      .withColumn("prev_latitude", lag("latitude").over(window_spec))
      .withColumn("prev_longitude", lag("longitude").over(window_spec))
      .withColumn("distance_traveled", when(col("prev_latitude").isNotNull(),((col("latitude") - col("prev_latitude"))**2 +(col("longitude") - col("prev_longitude"))**2)**0.5).otherwise(0))
      .filter(col("fuel_consumed") &amp;gt; 0)
      .groupBy("vehicle_id").agg(
         round(sum("distance_traveled"),2).alias("total_distance_traveled"),
         round(sum("fuel_consumed"),2).alias("total_fuel_consumed")
      ).withColumn("fuel_efficiency",round(col("total_distance_traveled") / col("total_fuel_consumed"),2))
 )


@dlt.table(
 name="gold_vehicle_utilization",
 comment="calculates the vehicle utilization rate"
 )
def vehicle_utilisation_summary():
 return (
   dlt.read("silver_fleet_events")
      .withColumn("is_active", col("speed") &amp;gt; 0)
      .groupBy("vehicle_id").agg(
       sum(when(col("is_active"), col("event_timestamp")).otherwise(0)).alias("total_active_time"),
       sum(col("event_timestamp")).alias("total_time")
      ).withColumn("utilization_rate", (col("total_active_time") / col("total_time")) * 100)
 )&lt;/LI-CODE&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;DIV id="tinyMceEditorsrikanthkilari_6" class="mceNonEditable lia-copypaste-placeholder"&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;Sample results:&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;&lt;FONT face="courier new,courier"&gt;gold_fuel_efficiency&lt;/FONT&gt;: Aggregates total distance traveled vs. fuel consumption.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;&lt;FONT face="courier new,courier"&gt;gold_vehicle_utilization&lt;/FONT&gt;: Calculates vehicle utilization rates across time.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="gold materialized views.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/11424iD7ED88EA3CF1BD81/image-size/large?v=v2&amp;amp;px=999" role="button" title="gold materialized views.png" alt="gold materialized views.png" /&gt;&lt;/span&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&amp;nbsp;&lt;/H2&gt;
&lt;H1&gt;&lt;SPAN&gt;Conclusion&lt;/SPAN&gt;&lt;/H1&gt;
&lt;P&gt;&lt;SPAN&gt;Protobuf deserialization is a crucial step in processing high-volume, real-time data streams, especially when dealing with consolidated messages from edge devices. By leveraging the native from_protobuf function within a Serverless DLT pipeline, data engineering teams can simplify the deserialization process, reduce infrastructure overhead, improve deserialization performance, and minimize maintenance efforts.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The Serverless nature of DLT further enhances this approach by eliminating the need for infrastructure management, allowing teams to focus solely on data processing and analytics. This streamlines the ingestion and processing of complex Protobuf messages and ensures that your data pipelines are scalable, cost-efficient, and easy to manage. Using declarative syntax in DLT, you can configure SCD Type 1 and 2 and other ETL needs (such as &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/delta-live-tables/expectations.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Data Quality Expectations&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;) to build highly efficient ETL pipelines that support real-time analytics and decision-making.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;As streaming data continues to play a pivotal role across industries, adopting best practices like these in your ETL pipelines will be essential for maintaining a competitive edge and optimizing operational efficiency. Following the steps outlined in this blog, you can confidently implement Protobuf deserialization in your Serverless Databricks DLT pipelines, ensuring that your streaming applications are optimized for performance, scalability, and accuracy.&lt;/SPAN&gt;&lt;/P&gt;</description>
    <pubDate>Wed, 25 Sep 2024 12:47:50 GMT</pubDate>
    <dc:creator>srikanth-kilari</dc:creator>
    <dc:date>2024-09-25T12:47:50Z</dc:date>
    <item>
      <title>Real-time Vehicle Fleet Analytics with Databricks Delta Live Tables</title>
      <link>https://community.databricks.com/t5/technical-blog/real-time-vehicle-fleet-analytics-with-databricks-delta-live/ba-p/91422</link>
      <description>&lt;P&gt;Unlock real-time insights into vehicle fleet management with Databricks Delta Live Tables (DLT). This blog explores how a logistics provider leverages Databricks native functionality for Protobuf deserialization with a serverless DLT pipeline to optimize fleet performance. Discover how scalable, automated data pipelines utilize these capabilities to transform real-time telemetry data into actionable insights, improving fuel efficiency and vehicle utilization.&lt;/P&gt;</description>
      <pubDate>Wed, 25 Sep 2024 12:47:50 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/real-time-vehicle-fleet-analytics-with-databricks-delta-live/ba-p/91422</guid>
      <dc:creator>srikanth-kilari</dc:creator>
      <dc:date>2024-09-25T12:47:50Z</dc:date>
    </item>
  </channel>
</rss>

