YouTube2Text

End-to-End Azure Data Engineering Project | Build a Complete Data Pipeline from Scratch — Transcript

by Tech with Amol · 14,259 words · 2,462 segments · language en · Watch on YouTube

Full transcript

  1. 0:00Hello everyone, welcome to the channel.
  2. 0:03If you are learning a data engineering,
  3. 0:05you have probably come across uh
  4. 0:06technologies like Azure Data Factory,
  5. 0:09Azure Data Bricks, PySpark, Azure Data
  6. 0:11Lake Storage, etc. But knowing these
  7. 0:14technologies individually is one thing,
  8. 0:17and understanding how they work together
  9. 0:19to solve a real business problem is what
  10. 0:21actually matters when you work as a data
  11. 0:24engineer.
  12. 0:25The Think about a company that uh sells
  13. 0:28electronic products across a multiple
  14. 0:30stores. Everyday company generates uh
  15. 0:32data from different business operations.
  16. 0:35Customer purchase the product, stores
  17. 0:37process sales transaction, new products
  18. 0:39are launched, and customers raises
  19. 0:41warranty claims. Now, imagine all this
  20. 0:44information stored across the different
  21. 0:46files, datasets, applications. The
  22. 0:49business want uh wants a answer to a
  23. 0:51questions like how much revenue are we
  24. 0:54generating, which products are selling
  25. 0:56most, which stores are performing
  26. 0:58better, which products are receiving the
  27. 1:00most warranty claims. The problem is
  28. 1:03that this data isn't always available in
  29. 1:06one place. It may contain duplicates
  30. 1:08records, missing value, inconsistent
  31. 1:11column names, incorrect data types, and
  32. 1:13or many other data issues. And before
  33. 1:17anyone can use this data for analysis,
  34. 1:19someone needs to bring these together,
  35. 1:21clean it, transform it, and make it
  36. 1:23reliable. That's where data engineer
  37. 1:26comes in. A data engineer builds and
  38. 1:29maintain the pipeline that moves data
  39. 1:31from a source system into a centralized
  40. 1:33platform, transform it into a usable
  41. 1:36format, and make it available for a
  42. 1:38downstream application and analytics.
  43. 1:41And that's exactly what we are going to
  44. 1:43build in this video. We are going to
  45. 1:45create a practical data engineering
  46. 1:47pipeline using uh Azure Data Factory,
  47. 1:49Azure Data Lake Storage Gen2, and Azure
  48. 1:52Data Bricks and PySpark. We will work
  49. 1:55with a five datasets, categories,
  50. 1:58products, sales, stores, and warranty.
  51. 2:00These data sets are available in my
  52. 2:03GitHub link.
  53. 2:05I have attached that link in my comment
  54. 2:07section. So, don't worry about that.
  55. 2:10This is just about a learning individual
  56. 2:13Azure services. It's about understanding
  57. 2:16the responsibility of a data engineer
  58. 2:18and how to implement a complete
  59. 2:20ingestion and transformation workflow.
  60. 2:23Now, if you are preparing for data
  61. 2:25engineering role, this project will help
  62. 2:27you to understand several concepts that
  63. 2:29commonly come up during the technical
  64. 2:31interviews. For example, how do you
  65. 2:34design end-to-end data pipeline in
  66. 2:36Azure? How do you ingest a multiple
  67. 2:39files dynamically using Azure Data
  68. 2:41Factory? What is the difference between
  69. 2:43bronze, silver, and gold layer? How do
  70. 2:46you connect Azure Data Bricks to Azure
  71. 2:48Data Lake Storage securely? How do you
  72. 2:51handle duplicates, null values, or any
  73. 2:53other transformation questions? These
  74. 2:56are not just a theoretical questions,
  75. 2:58truly data engineering interview
  76. 3:00questions. Throughout this tutorial, we
  77. 3:02will be implementing these concepts
  78. 3:04step-by-step. So, whether you are
  79. 3:06beginner learning Azure Data Engineering
  80. 3:09or developer transitioning into a data
  81. 3:11engineering or someone preparing for
  82. 3:13technical interviews, this project will
  83. 3:16give you a practical foundation. And
  84. 3:18more importantly, you will have a
  85. 3:20working project that you can practice
  86. 3:23explaining during the interviews. Now,
  87. 3:25before we start implementing anything,
  88. 3:27let's understand the business scenario
  89. 3:30and overall architecture. Let's imagine
  90. 3:33we are working as a data engineer for a
  91. 3:34retail company that sells electronic
  92. 3:37products across different location. The
  93. 3:39company has a several business system
  94. 3:41generating data every day. For this
  95. 3:44project, we are working with a five data
  96. 3:46set. The category data set contains
  97. 3:48information about the product
  98. 3:50categories. The product data set, which
  99. 3:52gives us the details about the product.
  100. 3:55A sales data set contains the
  101. 3:56transactional information. Then a stores
  102. 3:59data set contains the information about
  103. 4:01the company stores. And finally, we have
  104. 4:04a warranty data set that contains the
  105. 4:06information about the warranty claims
  106. 4:08and repair status. Now, imagine the
  107. 4:10company wants to analyze its sales
  108. 4:13performance. The analytics team needs a
  109. 4:15reliable data to understand revenue,
  110. 4:17product performance, and store
  111. 4:19performance. But before that analysis
  112. 4:21can happen, we need to collect all these
  113. 4:24data source, store it centrally, and
  114. 4:26apply the necessary transformation.
  115. 4:28That's That's where your responsibility
  116. 4:31come in the picture as a data engineer.
  117. 4:34Let's see how we will achieve this using
  118. 4:36a Azure. The first component in our
  119. 4:38architecture is Azure Data Factory. In a
  120. 4:41real company, data might come from SQL
  121. 4:43database, ERP system, APIs, cloud
  122. 4:46application, files, etc. For this
  123. 4:49project, we are using a CSV file to
  124. 4:51represent those source system. Our first
  125. 4:54responsibility is to move this data into
  126. 4:56a cloud storage environment. And that's
  127. 4:59where Azure Data Factory comes in. Data
  128. 5:02Factory is a data ingestion and
  129. 5:04orchestration service that allows us to
  130. 5:06build pipelines for moving and
  131. 5:08processing data. Now, one approach would
  132. 5:10be to create a separate pipeline for
  133. 5:13each data set. But imagine working in a
  134. 5:15company with a 50 to 100 different
  135. 5:18source file, creating and maintaining a
  136. 5:20separate pipeline for every file would
  137. 5:23quickly become difficult. So, instead of
  138. 5:25we are going to build a dynamic reusable
  139. 5:28ingestion pipeline. We will use a
  140. 5:30lookup, for each, and copy data
  141. 5:33activities. This is an important concept
  142. 5:35because data engineers frequently need
  143. 5:37to design pipelines that can handle
  144. 5:39multiple data sets without duplicating
  145. 5:42the same logic. By the end of this
  146. 5:44section, you will understand how these
  147. 5:46activities work together to automate
  148. 5:49data ingestion.
  149. 5:50Once our data is ingested, we need to
  150. 5:53somewhere to store
  151. 5:54it. For that, we are using Azure Data
  152. 5:57Lake Storage Gen2. Think of it as a
  153. 6:00centralized storage location for our
  154. 6:02data platform. Instead of keep keeping
  155. 6:05information scattered across a different
  156. 6:08system, we will bring it into a common
  157. 6:10storage environment. Now, one important
  158. 6:12concept in modern data engineering is a
  159. 6:15Medallion architecture. In this
  160. 6:16architecture, data is organized into a
  161. 6:19different layer based on how much
  162. 6:21processing it has undergone. The three
  163. 6:24commonly used layers are bronze, silver,
  164. 6:26and gold. The bronze layer is where we
  165. 6:29store our raw data received from our
  166. 6:31source system. We are preserving the
  167. 6:33original source data so that we have a
  168. 6:36starting point for the further
  169. 6:37processing. This is very important
  170. 6:40because if something goes wrong during
  171. 6:42the transformation, we can return to our
  172. 6:44raw data and process it again. Next, we
  173. 6:47have a silver layer. This is where
  174. 6:49actual data cleaning and transformation
  175. 6:51happens. Once the transformation are
  176. 6:53completed, we will save this processed
  177. 6:55data set into a silver layer using a
  178. 6:58parquet files. This is one of the core
  179. 7:00responsibility of data engineer making
  180. 7:02sure that the data structure consistent
  181. 7:05and suitable for the downstream use. And
  182. 7:08the last layer is a gold layer. The gold
  183. 7:10layer contains curated data set designed
  184. 7:12around the business requirements. All
  185. 7:15these layer have a different different
  186. 7:18permissions, so
  187. 7:19not everyone and each person of your
  188. 7:22company will access all these data.
  189. 7:25Specific sets of people only can access
  190. 7:27the bronze layer, gold layer, and a
  191. 7:29silver layer. That is a main purpose of
  192. 7:32these three different layer.
  193. 7:35Now, let's talk about the processing
  194. 7:36component of our architecture. We have
  195. 7:39ingested our raw files into a bronze
  196. 7:41layer, but how do we actually clean
  197. 7:44transform the data? That's where
  198. 7:46Databricks comes in. Databricks is an
  199. 7:48Apache Spark-based data processing
  200. 7:51platform. It allows us to process data
  201. 7:53using a
  202. 7:54Python or SQL or PySpark. In this
  203. 7:57process, we will be using a PySpark. We
  204. 8:00will create our Databricks workspace and
  205. 8:02configure the required compute resource.
  206. 8:05Then we will establish access to our
  207. 8:07Azure Data Lake Storage using the
  208. 8:09application register in Microsoft Entra
  209. 8:12ID. Once the connection is configured,
  210. 8:15we will read our bronze data set into a
  211. 8:17Spark data frame. Then we will do some
  212. 8:20transformation and we will write this
  213. 8:22transform data back into our silver
  214. 8:24layer using a parquet format. Parquet is
  215. 8:27particularly useful for analytics
  216. 8:29workload because it supports columnar
  217. 8:31storage and efficient compression. So,
  218. 8:34the overall flow is straightforward.
  219. 8:37Azure Data Factory handles the ingestion
  220. 8:39and orchestration. Azure Data Lake
  221. 8:41Storage stores our data set and Azure
  222. 8:44Databricks perform the transformation.
  223. 8:47These are the core components of the
  224. 8:48pipelines we are going to build.
  225. 8:51Now, there's one more thing that I want
  226. 8:53you to understand before we start. When
  227. 8:55you attend a data engineering interview,
  228. 8:58the interviewer may ask, "Can you
  229. 8:59explain me end-to-end pipeline you have
  230. 9:02worked on?"
  231. 9:03A strong answer isn't simply listing the
  232. 9:06technology you have used. You need to
  233. 9:08explain the business problem, how the
  234. 9:10data was ingested, where it was stored,
  235. 9:13how the transformation applied, and how
  236. 9:16the processed data made available to
  237. 9:18different teams. And that's exactly the
  238. 9:21approach we are going to follow in this
  239. 9:23project. By the time you complete this
  240. 9:25tutorial, you will be able to explain
  241. 9:27how a retail data pipeline can be
  242. 9:29designed using Azure services. You will
  243. 9:32understand why we use a dynamic
  244. 9:35pipeline,
  245. 9:36why we separate raw and transform data,
  246. 9:39how we use a PySpark transformation, and
  247. 9:41why we choose a format such as parquet.
  248. 9:44You will also be able to discuss some of
  249. 9:46the
  250. 9:47design decisions and trade-off involved.
  251. 9:50The goal is not to just a memorize
  252. 9:53interview answers, but to understand the
  253. 9:55implementation well enough to explain
  254. 9:57confidently. So, that's the business
  255. 9:59problem we are trying to solve
  256. 10:02and the architecture we are going to
  257. 10:04implement. We will start by creating
  258. 10:06required Azure resources. Don't worry
  259. 10:08about that. I will be explaining each
  260. 10:11and every concept and every resources
  261. 10:15and how to create it, what process we
  262. 10:17need to follow, everything you will
  263. 10:19learn in this project. So, don't worry
  264. 10:21about that. So, let's get started and
  265. 10:23build our Azure data engineering
  266. 10:25pipeline.
  267. 10:28Let's start working with Azure. We are
  268. 10:31now inside the Azure portal. As you can
  269. 10:34see, there is a create a resource plus
  270. 10:36button here. I know you might be excited
  271. 10:39to click on it immediately, but before
  272. 10:41creating any resource, there is one more
  273. 10:44important step we need to complete
  274. 10:46first.
  275. 10:47We need to create a resource group. A
  276. 10:50resource group is extremely important
  277. 10:52because it act as a logical container
  278. 10:54where all your Azure resources will be
  279. 10:57live.
  280. 10:58Think of it as a folder where you are
  281. 11:00placing everything in your project. So,
  282. 11:03how do we create Azure resource group?
  283. 11:07If the resource group option is not
  284. 11:10directly visible on your screen, don't
  285. 11:12worry. Azure only shows recently used
  286. 11:15services here. Simply use the search bar
  287. 11:18at the top of the portal. This search
  288. 11:21bar helps you navigate the existing
  289. 11:23resource and also create new ones.
  290. 11:28Type resource group in the search bar
  291. 11:31and click on it. Here you will see all
  292. 11:33existing resource group. Don't worry if
  293. 11:36you see many already created. I already
  294. 11:39have some in my accounts.
  295. 11:41For this project, we will be creating a
  296. 11:44new one.
  297. 11:45Click on a create button. This opens the
  298. 11:48configuration screen for creating the
  299. 11:50resource. The configuration is very
  300. 11:54simple. First, we need to provide a name
  301. 11:57for our resource group. This name should
  302. 11:59be a something meaningful and unique.
  303. 12:02Next, you will see the subscription. You
  304. 12:05don't need to worry about this as of
  305. 12:08now. In most cases, you will have only
  306. 12:10one subscription.
  307. 12:14Let's give the resource group a name.
  308. 12:17Let's think of something unique. I will
  309. 12:19give it
  310. 12:21a short project.
  311. 12:23Azure will check whether the name is
  312. 12:26available or not.
  313. 12:28Now comes the region selection. This is
  314. 12:31a very important concept. It's always
  315. 12:34recommended to choose a region closest
  316. 12:36to you to achieve a lower latency.
  317. 12:39Since this project is not highly
  318. 12:41critical, you can choose any region.
  319. 12:44I will select East US as it works
  320. 12:47perfectly fine.
  321. 12:49Click on next to move on the tax
  322. 12:52section.
  323. 12:53Tax are used to categorize resources,
  324. 12:56usually for billing or organization
  325. 12:59purpose. For now, we can skip this
  326. 13:02section.
  327. 13:03Click on review plus create button.
  328. 13:06Azure will validate the configuration.
  329. 13:09Once validation is successful, then
  330. 13:11click on create button.
  331. 13:13Within a few seconds, the resource group
  332. 13:16will be created.
  333. 13:18Now click on the resource group to open
  334. 13:21it.
  335. 13:22As you can see, it's currently empty
  336. 13:24because we haven't added any resources
  337. 13:27yet.
  338. 13:29There are two way to create a resources.
  339. 13:32One way is to use to the create button
  340. 13:35inside the resource group,
  341. 13:37which is automatically associated
  342. 13:40new resources with this group. The
  343. 13:43second way is to create a resources from
  344. 13:45the Azure home page.
  345. 13:49Let's go back to the our Azure home tab.
  346. 13:54Uh now comes an important question. What
  347. 13:57should be the first resource we create
  348. 14:00for the data engineering project?
  349. 14:03Yes, you get guess it right. We start
  350. 14:05with a data lake.
  351. 14:09In Azure, data lake is created using a
  352. 14:12storage account. So, search for a
  353. 14:15storage account in the search bar and
  354. 14:17click on it.
  355. 14:19In Azure, data lake is created using a
  356. 14:23storage account. You will see the
  357. 14:25existing storage account if you already
  358. 14:28have some.
  359. 14:29Don't worry about those. Click on
  360. 14:31create.
  361. 14:33During the creation, Azure automatically
  362. 14:35select our resource group.
  363. 14:39If your resource group didn't exist, you
  364. 14:43could also create one from here. But,
  365. 14:46it's always best practice to create
  366. 14:49it beforehand.
  367. 14:51Uh now provide a unique name for our
  368. 14:54storage account. Storage account name
  369. 14:56must be globally unique. So,
  370. 14:59feel free add your name or suffix if
  371. 15:03needed.
  372. 15:06I will add Azure data lake 90.
  373. 15:10Uh next, keep the performance as
  374. 15:14standard.
  375. 15:22Now comes an inter inter- important
  376. 15:26interview related topic. That is
  377. 15:28redundancy.
  378. 15:30By default Azure select geo-redundant
  379. 15:33storage, which replicates the data
  380. 15:35across different region.
  381. 15:38For this project, we don't need a
  382. 15:40geo-replication.
  383. 15:41So, we will select locally redundant
  384. 15:44storage, which keeps the data replicates
  385. 15:47within the same data center.
  386. 15:50Now, here's very important question. By
  387. 15:53default, a storage account creates a
  388. 15:55blob storage, not a data lake.
  389. 15:58So, how do we enable data lake
  390. 16:00functionality?
  391. 16:02The answer is very simple. We need
  392. 16:05enable hierarchical namespace.
  393. 16:08This small checkbox is the key
  394. 16:11difference.
  395. 16:12When hierar-
  396. 16:13hierarchical namespace is enabled, the
  397. 16:16storage account become a data lake.
  398. 16:19Without it, you only get a blob storage.
  399. 16:23Now, let's understand why this matters.
  400. 16:27In blob storage, you can create
  401. 16:29containers and store files, but you
  402. 16:31cannot create folders hierarchies.
  403. 16:34In data lake, you can create folders
  404. 16:36within folders just like a file system.
  405. 16:39This hierarchical structure is extremely
  406. 16:42important when working with analytic
  407. 16:44analytics tables and large-scale data
  408. 16:46processing. If you are working with
  409. 16:49analytical data, you should always use a
  410. 16:51data lake. Now, let's move on to the
  411. 16:54access tiers. Hot tier is used when data
  412. 16:58is accessed frequently.
  413. 17:01Cool tier is used less frequent access
  414. 17:03at lower cost.
  415. 17:05Cold
  416. 17:06Cold tier tier is used for archival
  417. 17:09purpose
  418. 17:11with minimum storage, but the higher
  419. 17:14access cost. Since we will be frequently
  420. 17:18accessing our data, we will keep our
  421. 17:20tier as a hot.
  422. 17:22Now, review the configuration and click
  423. 17:24on the review plus create button. Once
  424. 17:27validation is complete, click on the
  425. 17:29create button.
  426. 17:31Azure will take few seconds to create
  427. 17:33the data lake. Once it's ready, we can
  428. 17:36see the resources is successfully
  429. 17:38created. Now, the next step is to create
  430. 17:41the Azure Data Factory. Search for Azure
  431. 17:44Data Factory in our search bar and click
  432. 17:46on it. If you don't see any existing
  433. 17:49data factories, that's perfectly fine.
  434. 17:52Click on the create button, select the
  435. 17:54name resource group because all the
  436. 17:56resources should be belong to one
  437. 17:58project. Give your data factory unique
  438. 18:01name. Again, name must be globally
  439. 18:03unique, so adjust accordingly.
  440. 18:05Once done, click on the review plus
  441. 18:08create button and then create.
  442. 18:11Azure Data Factory will deploy in a few
  443. 18:14seconds. Now, our core resources for
  444. 18:17phase one are ready.
  445. 18:20We have the resource group, data lake,
  446. 18:23and Azure Data Factory in place.
  447. 18:26Now, let's move on into Azure Data
  448. 18:28Factory.
  449. 18:30Our goal is
  450. 18:32In this phase, we will create a bronze,
  451. 18:34silver, and gold zones and start
  452. 18:36building the ingestion pipeline using
  453. 18:38Azure Data Factory.
  454. 18:40First, click on the launch studio. This
  455. 18:42will open the Azure Data Factory studio.
  456. 18:45If you are new to Azure Data Factory,
  457. 18:47you will love the UI. It's a clean,
  458. 18:50intuitive, and designed specifically for
  459. 18:53building the data pipelines.
  460. 18:55This is the home page of Azure Data
  461. 18:58Factory. For now, don't worry about the
  462. 19:01GitHub integration. We will cover that
  463. 19:03later.
  464. 19:04Let me quickly walk through walk you
  465. 19:07through the main tabs.
  466. 19:10The author tab
  467. 19:12is most important one. This is where we
  468. 19:15we will create the pipelines, dataset,
  469. 19:18link services, activities, and
  470. 19:20notebooks. Most of our work will happen
  471. 19:24there.
  472. 19:25Next, in the monitor monitor tab, this
  473. 19:28is where we track the pipeline education
  474. 19:31execution, sorry.
  475. 19:34Monitor failure and debug issues. Think
  476. 19:37of it as a control center for all your
  477. 19:40pipelines.
  478. 19:41Then we have a manage tab. This is where
  479. 19:45we configure the link services, GitHub
  480. 19:48or Azure DevOps repositories,
  481. 19:50integration runtimes, and global
  482. 19:52parameters. Finally, we have the
  483. 19:55learning center where you can explore
  484. 19:58the documentation, sample dataset, and
  485. 20:00learning resources.
  486. 20:02Now that you understand the UI, let's
  487. 20:05prepare our storage zone. We will we
  488. 20:08have to create three containers in a
  489. 20:11data lake. One is bronze, another
  490. 20:13silver, and another one is gold. Now
  491. 20:16let's go back to our Azure portal. Open
  492. 20:19your storage account and click on the
  493. 20:21containers. Create a new container named
  494. 20:24bronze. Repeat the same steps for the
  495. 20:27silver and gold containers.
  496. 20:29These containers represents different
  497. 20:31stages of the data processing and follow
  498. 20:34the Mendelian architecture pattern
  499. 20:35commonly used in a real world data
  500. 20:37engineering projects.
  501. 20:39Now that our zones are ready, it's time
  502. 20:43to start loading data using the Azure
  503. 20:45Data Factory. Let's go back to our data
  504. 20:49our Azure Data Factory Studio. To create
  505. 20:52the pipeline, click on the pipelines,
  506. 20:54then click on the three dots, and select
  507. 20:56the new pipeline.
  508. 20:58This will open our pipeline canvas.
  509. 21:02First, give your pipeline a meaningful
  510. 21:04name. Here I'm giving Git to raw.
  511. 21:08Now, let's add our first activity.
  512. 21:11From the move and transform section,
  513. 21:14drag a drag the copy
  514. 21:16copy data activity into your canvas.
  515. 21:19Rename the activity to copy
  516. 21:24copy raw data.
  517. 21:26Uh
  518. 21:27A copy activity always requires a source
  519. 21:30and sync. In our case, the source is
  520. 21:33GitHub repository and the sync is Azure
  521. 21:36Data Lake Gen2.
  522. 21:38To connect to GitHub, we need a linked
  523. 21:41service.
  524. 21:42A linked service is simply a connection
  525. 21:45Azure Data Factory uses linked service
  526. 21:47to connect to external systems like
  527. 21:49GitHub API, storage accounts.
  528. 21:53Before building a data set or pipeline,
  529. 21:55it's always a best practice to create a
  530. 21:57linked services first.
  531. 22:00Now, go to the manage tab. There you can
  532. 22:03see the linked services option.
  533. 22:05In that, just
  534. 22:07click on the new and on the right side
  535. 22:09of the panel, you will see the lot of
  536. 22:12linked services are already are there.
  537. 22:16Uh we are using a GitHub data, so we
  538. 22:19need a HTTP
  539. 22:21URL.
  540. 22:23And for that, we need quiet a HTTP
  541. 22:26your linked services. Here you can see
  542. 22:29the my GitHub data and on that, you have
  543. 22:32to click on the raw data. In the raw
  544. 22:35data, you will find the
  545. 22:37HTTP link. Now, search the HTTP.
  546. 22:41Uh click on that and on that, you will
  547. 22:45get a configurational option.
  548. 22:48Now, in the name tab, just
  549. 22:52uh type a HTTP linked service.
  550. 22:55On the base URL,
  551. 22:57uh paste the
  552. 22:59link you have copied from the GitHub.
  553. 23:02Uh here you can see the that link. Just
  554. 23:07till the github.com,
  555. 23:10just paste that.
  556. 23:13In authentication, select anonymous as a
  557. 23:16authentication type.
  558. 23:18And then click on the test connection to
  559. 23:21verify the connectivity.
  560. 23:23Once the test succeed, click click on
  561. 23:26the create button.
  562. 23:29Now, let's create another linked service
  563. 23:31for our data lake.
  564. 23:33Click on new linked service, search for
  565. 23:36the Azure Data Lake Storage Gen2, and
  566. 23:40select it.
  567. 23:42Uh give it a meaningful name, select
  568. 23:44your storage account, test the
  569. 23:46connection, and that's it. The and click
  570. 23:49the create button.
  571. 23:52Now, go back to our author tab and
  572. 23:55select the copy activity.
  573. 23:57In that, you have to select we have to
  574. 24:00create a source and sync now.
  575. 24:03In the source, just select the
  576. 24:06source format, where you will see that
  577. 24:09that we don't have anything. So, in
  578. 24:11that, just press click on the new
  579. 24:13button. In that, select the HTTP
  580. 24:16service.
  581. 24:17Once you select the HTTP service, we
  582. 24:20need to configure that.
  583. 24:23In that, now select the format as a CSV
  584. 24:26format because we have all of our data
  585. 24:28in a CSV. Just select the CSV.
  586. 24:32Now, in the name,
  587. 24:34just give DS2 uh
  588. 24:37HTTP.
  589. 24:38In the
  590. 24:40uh linked services, select our HTTP
  591. 24:44linked service, which we have created
  592. 24:46earlier.
  593. 24:47Now, we have to add the relative URL.
  594. 24:50So, real relative URL will be your
  595. 24:54dot next part of the dot com. So, go to
  596. 24:59the GitHub tab. In that,
  597. 25:02just select
  598. 25:04from name to the dot CSV till the dot
  599. 25:08CSV.
  600. 25:10Once you have selected that and pasted
  601. 25:12on into the relative tab, just click on
  602. 25:15the OK button.
  603. 25:17Okay?
  604. 25:18Now,
  605. 25:20here is the catch. If you want to see
  606. 25:22the data, how data is looking like, just
  607. 25:24click on the preview data. In that, you
  608. 25:27can see our data.
  609. 25:30Now, we will create the
  610. 25:32sync parameter.
  611. 25:34In the sync, just select we have the
  612. 25:38option of the DS HTTP, but don't select
  613. 25:41that because this is for the source one.
  614. 25:44We need to create a new one for the
  615. 25:46sync. And in the search menu, just
  616. 25:50select the
  617. 25:51Azure data Azure data lake storage gen
  618. 25:55two.
  619. 25:56Once you have selected that,
  620. 25:59then we need to
  621. 26:01select the format that again it will be
  622. 26:03stored as a CSV format. So,
  623. 26:06select the CSV.
  624. 26:08Then give a meaningful name. In that,
  625. 26:12we will write uh
  626. 26:14um
  627. 26:15uh something like
  628. 26:18DS raw, DS underscore raw. And in the
  629. 26:23linked services, we will write the
  630. 26:26storage data link.
  631. 26:28Now, we need to give the file path. So,
  632. 26:33here is the catch. We have to say that
  633. 26:36where we want to store. So, now this one
  634. 26:39is our raw data. So, we will be storing
  635. 26:41in the bronze folder. So,
  636. 26:44just select the bronze folder.
  637. 26:47Then
  638. 26:49in the another
  639. 26:51import schema, we have a three option,
  640. 26:54but we will say as none.
  641. 26:58Okay.
  642. 27:00Uh
  643. 27:01in the bronze, we are just giving a
  644. 27:04folder name as a category and then we
  645. 27:07are giving the file name as a
  646. 27:10category.csv
  647. 27:12because that file had the
  648. 27:14csv. uh
  649. 27:16Uh sorry, category.csv
  650. 27:19file name.
  651. 27:21Okay. Now in the import schema, we are
  652. 27:24selecting none. Once we have done that,
  653. 27:28just click on the okay button.
  654. 27:31Now our sync is
  655. 27:33placed.
  656. 27:35Okay. Now
  657. 27:37Uh
  658. 27:38okay. Now we have another tab that is
  659. 27:42mapping tab. So if you have already
  660. 27:45predefined mapping or we have anything
  661. 27:49already there, then we can do that. But
  662. 27:52in our case, we don't have any mapping,
  663. 27:54so just
  664. 27:56don't do anything in the mapping tab.
  665. 28:01Okay. Now
  666. 28:04moving to another
  667. 28:06part that is now let's debug our
  668. 28:10pipeline.
  669. 28:12Just play click the debug
  670. 28:15option.
  671. 28:17Now here you will see the all of our
  672. 28:20activities in the queue phase.
  673. 28:22Now we we are waiting for the green
  674. 28:26button or green indicator. So green will
  675. 28:29tell us that our activity is
  676. 28:32successfully executed.
  677. 28:34Just wait that.
  678. 28:37It will take couple of seconds because
  679. 28:40our data was very less. Yeah. So here
  680. 28:43you can see our activity is succeeded.
  681. 28:47Now we have to see the our data. So,
  682. 28:50let's go back to our
  683. 28:53Azure Data Lake
  684. 28:55storage account. In that just
  685. 28:59click on the bronze folder. In that you
  686. 29:01will see the category folder and in that
  687. 29:04you have a category.csv file. Just click
  688. 29:08on that. Here you will see the all the
  689. 29:10details about the file. If you want to
  690. 29:12see the file, then just click on the
  691. 29:14edit button. Don't change anything
  692. 29:17there.
  693. 29:18Okay, otherwise it will change our data.
  694. 29:21Just close it and again come back to our
  695. 29:26Azure
  696. 29:28Data Factory. Now click on the
  697. 29:31publish all so that it will save all of
  698. 29:34our changes all the workings.
  699. 29:37Once we have done that, now this was our
  700. 29:41static pipeline because we need to add
  701. 29:44the all the file name and everything was
  702. 29:47there. Now we we wanted to create a
  703. 29:49dynamic pipeline. So, how we will create
  704. 29:52the dynamic pipeline where it will take
  705. 29:54all the inputs from the file or all the
  706. 29:57file names. We don't have to add the
  707. 30:00file names manually. So, for that
  708. 30:03we will be doing the
  709. 30:06dynamic pipeline.
  710. 30:09Let's go back to our
  711. 30:11GitHub folder.
  712. 30:12So, there you can see we have
  713. 30:15around five files.
  714. 30:18We can see that we have
  715. 30:21product, then we have a category, sales,
  716. 30:25stores, and warranty data.
  717. 30:28So, for that we need to add the dynamic
  718. 30:30pipeline. So, we don't have to add the
  719. 30:32all the each file name and each folder
  720. 30:35name in our pipeline. So, how we will do
  721. 30:39that?
  722. 30:40Now coming back to our
  723. 30:44Azure Data Factory
  724. 30:47tab, there again from the trans move and
  725. 30:50transform, just select the copy
  726. 30:54copy data
  727. 30:56functionality. In that, now we will we
  728. 30:59have to give the unique name for that.
  729. 31:03Not unique, just give a meaningful name.
  730. 31:05So, for that we I'm giving a dynamic
  731. 31:08copy.
  732. 31:09Now, we need to create a source.
  733. 31:12Click on the new button. In that, search
  734. 31:15for HTTP and then select HTTP
  735. 31:19and then select the format as a CSV.
  736. 31:23Here, we will be giving name as a DS
  737. 31:25underscore dynamic and the linked
  738. 31:27services as a HTTP linked service.
  739. 31:31Now, we will here you can see that we
  740. 31:34have a different different files. Now,
  741. 31:37we we need to select the relative URL.
  742. 31:40So, the relative URL will be your
  743. 31:43github.com and your username.
  744. 31:46So, in the relative URL, but don't paste
  745. 31:50relative URL here.
  746. 31:53Click on the advance button.
  747. 31:57In that, select the open this data set.
  748. 32:01Once you have selected that, you will
  749. 32:03see we have a
  750. 32:05couple of options to configure.
  751. 32:07In the relative URL, if you click on
  752. 32:10that, you we will get the option of add
  753. 32:12dynamic content. We need to add the
  754. 32:15dynamic content.
  755. 32:17So, once you click that, you you will
  756. 32:19get a
  757. 32:20pipeline expression builder
  758. 32:22tab. In that, we need to create some
  759. 32:25parameters. If you
  760. 32:28search on something, you will not see
  761. 32:30anything. So, we will need to add the
  762. 32:33new parameter. In the new parameter,
  763. 32:36just
  764. 32:37uh write the name as a P underscore
  765. 32:40relative.
  766. 32:41Uh
  767. 32:42a relative URL, uh then default value
  768. 32:45none, and add okay. Now, select that P
  769. 32:49relative URL
  770. 32:51uh
  771. 32:51parameter. Once you selected that, it
  772. 32:54will appear at above text
  773. 32:57about above box.
  774. 33:00Once you selected that, just click on
  775. 33:02the okay button.
  776. 33:04Okay? Now, we have a relative URL
  777. 33:07parameters.
  778. 33:10Now, go back to our uh dynamic get to
  779. 33:13raw tab. In that in the source section,
  780. 33:17you will see that we have a P underscore
  781. 33:20relative underscore URL parameter. But,
  782. 33:23the value as a null as of now. So, don't
  783. 33:26worry about that. We will come back to
  784. 33:28that part later on.
  785. 33:30Now, move to the
  786. 33:33sync section. Just uh
  787. 33:36>> [clears throat]
  788. 33:36>> select sync. In that also, we need to
  789. 33:39create a new parameters.
  790. 33:41Uh click new, then
  791. 33:43uh Azure Data Lake Gen2, and then format
  792. 33:46as a CSV.
  793. 33:48Give
  794. 33:49name as a DS underscore uh
  795. 33:52uh dynamic
  796. 33:54uh
  797. 33:56raw. Then
  798. 33:58uh linked services, uh
  799. 34:01again, uh we need to select it as a
  800. 34:04storage Data Lake.
  801. 34:06Okay? Once you have selected that, you
  802. 34:09will see that we need to add the file
  803. 34:12path. But, uh we are creating
  804. 34:15uh we are storing all the data in our
  805. 34:17bronze layer, so we can select that as a
  806. 34:21bronze option.
  807. 34:23Um
  808. 34:24but uh we we are creating the uh dynamic
  809. 34:28parameters. So,
  810. 34:30uh go to advanced tab. In that, uh,
  811. 34:34advanced tab, you will see we have a,
  812. 34:37uh,
  813. 34:38new connection,
  814. 34:40uh, tab is there. We need to configure
  815. 34:42that. In the file path, add the, uh,
  816. 34:45bronze, uh,
  817. 34:46folder. [clears throat]
  818. 34:47And then,
  819. 34:49uh, in the directory part, uh, select
  820. 34:51the add dynamic content. In that, uh, we
  821. 34:54will create a new parameter. So, first
  822. 34:57one is p_sync_folder.
  823. 35:00Select that parameter, and that will
  824. 35:03appear in a dynamic,
  825. 35:04uh, folder parameter. Now, for the file,
  826. 35:08uh, name, uh, we will create a
  827. 35:09p_sync_file_name
  828. 35:12parameter, and that will
  829. 35:14appear under the, uh, file name, uh,
  830. 35:18uh, part.
  831. 35:19Okay? So, once you have created that,
  832. 35:22now we need to pass the values for those
  833. 35:25parameters. So, if we go back to the
  834. 35:28dynamic,
  835. 35:29uh, get to raw tab, there you will see
  836. 35:32that, uh, value as a null for both the
  837. 35:34parameter, p sync folder and p sync file
  838. 35:37name. So,
  839. 35:39how we will pass that, uh, values to
  840. 35:42our, uh, parameters?
  841. 35:44So, instead of hard coding values, we
  842. 35:47will pass them dynamically using the
  843. 35:49loop. So, drag a for each activity, and
  844. 35:53rename it as,
  845. 35:55uh, for each files.
  846. 35:57Uh, once we have done that, uh, for for
  847. 36:00for for each activities, uh, we required
  848. 36:04a array to iterate over.
  849. 36:06To provide this array, we will use the
  850. 36:08lookup activity.
  851. 36:10Now, we will creating a JSON file that
  852. 36:12contains a metadata for all files,
  853. 36:15including relative URL, target folder,
  854. 36:18and targeted file names.
  855. 36:20And then, we will upload those, uh,
  856. 36:24to our,
  857. 36:25uh, Azure Data Factory.
  858. 36:28Open any, uh, text editor.
  859. 36:31In the, uh, I'm opening, uh,
  860. 36:34PyCharm. In that, I'm creating a Git and
  861. 36:38a Git.
  862. 36:39json file.
  863. 36:40In that, uh, just, uh, create a one
  864. 36:45list. Inside the list, we need to create
  865. 36:47a multiple, uh, loops or multiple
  866. 36:50parameters. So, first I'm passing
  867. 36:53through the, uh, dictionary. So, in the
  868. 36:56dictionary, we need to pass over the
  869. 36:58three, uh, parameters. So, what was
  870. 37:01those? You can see in our, uh, Azure
  871. 37:03Data Factory. So, one was, uh, P
  872. 37:05relative URL.
  873. 37:07Then, uh, select that, paste it there.
  874. 37:10Then, uh, another one is, uh, P
  875. 37:13underscore, uh, sync folder name. And
  876. 37:15another one is P underscore file name.
  877. 37:17So, what will be our P relative URL? Go
  878. 37:20to our, uh,
  879. 37:22GitHub folder. In that, you will see
  880. 37:25this over, uh, data and select the raw.
  881. 37:28And, uh, from the, uh, URL, you will get
  882. 37:32the relative URL. Just select that and
  883. 37:34paste it in our, uh, value part.
  884. 37:37Now, we need to add the, uh, our two,
  885. 37:40uh, parameters. So, one is, uh,
  886. 37:43P sync folder and, uh, another one is,
  887. 37:46uh, P sync file name.
  888. 37:49So,
  889. 37:50what will be our P sync
  890. 37:52folder? So, in the first case, it will
  891. 37:55be a category. And, uh, P sync file name
  892. 37:59will be our, uh, file, uh, file
  893. 38:01name.csv. Because all the data we have
  894. 38:04in a CSV format.
  895. 38:06So,
  896. 38:08uh, file name will be our,
  897. 38:10uh, category.csv.
  898. 38:13Now, we need to create all these
  899. 38:15dictionary for all of our, uh, folders.
  900. 38:18So, we have our
  901. 38:20We have total five folders. And, uh,
  902. 38:23need to create the uh,
  903. 38:25all the parameters for all the folders.
  904. 38:27I'm just fast forward fast forwarding
  905. 38:31this.
  906. 38:33Once we have created all the files,
  907. 38:37it will look like this.
  908. 38:39Now, I'm just saving this and then once
  909. 38:44we have saved that, we need to upload
  910. 38:47that file in our
  911. 38:51our Azure Data Lake
  912. 38:54folder. So, in the Azure Data Lake, I'm
  913. 38:58creating one more container that is
  914. 39:01parameters and in the in the parameters,
  915. 39:04I'm just
  916. 39:06drag and drop. Just do the drag and
  917. 39:09drop. Once you have done that, now come
  918. 39:12to the our Azure Data Factory tab.
  919. 39:15Now, let's use the output of our JSON
  920. 39:19file.
  921. 39:20If we simply want to read a file and see
  922. 39:23what it contains, we can use the lookup
  923. 39:25activity in our Azure Data Factory.
  924. 39:28Lookup allows us to retrieve data from
  925. 39:31the file and use that output in other
  926. 39:34activities.
  927. 39:35So, let's add lookup activity to our
  928. 39:38pipeline. I will search for the lookup
  929. 39:41and drag it into our canvas. I will name
  930. 39:44that
  931. 39:46it as a lookup lookup kit.
  932. 39:49Now,
  933. 39:50in this setting section, we need to
  934. 39:53provide a data set because lookup needs
  935. 39:56to know which file it should read.
  936. 39:59Let's create a new data set. I will
  937. 40:02click new, select Azure Data Lake
  938. 40:04storage Gen2 and then will continue.
  939. 40:09Our file is in a JSON format, so I will
  940. 40:12select JSON and will continue.
  941. 40:15I will give the data set
  942. 40:18a name like DS
  943. 40:20get underscore parameter.
  944. 40:22For the link services, I will use the
  945. 40:25same storage account that we have
  946. 40:26configured.
  947. 40:28Now, we need to specify the file path. I
  948. 40:31will browse through the container where
  949. 40:34our JSON is stored. In this case, the
  950. 40:37file is inside our parameter container.
  951. 40:40I will select the JSON file and will
  952. 40:43click okay.
  953. 40:45That's all we need to do for the look up
  954. 40:48look up configuration.
  955. 40:50But there is one important setting that
  956. 40:53we need to understand here.
  957. 40:55By default, the look up activity is
  958. 40:57configured to return only the first row.
  959. 41:00In our scenario, that's not what we
  960. 41:02want. Our JSON file contains multiple
  961. 41:05entities and we want to retrieve all of
  962. 41:08them because the later we are going to
  963. 41:10pass these
  964. 41:12entities into our for each loop.
  965. 41:16So, we need to uncheck our first row
  966. 41:18only. This is only a small setting, but
  967. 41:21it's very important when we are building
  968. 41:23a dynamic pipeline using a look up and
  969. 41:26for each. If first row only remains
  970. 41:29enabled,
  971. 41:31look up will return only one record and
  972. 41:33our for each loop would execute only
  973. 41:36once. Now, let's see what exactly look
  974. 41:39up activity returns. For demonstration,
  975. 41:43I only want to run the particular
  976. 41:45activity. So, I will temporarily
  977. 41:47deactivated the other activities on the
  978. 41:50canvas. I will open the activity
  979. 41:53setting, go to general, and set the
  980. 41:56activity state as a deactivated.
  981. 41:59I [snorts] will do the same for other
  982. 42:01activities and I don't want to execute
  983. 42:04that. Now, only our look up activity
  984. 42:07will run. Let's trigger a debug run.
  985. 42:11Once [snorts]
  986. 42:12uh the activity succeeded, we can open
  987. 42:15the output and inspect what the lookup
  988. 42:17has written. Here, we can see the
  989. 42:20output. Under the value property, we
  990. 42:23have the list of records that we need.
  991. 42:25This is exactly what we are interested
  992. 42:28in.
  993. 42:30The value property contains an array,
  994. 42:33and uh each element in that array
  995. 42:35represent one entity.
  996. 42:38For example, one item contains the
  997. 42:40relative URL, another property contains
  998. 42:42sync folder, and another contains the
  999. 42:45file name. Our goal is to pass the
  1000. 42:48entire array into the for each activity.
  1001. 42:51That way, uh our for each
  1002. 42:54can process each activity each entity
  1003. 42:56one by one.
  1004. 42:58So, let's uh close the output window and
  1005. 43:02activate the uh our other activity
  1006. 43:05again. Now, we need to connect the
  1007. 43:07lookup activity to our for each uh
  1008. 43:10activity. When we are
  1009. 43:12connecting activities in ADF, we have
  1010. 43:15different dependency dependency
  1011. 43:18conditions, such as uh succeeded,
  1012. 43:21failed, skip, and completed. In our
  1013. 43:25case, we want uh if for each activity to
  1014. 43:27start only when the lookup activity
  1015. 43:30succeeded. So, I will select the
  1016. 43:33succeeded dependency and connect the
  1017. 43:35lookup to if for each.
  1018. 43:39Now, let's configure the for each
  1019. 43:41activity.
  1020. 43:45The most important property here is
  1021. 43:47items.
  1022. 43:48This is where we tell for each
  1023. 43:51uh which collection it needs to iterate
  1024. 43:54over. Because the collection is coming
  1025. 43:56from another activity, we don't want to
  1026. 43:59hardcode anything. We will use a dynamic
  1027. 44:02content. I will open dynamic content and
  1028. 44:05select the output from our lookup
  1029. 44:07activity.
  1030. 44:09But, there is one important detail here.
  1031. 44:11We don't want to pass the entire lookup
  1032. 44:14output. We specifically need the array
  1033. 44:17stored inside the value property.
  1034. 44:21So, instead of using only the lookup
  1035. 44:24output, we need to reference it.
  1036. 44:27Output.value. This tells ADF that take
  1037. 44:31the value that take the output of the
  1038. 44:33lookup activity and then take the value
  1039. 44:36property from the output. And that value
  1040. 44:39property contains the array that we want
  1041. 44:41to iterate over. Now, I will click okay.
  1042. 44:45Now, our for each activity has the
  1043. 44:47complete array as its input.
  1044. 44:50The next step is straightforward. We
  1045. 44:53need to place our copy activity inside
  1046. 44:56the for each loop. I will cut the
  1047. 44:58existing copy activity, open for each
  1048. 45:01activity, and go to the activity
  1049. 45:03section.
  1050. 45:04I will click on the pencil icon and
  1051. 45:08it will open the internal canvas for the
  1052. 45:11for each activity. Now, we are inside
  1053. 45:14the for each loop. I will paste the copy
  1054. 45:17activity here. This means that copy
  1055. 45:20activity will execute once for every
  1056. 45:23items in the array. Now, we need to
  1057. 45:25configure the parameter of our copy
  1058. 45:28activity.
  1059. 45:29Our source is requires values such as
  1060. 45:32relative URL, sync folder, and file
  1061. 45:35name.
  1062. 45:35These values are coming from the current
  1063. 45:38items of the for each loop. So, again,
  1064. 45:41we will use the dynamic content. Inside
  1065. 45:44the for each loop, the current record
  1066. 45:47can be accessed using the item
  1067. 45:49expression.
  1068. 45:50Remember, each element in our array is
  1069. 45:53one complete object. For example, one
  1070. 45:56item could look like relative URL, sync
  1071. 45:59folder, and file name. During the first
  1072. 46:02iteration, items represent the first
  1073. 46:04object. During the second
  1074. 46:07iteration, it represents the second
  1075. 46:09object and it is continuous until every
  1076. 46:12object has been processed.
  1077. 46:14For the source relative URL, we need a
  1078. 46:18relative URL property from the current
  1079. 46:20item. So, we will use a
  1080. 46:22item.p_relativeurl.
  1081. 46:25I will select that as a dynamic value.
  1082. 46:28For the sync folder, we will do the same
  1083. 46:30thing, but this time we will reference
  1084. 46:33the sync folder property. Items. Sorry,
  1085. 46:36item.p_sync_folder.
  1086. 46:40And finally, for the file name, we will
  1087. 46:42reference the file name property.
  1088. 46:44Item.p_file_name.
  1089. 46:47[clears throat]
  1090. 46:48Now, our copy activity is dynamically
  1091. 46:50using the values from from each items in
  1092. 46:53the lookup output. This is the main
  1093. 46:56concept behind the dynamic pipeline we
  1094. 46:58are building. Instead of creating a
  1095. 47:00separate copy activity for each and
  1096. 47:02every file, we we have one copy activity
  1097. 47:05inside a for each loop.
  1098. 47:08The lookup provides the list. The for
  1099. 47:11each iterates over the list and the copy
  1100. 47:14activity processes each items using the
  1101. 47:16parameter from the current iteration.
  1102. 47:19So, let's run the pipeline and see what
  1103. 47:21happens. I will start debug run. Now, we
  1104. 47:25can monitor the execution. If something
  1105. 47:29fails, that's completely fine. Debugging
  1106. 47:31is a part important part of building the
  1107. 47:34data pipeline. Let's monitor the
  1108. 47:37execution. It might take some
  1109. 47:39time, some few seconds. And now, we can
  1110. 47:42see the activities completing completing
  1111. 47:45successfully.
  1112. 47:46This is an important lesson when we are
  1113. 47:49working with a dynamic pipelines. Don't
  1114. 47:51assume that every failure means the
  1115. 47:54overall design is wrong. First, look at
  1116. 47:56the message, then compare it with the
  1117. 47:59actual data and the expression we are
  1118. 48:01using. Small differences in the property
  1119. 48:04names, paths, and parameter can cause
  1120. 48:07the this kind of issues. Once the
  1121. 48:10pipeline succeeded, we should
  1122. 48:13also validate the actual output. Let's
  1123. 48:16go to our storage account and open the
  1124. 48:19bronze container. Here we can see the
  1125. 48:21folders that are that we have created
  1126. 48:24using the pipeline.
  1127. 48:26Inside these folders, we should now see
  1128. 48:28the files that were processed by the
  1129. 48:30dynamic pipeline.
  1130. 48:32Uh these all files are in a CSV format.
  1131. 48:36So our first phase is now completed. We
  1132. 48:40have successfully created the dynamic
  1133. 48:42pipeline where lookup reads the
  1134. 48:44configuration, for each it reads through
  1135. 48:47the list, and a copy activity uses the
  1136. 48:50value for each iteration to process the
  1137. 48:52required files.
  1138. 48:54This is
  1139. 48:55uh more scalable than creating the
  1140. 48:57separate
  1141. 48:58activities manually for every file. And
  1142. 49:01this pattern is very useful in
  1143. 49:03real-world data engineering project
  1144. 49:06because the number of files the or the
  1145. 49:08entities can change without requiring us
  1146. 49:11to redesign the entire pipeline.
  1147. 49:14Now that our ADF part is completed, we
  1148. 49:18will move to the next phase of our
  1149. 49:20project. And in this next phase phase,
  1150. 49:23we will start working with the Azure
  1151. 49:25data file data bricks.
  1152. 49:27>> [snorts]
  1153. 49:27>> And continue building our end-to-end
  1154. 49:29data engineering solution. Let's move on
  1155. 49:32to the data bricks part.
  1156. 49:35>> Great. With that, our first phase is
  1157. 49:37completed. We have successfully built
  1158. 49:40and tested our dynamic pipeline in Azure
  1159. 49:42Data Factory.
  1160. 49:44Now let's move to phase two where we
  1161. 49:46will start working with Azure Data
  1162. 49:48Bricks.
  1163. 49:49In this phase, we will create our Data
  1164. 49:51Bricks workspace, configure the compute,
  1165. 49:54create the notebooks, and then we will
  1166. 49:56start working with the data that just we
  1167. 49:59have ingested. So, let's get started. I
  1168. 50:02will go back to our Azure portal where I
  1169. 50:05will click on a home button. From here,
  1170. 50:08I will select a creator resource and
  1171. 50:10search for Azure Databricks.
  1172. 50:13I will select the Microsoft Azure
  1173. 50:14Databricks service and then click
  1174. 50:16create. Now, we need to configure the
  1175. 50:19Databricks workspace.
  1176. 50:21First, I will select a resource group
  1177. 50:23that we are using for this project.
  1178. 50:26For the workspace name, I will use
  1179. 50:28something meaningful like ADB Azure
  1180. 50:31project.
  1181. 50:32You can use anything any meaningful name
  1182. 50:35based on your project. Next, we need to
  1183. 50:38select the pricing tier. Depending on
  1184. 50:41the subscription and purpose of our
  1185. 50:43environment, we get a options like
  1186. 50:46standard or premium one. Here, I'm using
  1187. 50:49a trial
  1188. 50:50option.
  1189. 50:52If you are following this as a practice
  1190. 50:55project, choose the option that is
  1191. 50:56available and appropriate for your
  1192. 50:59subscription.
  1193. 51:00Keep in mind that Databricks resource
  1194. 51:02can incur cost depending on the
  1195. 51:05configuration and how long we are
  1196. 51:07running it.
  1197. 51:08Now, we have to give the managed
  1198. 51:10resource group. So, here I'm giving a
  1199. 51:12managed ADB AW project. This is very
  1200. 51:16important concept to understand. Azure
  1201. 51:20Databricks create and manages Azure
  1202. 51:23resources required to run Databricks
  1203. 51:25infrastructure,
  1204. 51:26including resources associated with the
  1205. 51:29computing environment. You generally
  1206. 51:32don't manages these resources directly.
  1207. 51:35Azure Databricks manages them as a part
  1208. 51:37of your workspace.
  1209. 51:39Now,
  1210. 51:40I will use a clear I have used a clear
  1211. 51:43and meaningful name for the managed
  1212. 51:45resource group so that we can easily
  1213. 51:48identify it. Now let's continue with the
  1214. 51:51remaining configuration. I will go
  1215. 51:53through the networking setting then
  1216. 51:55encryption and following the security
  1217. 51:58option.
  1218. 51:59For the for this
  1219. 52:00practice purpose I will keep the default
  1220. 52:03configuration where
  1221. 52:05we need to we don't need to configure
  1222. 52:07anything. Now I will go to review and
  1223. 52:10create
  1224. 52:11option.
  1225. 52:13Azure will validate the configuration.
  1226. 52:16Once a validation succeeded I will click
  1227. 52:19on a create button.
  1228. 52:22The Databricks workspace is now start
  1229. 52:24deploying.
  1230. 52:25It might take some time for everyone.
  1231. 52:29While that's being created let's quickly
  1232. 52:32understand what we are going to do next.
  1233. 52:35Once the workspace is ready we will
  1234. 52:37launch it and start working directly
  1235. 52:40inside the Databricks environment.
  1236. 52:43We will build everything step-by-step
  1237. 52:46starting with the basic components and
  1238. 52:48then moving towards the actual data
  1239. 52:50transformation.
  1240. 52:52This is also where you will start seeing
  1241. 52:54how Databricks fix into your
  1242. 52:57end-to-end Azure data engineering
  1243. 53:00architecture.
  1244. 53:02The ADF pipelines that we created
  1245. 53:04earlier handles the ingestion and
  1246. 53:06orchestration side. While Databricks
  1247. 53:09will use for the processing and
  1248. 53:11transformation side.
  1249. 53:13So the two services work together as a
  1250. 53:16overall data pipeline.
  1251. 53:19The deployment is completed so let's
  1252. 53:22move to Databricks resource.
  1253. 53:26I will click on a go to resource button.
  1254. 53:29From here I will launch a Databricks
  1255. 53:31workspace and now we are inside the
  1256. 53:34Azure Databricks workspace.
  1257. 53:36The interface may look slightly
  1258. 53:39different depending on the Databricks
  1259. 53:41version and UI update, but the core
  1260. 53:44concept remains the same. Before we
  1261. 53:46start writing any code, let's understand
  1262. 53:50and
  1263. 53:51let's understand the main section we
  1264. 53:53will be working on.
  1265. 53:55The first important concept is compute.
  1266. 53:58Compute is where our data processing
  1267. 54:01workload actually run.
  1268. 54:03In Databricks, this is typically
  1269. 54:05represented by the compute resource or a
  1270. 54:08cluster.
  1271. 54:09When we execute a Spark node, perform
  1272. 54:12transformation, or process the data, the
  1273. 54:15compute resource provide the processing
  1274. 54:17power required to execute those
  1275. 54:19workloads.
  1276. 54:21We also have a workspace, which is where
  1277. 54:24we can organize our notebooks and
  1278. 54:26development resources.
  1279. 54:29Then we have a catalog, which is used
  1280. 54:32for the organizing and governing data
  1281. 54:35data assets such as like
  1282. 54:37catalog, schema, table, or external
  1283. 54:40locations, depending on the
  1284. 54:42configuration
  1285. 54:43of the environment. We also have a
  1286. 54:46workflows,
  1287. 54:48which can be used for scheduling and
  1288. 54:51orchestrating the Databricks jobs.
  1289. 54:54There are
  1290. 54:56also areas for SQL dashboards, alerts,
  1291. 54:59and other Databricks capabilities.
  1292. 55:02For now, we will be focusing on the most
  1293. 55:06important
  1294. 55:07component
  1295. 55:09that is a compute. So, let's create our
  1296. 55:12compute resource.
  1297. 55:14I will click on a compute. Since we
  1298. 55:17don't have any compute resource yet, I
  1299. 55:19will
  1300. 55:20click on a create compute.
  1301. 55:22Now, we need to configure our compute.
  1302. 55:26First, we can provide a name. I will
  1303. 55:28call it as a AW project cluster. Next,
  1304. 55:33we have the compute configuration and
  1305. 55:36policy option. For this practice
  1306. 55:38project, I'm going to keep the
  1307. 55:41configuration simple because we don't
  1308. 55:43need a large cluster to process over a
  1309. 55:45relatively
  1310. 55:47relatively small amount of data what we
  1311. 55:49are working with.
  1312. 55:51I will use for single node
  1313. 55:53configuration. For a smaller learning
  1314. 55:56project, single node setup is usually
  1315. 55:58sufficient. Next, we need to select the
  1316. 56:01Databricks runtime.
  1317. 56:03The runtime determines the Spark and
  1318. 56:06related software environment that our
  1319. 56:09workload will be using.
  1320. 56:11I will select and available LTS or a
  1321. 56:14long-term support runtime.
  1322. 56:17The exact version you may see different
  1323. 56:20depending on
  1324. 56:22when you are following this tutorial.
  1325. 56:25So, that's completely fine. The The
  1326. 56:27important thing is to choose compatible
  1327. 56:30LTS runtime that is available in your
  1328. 56:33environment. Next, we have to select the
  1329. 56:36node type. I will select general purpose
  1330. 56:38node suitable for this practice
  1331. 56:40workload. For example, DS3
  1332. 56:43V2 configuration may be sufficient for
  1333. 56:46this small exercise, but the available
  1334. 56:49node types and pricing can be varied by
  1335. 56:51the subscription and the regions.
  1336. 56:54One of the most important setting here
  1337. 56:56is a auto termination. So, this is very
  1338. 57:00important
  1339. 57:01because when you are working with a paid
  1340. 57:04Azure sub the subscription, if the
  1341. 57:07cluster remains running when you are not
  1342. 57:09using, you may continue to incur compute
  1343. 57:12cost. So, I will configure the cluster
  1344. 57:15to automatically terminate after short
  1345. 57:17period of
  1346. 57:18inactivity.
  1347. 57:19For this project, I will use around a 20
  1348. 57:23minutes.
  1349. 57:25You can choose different value depending
  1350. 57:27on your workload. If you are a working
  1351. 57:30on a real project,
  1352. 57:32don't simply use a short time out
  1353. 57:34without considering the workload. The
  1354. 57:37setting should match how frequently the
  1355. 57:39cluster is expected to be used.
  1356. 57:42For now,
  1357. 57:44I will leave the remaining option
  1358. 57:46as default as default values.
  1359. 57:50I don't need to add any tags for the for
  1360. 57:53this demonstration.
  1361. 57:55And I don't need any additional
  1362. 57:57acceleration features for this
  1363. 58:00workloads. So now I will click on a
  1364. 58:02create compute. Our computer resource is
  1365. 58:05being created. Once it's ready, we will
  1366. 58:08able to start running Spark workloads
  1367. 58:10inside the data bricks.
  1368. 58:12You can also monitor the compute status
  1369. 58:15and when needed impact inspect the Spark
  1370. 58:19UI to understand the execution of the
  1371. 58:21Spark jobs.
  1372. 58:24While the computer is starting, let's
  1373. 58:27understand why we are using a data
  1374. 58:29bricks here.
  1375. 58:30Our data factory pipeline was
  1376. 58:32responsible for dynamic reading the
  1377. 58:35configuration and moving the resource
  1378. 58:37file into the bronze layer.
  1379. 58:39Now we are moving into the processing
  1380. 58:41stage. Data bricks gives us a Spark base
  1381. 58:44environment where we we can use a
  1382. 58:47languages like Python, SQL, Scala, or R
  1383. 58:51to process our
  1384. 58:52process our data and transform it.
  1385. 58:55For our project, we will primarily work
  1386. 58:57with a Python and PySpark along with a
  1387. 59:01SQL where where we needed.
  1388. 59:04We will take the data that we have
  1389. 59:06landed in our storage account and start
  1390. 59:08the transforming it.
  1391. 59:10This is where concepts like data frames,
  1392. 59:13Spark transformation, join, filters,
  1393. 59:16aggregation, partition, and eventually
  1394. 59:19Delta Lake will come into the picture.
  1395. 59:22It's also important to understand the
  1396. 59:24difference between simply learn data
  1397. 59:26bricks in isolation and using a data
  1398. 59:28bricks as a part of a cloud data
  1399. 59:30engineering project.
  1400. 59:32When you connect a data bricks
  1401. 59:35to the Azure storage, you are working
  1402. 59:37with the actual cloud data.
  1403. 59:40You are reading the data from storage,
  1404. 59:42processing it using a spark, and writing
  1405. 59:45the transform results back to our
  1406. 59:48appropriate layers.
  1407. 59:50That gives you much better understanding
  1408. 59:52of how data bricks fits into the real
  1409. 59:55world of data platform.
  1410. 59:57And that's exactly what we are going to
  1411. 59:59build in this project. Our compute is
  1412. 1:00:02now being
  1413. 1:00:04prepared. Once it become available, we
  1414. 1:00:07will create our first notebook and start
  1415. 1:00:09working with the data.
  1416. 1:00:11From this point onward, we will move
  1417. 1:00:13from infrastructure setup into the
  1418. 1:00:15actual data engineering work. So, let's
  1419. 1:00:18continue with our first data bricks
  1420. 1:00:21notebook.
  1421. 1:00:25Now that we have created our Azure data
  1422. 1:00:28bricks workspace and configure our
  1423. 1:00:31compute, let's move to the next
  1424. 1:00:32important step.
  1425. 1:00:34Connecting data bricks to our Azure data
  1426. 1:00:37lake storage. Before we start writing
  1427. 1:00:40any transformation, we need to make sure
  1428. 1:00:42that data bricks can access our data
  1429. 1:00:45that we have already stored in our
  1430. 1:00:46bronze layer.
  1431. 1:00:48Let's understand how this work. In the
  1432. 1:00:51previous section, we uh use Azure data
  1433. 1:00:54factory to ingest a source file into the
  1434. 1:00:56data lake storage Gen2 account.
  1435. 1:00:59Our data is now available into the
  1436. 1:01:01storage account. However, a data lake
  1437. 1:01:04storage and data bricks are two separate
  1438. 1:01:06Azure services. Just because we have
  1439. 1:01:09created both the resources under the
  1440. 1:01:11same Azure subscription doesn't mean
  1441. 1:01:14that data bricks automatically has
  1442. 1:01:16permission to access the storage
  1443. 1:01:18account.
  1444. 1:01:19We need to explicitly configure
  1445. 1:01:21authentication and authorization. So,
  1446. 1:01:24authentication verifies the identity of
  1447. 1:01:27the application requesting access, while
  1448. 1:01:30authorization determines what that
  1449. 1:01:33application is allowed to do. For
  1450. 1:01:35example, whether it can read file,
  1451. 1:01:37create new files, or modify the existing
  1452. 1:01:40data.
  1453. 1:01:41For this project, we are going to
  1454. 1:01:43configure access using the service
  1455. 1:01:45principle. So, service principle is an
  1456. 1:01:48identity that application and services
  1457. 1:01:51can use to authenticate and access Azure
  1458. 1:01:54resources.
  1459. 1:01:56Think of it as a dedicated identity of
  1460. 1:01:59for our Databricks workload. So, instead
  1461. 1:02:02of using our personal Azure account to
  1462. 1:02:05access the storage, we will create
  1463. 1:02:07application identity and assign the
  1464. 1:02:10required permissions.
  1465. 1:02:12Then, we will configure Databricks to
  1466. 1:02:15authenticate using the that identity.
  1467. 1:02:19The overall process involved three
  1468. 1:02:21steps. First, we will register our our
  1469. 1:02:24application in a Microsoft Entra ID.
  1470. 1:02:28Then, we will assign the application
  1471. 1:02:31that require permission on our storage
  1472. 1:02:33account. And finally, we will configure
  1473. 1:02:36Databricks to use the application
  1474. 1:02:38credential when accessing the Azure Data
  1475. 1:02:41Lake storage.
  1476. 1:02:43Let's go through these steps one by one.
  1477. 1:02:46Now, I will switch back to my Azure
  1478. 1:02:50portal.
  1479. 1:02:52I will suggest to you to do the same. In
  1480. 1:02:54the search bar, I will search for the
  1481. 1:02:56Microsoft Entra ID.
  1482. 1:03:00Microsoft Entra ID is a Microsoft
  1483. 1:03:04cloud-based identity and access
  1484. 1:03:06management service. It allows us to
  1485. 1:03:08manage users, application identities,
  1486. 1:03:11and authentication across the Azure
  1487. 1:03:13services. I will open uh will open
  1488. 1:03:17Microsoft Entra ID. On the left side
  1489. 1:03:21uh we have a several options including
  1490. 1:03:24users, groups, roles, and app
  1491. 1:03:27registration. For our scenario, we we
  1492. 1:03:30are interested in only app registration
  1493. 1:03:33as of now.
  1494. 1:03:34I will select app registration and I
  1495. 1:03:36will click new registration. Now, Azure
  1496. 1:03:40is asking us to provide a name of our
  1497. 1:03:43application.
  1498. 1:03:44I will name it as a
  1499. 1:03:46Azure project underscore app.
  1500. 1:03:50Now,
  1501. 1:03:52you can choose any meaningful name based
  1502. 1:03:54on your project. For the support account
  1503. 1:03:57types, I will keep the default options
  1504. 1:03:59for the accounts in this organizational
  1505. 1:04:02directory.
  1506. 1:04:03We don't need to configure a redirect
  1507. 1:04:06URL because we are not building an
  1508. 1:04:08interactive web application.
  1509. 1:04:10Now, click on the register button.
  1510. 1:04:13And that's it. Our application
  1511. 1:04:15registration has been created
  1512. 1:04:17successfully. Azure has also created an
  1513. 1:04:20associated application identity that we
  1514. 1:04:24can use for authentication. Now, let's
  1515. 1:04:27look at the information available on
  1516. 1:04:29this page. We have the application
  1517. 1:04:32client ID, directory
  1518. 1:04:34tenant ID, and object ID. These
  1519. 1:04:37identifiers serves uh different
  1520. 1:04:39purposes. The application ID uniquely
  1521. 1:04:42identify our registered application. The
  1522. 1:04:46tenant ID identifies the Microsoft Entra
  1523. 1:04:49directory where the application is
  1524. 1:04:51registered.
  1525. 1:04:53And the object ID identifies the
  1526. 1:04:55application object within the directory.
  1527. 1:04:58For our Databricks connections, we'll
  1528. 1:05:01primarily need application ID and tenant
  1529. 1:05:04ID. Let's copy all these values and keep
  1530. 1:05:07them available for the next steps. I
  1531. 1:05:10will
  1532. 1:05:11copy first application ID, then I will
  1533. 1:05:14copy directory and tenant ID.
  1534. 1:05:17One important point here is that tenant
  1535. 1:05:20ID and the object ID are not
  1536. 1:05:22interchangeable. So, when when
  1537. 1:05:25configuring
  1538. 1:05:27OAuth authentication, we must use the
  1539. 1:05:30tenant ID in the app authentication
  1540. 1:05:32endpoint. Now, we need one more piece of
  1541. 1:05:35information that is our client secret.
  1542. 1:05:38To authenticate our application, we are
  1543. 1:05:40going to create a client secret.
  1544. 1:05:43A client secret acts like a password for
  1545. 1:05:46our application identity.
  1546. 1:05:49Databricks can use the application ID,
  1547. 1:05:51tenant ID, and client secrets to request
  1548. 1:05:54an access token from the Microsoft Entra
  1549. 1:05:57ID.
  1550. 1:05:58That access token can then be used to
  1551. 1:06:02access our storage account, provided the
  1552. 1:06:05application has the required permission.
  1553. 1:06:08So, let's create the secret. Inside our
  1554. 1:06:11application registration, I will select
  1555. 1:06:13certificates and secrets. Under the
  1556. 1:06:15client secrets, I will click a new
  1557. 1:06:17client secret. Now, we need to provide a
  1558. 1:06:21description. I will use Azure project.
  1559. 1:06:24Next, we need to choose an expiration
  1560. 1:06:27period. For this demonstration, I will
  1561. 1:06:29select a 6 months. In production
  1562. 1:06:32environment, credentials should have an
  1563. 1:06:34appropriate expiration and rotation
  1564. 1:06:36policy.
  1565. 1:06:38Now, I will click add.
  1566. 1:06:40Our client secret has been created.
  1567. 1:06:43Here, we can see two different fields,
  1568. 1:06:45value and secret ID. This distinction is
  1569. 1:06:48very important. For authentication, we
  1570. 1:06:51need a value, not a secret ID. The
  1571. 1:06:54secret ID is only for the identifier for
  1572. 1:06:57the secret. I will copy the client
  1573. 1:07:00secret value now because Azure will not
  1574. 1:07:02display the full value again after
  1575. 1:07:05we leave this page.
  1576. 1:07:07For a real project, we should store
  1577. 1:07:09these values securely in Azure Key Vault
  1578. 1:07:13or another approach secret management
  1579. 1:07:16solution.
  1580. 1:07:17We should never expose secret in a
  1581. 1:07:20source code or Git repository or public
  1582. 1:07:23shared notebooks. Now, we have three
  1583. 1:07:26values required for our authentication.
  1584. 1:07:29Client ID,
  1585. 1:07:30tenant ID, and client secret value. Our
  1586. 1:07:34application identity is ready. But,
  1587. 1:07:36there is one more thing we need to do
  1588. 1:07:39that. So, we have to create the
  1589. 1:07:41identity, but we haven't granted the
  1590. 1:07:44permissions to access our storage
  1591. 1:07:46account. So, let's configure that also.
  1592. 1:07:49I will return to my Azure portal
  1593. 1:07:52homepage. Now, I will open a storage
  1594. 1:07:55account that we are using for this
  1595. 1:07:56project. Remember, this is the same
  1596. 1:07:59storage account
  1597. 1:08:01where Azure Data Factory has already
  1598. 1:08:03loaded our source files.
  1599. 1:08:05Inside the storage account, I will
  1600. 1:08:07select access control, that is IAM.
  1601. 1:08:11IAM stands for identity and access
  1602. 1:08:14management. This is where we can control
  1603. 1:08:17which users and application have access
  1604. 1:08:20to our Azure
  1605. 1:08:22resources.
  1606. 1:08:23I will click add and followed by add
  1607. 1:08:27role assignment. Now, Azure displays
  1608. 1:08:30several built-in roles. For our project,
  1609. 1:08:33we need a role that allows our
  1610. 1:08:35application to read and write the data
  1611. 1:08:38into Azure Blob Storage and Data Lake
  1612. 1:08:41Storage Gen2.
  1613. 1:08:43I will search for storage
  1614. 1:08:46blob data contributor. This role
  1615. 1:08:49provides permission to read, write, and
  1616. 1:08:51delete blob data. Since we will be
  1617. 1:08:54reading data from the bronze layer and
  1618. 1:08:56writing the transformation data into our
  1619. 1:08:58silver layer, this role is suitable for
  1620. 1:09:01our demonstration. In production
  1621. 1:09:03environment, we should follow the
  1622. 1:09:05principle of least privilege and assign
  1623. 1:09:08permission only at the scope required by
  1624. 1:09:11the workload.
  1625. 1:09:13Uh for example, we might grant access at
  1626. 1:09:16the container level rather than at the
  1627. 1:09:18storage account level.
  1628. 1:09:20I will select a storage blob data
  1629. 1:09:22contributor and click next. Now we need
  1630. 1:09:25to select the identity that should
  1631. 1:09:27receive this role. So I will click on a
  1632. 1:09:30select member. In the search box, I will
  1633. 1:09:33search for the application we created
  1634. 1:09:35earlier, that is Azure project
  1635. 1:09:37underscore app.
  1636. 1:09:39Here we can see our application. I will
  1637. 1:09:42select it and confirm it. Now I will
  1638. 1:09:45click on a review and assign button.
  1639. 1:09:48Um Azure will create a role assignment.
  1640. 1:09:51Once the assignment is completed, our
  1641. 1:09:54application will have the required Azure
  1642. 1:09:56RBAC permission.
  1643. 1:09:59Keep in mind that the role assignment
  1644. 1:10:01may take a few minutes to
  1645. 1:10:04process. Also for Azure Data Lake
  1646. 1:10:06Storage Gen2, access can depend on both
  1647. 1:10:09Azure RBAC and file system ACLs.
  1648. 1:10:14If you are using a more restrictive
  1649. 1:10:16permission setup, you may need to
  1650. 1:10:19configure those separately.
  1651. 1:10:21For our
  1652. 1:10:22current configuration, we will
  1653. 1:10:24proceed with the assigned role.
  1654. 1:10:27Now we have completed the first two
  1655. 1:10:29steps. We have created the application
  1656. 1:10:32identity and assigned storage
  1657. 1:10:34permission. Next we will be configuring
  1658. 1:10:36a connection from the Azure Databricks.
  1659. 1:10:39So now let's return to our Databricks. I
  1660. 1:10:43will open the Databricks workspace that
  1661. 1:10:46we have created earlier. We already have
  1662. 1:10:49our compute configured, so we can start
  1663. 1:10:52working with the notebooks.
  1664. 1:10:54First I will navigate to our workspace
  1665. 1:10:56section. This is where we can organize
  1666. 1:10:59our notebooks and project files.
  1667. 1:11:02To keep everything structured, I will
  1668. 1:11:04create a separate folder for Azure
  1669. 1:11:06project. I will create a
  1670. 1:11:10folder. I will name it as Azure
  1671. 1:11:13underscore project. Now we have
  1672. 1:11:15dedicated folder where we can store all
  1673. 1:11:17of our
  1674. 1:11:18notebooks related to this project. I
  1675. 1:11:22I will click on create again and select
  1676. 1:11:26the notebook. This opens the Databricks
  1677. 1:11:29notebook interface. If you have worked
  1678. 1:11:32with the Jupyter notebook before, this
  1679. 1:11:34is this interface should looks familiar
  1680. 1:11:37to you. Databricks notebooks allows us
  1681. 1:11:39to write and execute code and in
  1682. 1:11:42individual cells. We can [snorts] use a
  1683. 1:11:44Python, SQL, Scala, and R depending on
  1684. 1:11:47notebook and compute configuration.
  1685. 1:11:51For this project, we will be mainly
  1686. 1:11:52using a Python and PySpark. So let's
  1687. 1:11:55start with our notebook and let's give
  1688. 1:11:57it a meaningful name.
  1689. 1:12:00I will
  1690. 1:12:01rename it as a silver layer data
  1691. 1:12:04transformation.
  1692. 1:12:06This notebook will eventually contain
  1693. 1:12:08the transformation required to process
  1694. 1:12:10our bronze layer data and prepare the
  1695. 1:12:13silver layer. So before writing any
  1696. 1:12:15transformation logic, we need to connect
  1697. 1:12:18notebook to our compute.
  1698. 1:12:21I will click connect at the top.
  1699. 1:12:23Uh here we can see the compute resources
  1700. 1:12:26that we have created earlier. I will
  1701. 1:12:28select the our project cluster. If the
  1702. 1:12:31project cluster is stopped, Databricks
  1703. 1:12:33will start it when it required. It may
  1704. 1:12:36take a few minutes for the computer to
  1705. 1:12:39become available. While that's
  1706. 1:12:41happening, let's organize our notebook.
  1707. 1:12:44One
  1708. 1:12:45useful feature for Databricks notebook
  1709. 1:12:48is the ability to combine code with a
  1710. 1:12:50documentation.
  1711. 1:12:52We can use the markdown cells to add
  1712. 1:12:55headings,
  1713. 1:12:56descriptions, and explanations.
  1714. 1:12:59This makes our notebook easier to
  1715. 1:13:01understand and maintain. I will select
  1716. 1:13:04the first cell and change its type to
  1717. 1:13:07from Python to markdown. Now, I will add
  1718. 1:13:10a heading silver layer data
  1719. 1:13:12transformation.
  1720. 1:13:14>> [snorts]
  1721. 1:13:14>> To create a heading in a markdown, we
  1722. 1:13:17can use the hash symbol. For example,
  1723. 1:13:20one hash symbol create a one-level
  1724. 1:13:22heading while two or three hash symbol
  1725. 1:13:26create a smaller headings. I will use a
  1726. 1:13:29heading and execute the cell cell using
  1727. 1:13:31a shift plus enter.
  1728. 1:13:33Now, the heading is displayed in a
  1729. 1:13:37formatted style. Let's add another
  1730. 1:13:39section called
  1731. 1:13:41In that, I will add a data loading.
  1732. 1:13:44Before
  1733. 1:13:45Before that, we need to access our data.
  1734. 1:13:48So,
  1735. 1:13:49I will again add in a new cell above and
  1736. 1:13:52I will add in that
  1737. 1:13:54data access using
  1738. 1:13:57app. This section will contain the
  1739. 1:13:59configuration required to access our
  1740. 1:14:01Azure Data Lake Storage. Below that, we
  1741. 1:14:04will
  1742. 1:14:05we will read our
  1743. 1:14:06data. We have already created our
  1744. 1:14:09application in Microsoft Entra ID. We We
  1745. 1:14:13have also assigned the required
  1746. 1:14:15permission to our storage account. Now,
  1747. 1:14:18we need to configure a Databricks to
  1748. 1:14:20authenticate using the application
  1749. 1:14:22identity. For this, we will be using the
  1750. 1:14:25auth authentication mechanism supported
  1751. 1:14:28by the our Azure Data Lake Storage Gen2.
  1752. 1:14:31Rather than the Rather than writing the
  1753. 1:14:34configuration entirely from memory, we
  1754. 1:14:37can refer to the official Microsoft
  1755. 1:14:39documentation. I will open in another
  1756. 1:14:42tab and will search for it. Connect
  1757. 1:14:45Azure Databricks to Azure Data Lake
  1758. 1:14:48Storage Gen2 using a service principle.
  1759. 1:14:51From the Microsoft documentation, we can
  1760. 1:14:54find the configuration required to
  1761. 1:14:56authenticate using OAuth.
  1762. 1:14:59I will
  1763. 1:15:00locate the service principle
  1764. 1:15:02authenticate authentication example. The
  1765. 1:15:05configuration uses a spark setting to
  1766. 1:15:08specify the authentication type OAuth
  1767. 1:15:11provider client ID, client secret, and
  1768. 1:15:13token endpoint.
  1769. 1:15:15I will copy the relevant example in our
  1770. 1:15:18own notebook.
  1771. 1:15:20Uh [snorts] don't worry about this code.
  1772. 1:15:23Once you are familiar with
  1773. 1:15:25all this stuff, you will automatically
  1774. 1:15:28remember all this required code. So, you
  1775. 1:15:31don't have to entirely
  1776. 1:15:34by heart all this code.
  1777. 1:15:37Now, before executing the code, we need
  1778. 1:15:39to replace the placeholder values with
  1779. 1:15:41our own configuration. The first value
  1780. 1:15:44is the storage account name. I will
  1781. 1:15:47return to the Azure portal and copy the
  1782. 1:15:50name of our storage account. Now, I will
  1783. 1:15:52replace the storage account placeholder
  1784. 1:15:55in the configuration.
  1785. 1:15:57We need to make sure that storage
  1786. 1:15:58account name is correct everywhere it
  1787. 1:16:01appears.
  1788. 1:16:02Next, we have a application ID. I will
  1789. 1:16:05use a client ID from the application
  1790. 1:16:07registration we have created earlier.
  1791. 1:16:10Then, we need a tenant ID. I will copy
  1792. 1:16:13the directory tenant ID from our
  1793. 1:16:17Microsoft Entra ID. This will be used to
  1794. 1:16:21construct OAuth token endpoint. Finally,
  1795. 1:16:24we need to
  1796. 1:16:25copy client secret. For this demonstra-
  1797. 1:16:28demonstration, the configuration expects
  1798. 1:16:31the client secret value that we
  1799. 1:16:33generated earlier. However, instead of
  1800. 1:16:37placing the secret directly into our
  1801. 1:16:39notebook, the recommended approach is to
  1802. 1:16:42retrieve it securely using the
  1803. 1:16:44Databricks secret scope or another
  1804. 1:16:47supported secret management mechanism.
  1805. 1:16:50This
  1806. 1:16:52This will keep sensitive credential out
  1807. 1:16:54of the notebook source code. Now, let's
  1808. 1:16:57understand what each configuration
  1809. 1:17:00property does. The first property
  1810. 1:17:03specifies the authentication type. We
  1811. 1:17:06are using OAuth because we want to
  1812. 1:17:09authenticate through Microsoft Entra ID.
  1813. 1:17:12The second property identifies the OAuth
  1814. 1:17:16provider. The third property provide
  1815. 1:17:19provides our application client ID. And
  1816. 1:17:22the fourth property supplies the client
  1817. 1:17:24secret use used for our authentication.
  1818. 1:17:29And the final property specify the OAuth
  1819. 1:17:33token endpoint associated with our
  1820. 1:17:35Microsoft Entra tenant.
  1821. 1:17:37Together, these setting allows Spark to
  1822. 1:17:40authenticate when accessing files stored
  1823. 1:17:43in our Azure storage
  1824. 1:17:46Azure Data Lake storage account.
  1825. 1:17:49Once the configuration is complete, we
  1826. 1:17:51can execute the cell.
  1827. 1:17:53If the credential and the permission are
  1828. 1:17:56configured correctly, Databricks will be
  1829. 1:17:58able to authenticate to the storage
  1830. 1:18:00account. Of course,
  1831. 1:18:02configuration authentication is only the
  1832. 1:18:05first part.
  1833. 1:18:06We We should also verify that we have
  1834. 1:18:10actually accessed the data. In the next
  1835. 1:18:13step, we will be reading the file from
  1836. 1:18:15our bronze container and confirm that
  1837. 1:18:18the connection is working.
  1838. 1:18:21After that, we will
  1839. 1:18:22begin loading the data into the Spark
  1840. 1:18:25data frame and move towards the our
  1841. 1:18:28silver layer transformation.
  1842. 1:18:30Now that we have configured the storage
  1843. 1:18:33access, let's start working with our
  1844. 1:18:35Databricks.
  1845. 1:18:36As you remember in a first phase of our
  1846. 1:18:39project, we use a data factory to ingest
  1847. 1:18:42multiple CSV file into our bronze layer.
  1848. 1:18:45Uh
  1849. 1:18:46now, uh we will be using a PySpark to
  1850. 1:18:49read those file into data bricks,
  1851. 1:18:51explore the data, and prepare it for our
  1852. 1:18:53upcoming transformation.
  1853. 1:18:55Let's start with the category data set.
  1854. 1:18:58I will create a new Python cell under
  1855. 1:19:00the data loading section. To read the
  1856. 1:19:02CSV file, we will be using a spark.read.
  1857. 1:19:06Now, one important thing, there is a
  1858. 1:19:08file there is the file path. Since our
  1859. 1:19:10data is stored in a Azure Data Lake
  1860. 1:19:13Storage Gen2, we will be using a ABFSS
  1861. 1:19:17protocol to access it. The path includes
  1862. 1:19:20the container name, storage account
  1863. 1:19:22name, and the location of our file. I
  1864. 1:19:24will be
  1865. 1:19:25providing the path to our category CSV
  1866. 1:19:29file.
  1867. 1:19:30We will store the result in a data frame
  1868. 1:19:32called df_category.
  1869. 1:19:35A data frame is basically a collection
  1870. 1:19:37of a data organized into a row and
  1871. 1:19:39columns, similar to our database tables,
  1872. 1:19:43but designed for a distributed cup
  1873. 1:19:45processing using a Apache Spark. Now,
  1874. 1:19:48let's execute the code. Once you have
  1875. 1:19:51executed, you can see we have
  1876. 1:19:53encountered an error while executing the
  1877. 1:19:56cell. This is quite common when working
  1878. 1:19:59with our data bricks, especially when we
  1879. 1:20:01are reading a file from external
  1880. 1:20:03storage. Whenever you encounter an error
  1881. 1:20:07message, uh the first thing you should
  1882. 1:20:09do is check error message carefully. It
  1883. 1:20:12usually gives us a indication of what
  1884. 1:20:15went wrong. In our case, let's review
  1885. 1:20:18the code and then configure the what we
  1886. 1:20:21have provided. I will make the required
  1887. 1:20:23changes and execute the cell again. Now,
  1888. 1:20:26our data frame has been created
  1889. 1:20:28successfully. One thing worth
  1890. 1:20:30understanding here is that Spark uses a
  1891. 1:20:32lazy evolution.
  1892. 1:20:35This means that we when we define a data
  1893. 1:20:38frame, Spark doesn't necessarily process
  1894. 1:20:40all the data immediately. Instead, it
  1895. 1:20:43prepares the execution plan and the
  1896. 1:20:45actual processing happens when we
  1897. 1:20:48trigger the action.
  1898. 1:20:50We will understand this concept in more
  1899. 1:20:52detail when we start working with a
  1900. 1:20:54transformation.
  1901. 1:20:55For now, let's verify that our data has
  1902. 1:20:58been loaded correctly. For that, I will
  1903. 1:21:01be using display function. This
  1904. 1:21:03functions allow us to view the content
  1905. 1:21:06of our data frame directly inside the
  1906. 1:21:08Databricks notebook. Let's execute it
  1907. 1:21:12and here we can see our category data.
  1908. 1:21:14We have the category ID and category
  1909. 1:21:17name columns along with their
  1910. 1:21:18corresponding records. This confirms
  1911. 1:21:21that
  1912. 1:21:22we have able to access the CSV file from
  1913. 1:21:26our Azure Data Lake storage and read in
  1914. 1:21:28it it into Spark data frame. Now, let's
  1915. 1:21:32look at the something important. When we
  1916. 1:21:35read the CSV file, Spark provides
  1917. 1:21:37several options that helps us to control
  1918. 1:21:39how the data is loaded. For example, we
  1919. 1:21:42can specify whether first row contain a
  1920. 1:21:45column names, whether Spark should
  1921. 1:21:47automatically identify the data types.
  1922. 1:21:50Let's update our code and include those
  1923. 1:21:53option. First, we will be using a header
  1924. 1:21:56option by setting header equals to true.
  1925. 1:21:59We are telling Spark that first row of
  1926. 1:22:01our CSV file contains column name. Other
  1927. 1:22:05Otherwise,
  1928. 1:22:06Spark may assign default column names
  1929. 1:22:08such as _c0,
  1930. 1:22:10_c1 and so on. Next, we will be using a
  1931. 1:22:14infer schema. By setting infer schema to
  1932. 1:22:18true, Spark will
  1933. 1:22:19examine the data and attempt to identify
  1934. 1:22:23the appropriate data types. For example,
  1935. 1:22:25if a column contains a numeric value,
  1936. 1:22:28Spark may recognize it as a integer
  1937. 1:22:31rather than treating
  1938. 1:22:32everything as a string. These options
  1939. 1:22:35are very useful when we are explore
  1940. 1:22:38exploring the source data. In a
  1941. 1:22:40production pipeline, we often define the
  1942. 1:22:43schema explicitly to maintain
  1943. 1:22:45consistency and avoid unnecessary schema
  1944. 1:22:48inference.
  1945. 1:22:49Now, let's execute the updated code. I
  1946. 1:22:52will display the data frame again to
  1947. 1:22:54verify the output. As you can see, our
  1948. 1:22:57category data is available in a
  1949. 1:22:59structured format. So, we have
  1950. 1:23:01successfully loaded our first data set.
  1951. 1:23:04Now, let's move on to the next step.
  1952. 1:23:06That is we will be reading multiple
  1953. 1:23:08files in from our bronze layer and we
  1954. 1:23:11need to load them into Databricks before
  1955. 1:23:14we can start applying any
  1956. 1:23:15transformation. The good thing is that
  1957. 1:23:18we don't need to learn completely
  1958. 1:23:20different approach for every file. We
  1959. 1:23:23will be following same pattern. I will
  1960. 1:23:25create another Python cell and I will
  1961. 1:23:28use a spark.
  1962. 1:23:29read again. This time I will update the
  1963. 1:23:32data frame name and provide the path to
  1964. 1:23:35to our exact CSV file. The [snorts]
  1965. 1:23:38remaining configuration stay same. We
  1966. 1:23:41will specify the file format, enable the
  1967. 1:23:44required header option, and provide the
  1968. 1:23:47source path. Now, let's execute the
  1969. 1:23:50cell. Once the data frame is created, we
  1970. 1:23:52can use a display function to inspect
  1971. 1:23:55the record. I will repeat this process
  1972. 1:23:58for another data sets.
  1973. 1:24:05We would check the column names, data
  1974. 1:24:07types, and sample record. This This
  1975. 1:24:10helps us to identify a potential issue
  1976. 1:24:12early in the process. For example, we
  1977. 1:24:15might find a missing value, incorrect
  1978. 1:24:17data types, and inconsistent column
  1979. 1:24:19names. These are the kinds of issue we
  1980. 1:24:22will be addressing when we start
  1981. 1:24:23building our silver layer. For now, we
  1982. 1:24:26are just exploring the data and
  1983. 1:24:28confirming that the files have been
  1984. 1:24:31loaded correctly.
  1985. 1:24:33And as you can see, we are able to read
  1986. 1:24:36the data set directly from our Azure
  1987. 1:24:38Data Lake storage using a PySpark. Now
  1988. 1:24:41that we have loaded our data set into
  1989. 1:24:43Data Bricks, let's start working on a
  1990. 1:24:45transformation part.
  1991. 1:24:47In this section, we are going to use a
  1992. 1:24:49PySpark to transform our existing data
  1993. 1:24:52frame and prepare them for the silver
  1994. 1:24:54layer.
  1995. 1:24:55Before that, let's read all the columns
  1996. 1:24:58of our data frame. And for that, I will
  1997. 1:25:01be using a data frame.columns
  1998. 1:25:03to check our columns available in our
  1999. 1:25:06data frame. The purpose of silver layer
  2000. 1:25:09is to take the raw data that we have
  2001. 1:25:11already ingested and make it more
  2002. 1:25:13consistent and useful for further
  2003. 1:25:16processing. For example, we might need
  2004. 1:25:18to rename the columns, convert data
  2005. 1:25:20types, standardize the text value, or
  2006. 1:25:23select only the columns required for our
  2007. 1:25:25analysis. And that's what exactly we are
  2008. 1:25:28going to do here. First, I'm going to
  2009. 1:25:30import the PySpark function that we will
  2010. 1:25:33be using for transformation. Instead of
  2011. 1:25:37writing everything from scratch, PySpark
  2012. 1:25:40provides several built-in functions that
  2013. 1:25:42make it easier to manipulate data
  2014. 1:25:44frames. We will be using a function such
  2015. 1:25:47as col or alias and a few other
  2016. 1:25:50functions as we move through the
  2017. 1:25:52different data set. Now, let's start
  2018. 1:25:55with our category data set. I'm going to
  2019. 1:25:57create a new data frame for the
  2020. 1:25:59transform category data. Notice that we
  2021. 1:26:02have not directly modified our original
  2022. 1:26:04data frame. Instead, we are creating a
  2023. 1:26:07separate data frame to store our
  2024. 1:26:09transformation result. This is very
  2025. 1:26:11useful because our original data set
  2026. 1:26:14remains available if we need to compare
  2027. 1:26:17values or apply the different
  2028. 1:26:19transformation later.
  2029. 1:26:21Here I'm creating a new data frame
  2030. 1:26:23called silver underscore category using
  2031. 1:26:26our existing data df_category data
  2032. 1:26:29frame. The first transformation we are
  2033. 1:26:31applying is drop duplicates. We are
  2034. 1:26:34using a category underscore ID as a key
  2035. 1:26:37to identify duplicate records. This
  2036. 1:26:39means that if multiple records have the
  2037. 1:26:41same category ID, Spark will retain only
  2038. 1:26:44one of them. Next we are applying a
  2039. 1:26:47filter function. Here we are checking
  2040. 1:26:49whether category underscore ID is not
  2041. 1:26:51null. This is very important because the
  2042. 1:26:54category ID is a key identifier in our
  2043. 1:26:58data set and we don't want to records
  2044. 1:27:00with a missing category IDs in our clean
  2045. 1:27:03data. After that, we are using with
  2046. 1:27:05column along with the trim function. The
  2047. 1:27:08trim function removes any unnecessary
  2048. 1:27:10leading or trailing spaces from the
  2049. 1:27:13category underscore name column. For
  2050. 1:27:15example, if a category name contains a
  2051. 1:27:17extra space before or after the actual
  2052. 1:27:20text, this transformation will remove
  2053. 1:27:22those spaces and standardize the value.
  2054. 1:27:25We are also chaining these
  2055. 1:27:27transformation together, meaning we can
  2056. 1:27:30apply multiple cleaning operation within
  2057. 1:27:32a single data frame expression. So with
  2058. 1:27:35these three operation, we are removing
  2059. 1:27:37duplicate category IDs, filtering out
  2060. 1:27:40records with the missing IDs, and
  2061. 1:27:42cleaning unnecessary spaces from
  2062. 1:27:44category names. Now,
  2063. 1:27:46when I executed the cell, you can see
  2064. 1:27:48that Databricks showing some error. So
  2065. 1:27:51there is a error in my code, so I will
  2066. 1:27:54correct it and execute it again. This
  2067. 1:27:58time transformation should work.
  2068. 1:28:00Notice that we have only corrected the
  2069. 1:28:03problem in our transformation logic. We
  2070. 1:28:06we haven't changed any underlying source
  2071. 1:28:08data. Now that our category
  2072. 1:28:10transformation is working, let's move on
  2073. 1:28:13to the next step. We have created our
  2074. 1:28:15transform category data frame, but at
  2075. 1:28:18the moment the transformation result is
  2076. 1:28:20available through our data bricks
  2077. 1:28:22notebook. We also want to save this
  2078. 1:28:25result in Azure data lake storage, so it
  2079. 1:28:28can be used by another process.
  2080. 1:28:31For that, we are going to use a data
  2081. 1:28:33frame write operation. Here, I will take
  2082. 1:28:36our transform
  2083. 1:28:37transform category data frame and call a
  2084. 1:28:40write method. Next, I will specify the
  2085. 1:28:43output format. For this project, we are
  2086. 1:28:46using a parquet.
  2087. 1:28:48Parquet is a columnar file format that's
  2088. 1:28:51commonly used in the data engineering
  2089. 1:28:53and analysis workload. Unlike a
  2090. 1:28:55traditional CSV file, which stores data
  2091. 1:28:58row by row, parquet are organized data
  2092. 1:29:00by columns. This allows us processing
  2093. 1:29:04engine such as Spark to read only the
  2094. 1:29:06columns required for particular
  2095. 1:29:08operation.
  2096. 1:29:09Parquet also
  2097. 1:29:11supports efficient compression, which
  2098. 1:29:13can reduce the storage requirement.
  2099. 1:29:16Now, let's specify the destination of
  2100. 1:29:19the file. Here, we are writing the
  2101. 1:29:22transform data into our silver container
  2102. 1:29:24in our Azure data lake storage account.
  2103. 1:29:27I will also specify the write mode. The
  2104. 1:29:30write mode controls what happens if data
  2105. 1:29:33already exists at the destination. For
  2106. 1:29:36example, with a overwrite mode, Spark
  2107. 1:29:39Spark replace the existing data under
  2108. 1:29:41specify output location.
  2109. 1:29:44We should use this carefully because it
  2110. 1:29:46can remove existing files for from the
  2111. 1:29:49destination. Now, let's execute the
  2112. 1:29:52cell. The operation
  2113. 1:29:55completed successfully, so our transform
  2114. 1:29:57category data set has now been
  2115. 1:30:00written to silver layer.
  2116. 1:30:02But instead of assuming everything work,
  2117. 1:30:04let's verify the output. I will to our
  2118. 1:30:07Azure portal and I'm going to open a
  2119. 1:30:10storage accounts. Here you can see my
  2120. 1:30:14silver container and in that you can see
  2121. 1:30:16the output folder. Now let's back to
  2122. 1:30:19back in our data bricks.
  2123. 1:30:21Now I'm going to add another section for
  2124. 1:30:24the next data set.
  2125. 1:30:26Here I will be following the similar
  2126. 1:30:28approach. Now let's move to our product
  2127. 1:30:31data set.
  2128. 1:30:32Before we start transforming our product
  2129. 1:30:34data set, we will need a PySpark to
  2130. 1:30:37underscore data function to convert our
  2131. 1:30:39date column into correct format. So
  2132. 1:30:42let's first import to underscore date
  2133. 1:30:44from PySpark.sql.functions.
  2134. 1:30:47Now let's move on to our product data
  2135. 1:30:49set. Here I'm creating a new data frame
  2136. 1:30:51called silver_products
  2137. 1:30:54using our existing df_products data
  2138. 1:30:57frame. Unlike the category data set, our
  2139. 1:30:59product data data set require a few
  2140. 1:31:02additional transformation. First, I will
  2141. 1:31:05be using with column rename to
  2142. 1:31:07standardize the column names. As you can
  2143. 1:31:09see the original column name contains a
  2144. 1:31:12upper case letters, so we are converting
  2145. 1:31:14them into a lower case names with the
  2146. 1:31:16underscores. For example, product_id
  2147. 1:31:20becomes product_id
  2148. 1:31:22in a smaller case.
  2149. 1:31:24And likewise, we are applying a same
  2150. 1:31:27naming convention to launch underscore
  2151. 1:31:29data and price. This helps us to
  2152. 1:31:31maintain consistency. Next, we are
  2153. 1:31:34converting the launch date column into a
  2154. 1:31:36correct data type. In our source data,
  2155. 1:31:39the date is stored as a string and so
  2156. 1:31:43I'm using a PySpark to underscore date
  2157. 1:31:45function to specify the format as This
  2158. 1:31:48converts the string values
  2159. 1:31:52into a proper date values, allowing us
  2160. 1:31:55to perform date base filtering and
  2161. 1:31:57calculations later. After that, we are
  2162. 1:32:00converting price column into a decimal
  2163. 1:32:02data type. I'm using a cast with a
  2164. 1:32:05decimal 10,2.
  2165. 1:32:07This means that the columns can store up
  2166. 1:32:10to 10 digit in total with a two digits
  2167. 1:32:12after the decimal points. Using a
  2168. 1:32:15decimal data type is particularly useful
  2169. 1:32:17for monetary values because it provides
  2170. 1:32:20fixed precision representation unlike
  2171. 1:32:23floating point types. Notice that we are
  2172. 1:32:26chaining all these transformation
  2173. 1:32:27together using a withColumnRenamed and
  2174. 1:32:30withColumn. This allows us to
  2175. 1:32:32standardize the column names and convert
  2176. 1:32:34the required data types within the
  2177. 1:32:36single transformation. Finally, we are
  2178. 1:32:39storing the transformation result in our
  2179. 1:32:41new data frame silver_products.
  2180. 1:32:44Now, let's execute the cell. As you can
  2181. 1:32:46see the transformation completed
  2182. 1:32:48successfully. Our product data set now
  2183. 1:32:52has a consistent column names, properly
  2184. 1:32:54formatted launch date, and decimal data
  2185. 1:32:57type for the price column. Next, we will
  2186. 1:33:00be writing this transformation into our
  2187. 1:33:02parquet format into a silver layer like
  2188. 1:33:05just we did for the category data set.
  2189. 1:33:07Now, let's move to our sales data set. I
  2190. 1:33:10have pasted the transformation code, so
  2191. 1:33:13let's go through the what we are doing.
  2192. 1:33:15First, we are creating a data frame
  2193. 1:33:17called silver_sales
  2194. 1:33:19using existing df_sales data frame. The
  2195. 1:33:23first transformation uses a withColumn
  2196. 1:33:25along with a to_date to convert
  2197. 1:33:27sales_date
  2198. 1:33:29column into a proper date data type.
  2199. 1:33:32This is important because we will be
  2200. 1:33:34using a sales date for further analysis.
  2201. 1:33:37Next, we are applying a filter function
  2202. 1:33:39to to the quantity column. Here, we are
  2203. 1:33:42keeping only records where the quantity
  2204. 1:33:44is greater than zero. This helps us to
  2205. 1:33:47exclude records containing zero or a
  2206. 1:33:49negative quantities.
  2207. 1:33:51After that, we are using a drop
  2208. 1:33:53duplicates on a sales_id column. So,
  2209. 1:33:56with this three transformation, we are
  2210. 1:33:58converting sales date, filtering out
  2211. 1:34:00invalid quantities, and removing
  2212. 1:34:02duplicate sales IDs. Now, let's execute
  2213. 1:34:05the sales. Our clean sales data frame is
  2214. 1:34:09ready. Next, we are going to enrich our
  2215. 1:34:11sales data set with information from our
  2216. 1:34:14product data set. I have pasted the
  2217. 1:34:17next transformation code, so let's
  2218. 1:34:19understand how it works. Here, we are
  2219. 1:34:22taking our existing silver underscore
  2220. 1:34:24sales data frame and joining it with a
  2221. 1:34:27silver underscore products.
  2222. 1:34:29From the product data frame, we are
  2223. 1:34:31selecting only two columns, product
  2224. 1:34:33underscore ID and price. We don't need
  2225. 1:34:36all the product information for this
  2226. 1:34:38transformation. We only need a product
  2227. 1:34:40ID to establish relationship and the
  2228. 1:34:43price to calculate the sales amount. We
  2229. 1:34:46are using a inner join on a product
  2230. 1:34:48underscore ID. This means that Spark
  2231. 1:34:51will retain only the sales record that
  2232. 1:34:53have matched product ID in this product
  2233. 1:34:56data set. Once the join is complete, we
  2234. 1:34:58will have the product price available
  2235. 1:35:00along with the sales information. Next,
  2236. 1:35:03we are creating a new column called a
  2237. 1:35:06total underscore amount. We are using a
  2238. 1:35:09with column to multiply the quantity by
  2239. 1:35:11price.
  2240. 1:35:13This
  2241. 1:35:13This calculation gives us the sales
  2242. 1:35:15value for each transaction. Next, we are
  2243. 1:35:18creating a two additional columns, sales
  2244. 1:35:20underscore uh year and sale underscore
  2245. 1:35:23month. For this, we are using a PySpark
  2246. 1:35:26year and month function. This function
  2247. 1:35:29allow us to extract year and month
  2248. 1:35:31[clears throat] from a sale date column.
  2249. 1:35:33So, let's import these two functions.
  2250. 1:35:36Once we have completed the
  2251. 1:35:37transformation, we will be again writing
  2252. 1:35:40this transformation into our silver
  2253. 1:35:42layer.
  2254. 1:35:46Now, let's move on to our stores data
  2255. 1:35:49set. I have already pasted the
  2256. 1:35:51transformation code here, so let's
  2257. 1:35:53quickly go through it. We are creating a
  2258. 1:35:56new data frame called silver underscore
  2259. 1:35:58store where we are using a existing DF
  2260. 1:36:01underscore stores data frame.
  2261. 1:36:04We are using a width column rename to
  2262. 1:36:06standardize column names. Next, we are
  2263. 1:36:09using a drop duplicates. This will
  2264. 1:36:12ensure that we retain only one record
  2265. 1:36:14for each store ID. Now, let's execute
  2266. 1:36:17this cell. Next, we will write the
  2267. 1:36:19silver underscore stores data frame to
  2268. 1:36:21our silver container in a parquet format
  2269. 1:36:24using a append
  2270. 1:36:26mode.
  2271. 1:36:28Finally, let's move on to our warranty
  2272. 1:36:31data set. Before executing this
  2273. 1:36:33transformation, we need one additional
  2274. 1:36:35PySpark function called upper. So, let's
  2275. 1:36:38go to our import section and import
  2276. 1:36:41upper from PySpark.sql.functions.
  2277. 1:36:45Now, let's return to our warranty
  2278. 1:36:47transformation. I have already pasted
  2279. 1:36:50the code and let's see what it does. We
  2280. 1:36:53are creating a new data frame called a
  2281. 1:36:55silver underscore warranty using our
  2282. 1:36:57existing DF underscore warranty data
  2283. 1:37:00frame. The first one uses a to
  2284. 1:37:02underscore date to convert the claim
  2285. 1:37:05date. Then, we are using a upper to
  2286. 1:37:07convert the values in the repair status
  2287. 1:37:10column into a upper case. This will help
  2288. 1:37:12us to standardize the repair status
  2289. 1:37:15values and maintain consistency across
  2290. 1:37:17the data set.
  2291. 1:37:19Now, let's execute this cell. As you can
  2292. 1:37:22see, the our warranty transformation is
  2293. 1:37:24completed and let's write this
  2294. 1:37:26transformation also into our silver
  2295. 1:37:29layer. Now that we have completed our
  2296. 1:37:31transformation, let's examine the result
  2297. 1:37:34more closely. I will be using a display
  2298. 1:37:36function.
  2299. 1:37:38The Databricks provides an interactive
  2300. 1:37:40table view for displaying the data
  2301. 1:37:42frames. This makes it convenient to
  2302. 1:37:45inspect the records without having
  2303. 1:37:47export the data into another
  2304. 1:37:49application. Now, let's move on to the
  2305. 1:37:52next operation. Here we are using a
  2306. 1:37:55group by operation to summarize our data
  2307. 1:37:57set. Instead of examining every
  2308. 1:38:00individual record, we want to calculate
  2309. 1:38:02the aggregate result. For that, I will
  2310. 1:38:04be using a group by function. Group by
  2311. 1:38:07function groups records that have the
  2312. 1:38:10same value in the selected columns. We
  2313. 1:38:12can apply the aggregation to calculate
  2314. 1:38:15and summary for each group. Let's
  2315. 1:38:18execute the cell. Now, let's visualize
  2316. 1:38:21this aggregated result. One useful
  2317. 1:38:23feature of Databricks is that we can
  2318. 1:38:26create a charts directly from the output
  2319. 1:38:28of our notebook cell. We don't need to
  2320. 1:38:31move data into a separate reporting tool
  2321. 1:38:33just to create a quick visualization.
  2322. 1:38:36Here I will be opening a visualization
  2323. 1:38:39options. Now, let's select the options
  2324. 1:38:41to create a visualization. This opens
  2325. 1:38:44the visualization editor. On the left
  2326. 1:38:46side, we can configure the chart. On on
  2327. 1:38:49the right side, the Databricks will
  2328. 1:38:50display a preview. Let's start with a
  2329. 1:38:53bar chart. I will select the columns
  2330. 1:38:55that represent in our group. Then I will
  2331. 1:38:58select the numeric column that we want
  2332. 1:39:00to visualize. Notice that the chart
  2333. 1:39:02updates based on the selected columns.
  2334. 1:39:05Here we can compare the values across
  2335. 1:39:07the different groups. A bar chart is
  2336. 1:39:09very useful when we want to compare a
  2337. 1:39:11quantity across the categories. For
  2338. 1:39:14example, if we have a several groups and
  2339. 1:39:16want to identify which group has the
  2340. 1:39:18highest or lowest value, a bar chart
  2341. 1:39:21makes the comparison easier.
  2342. 1:39:23Now, let's examine the chart. We can
  2343. 1:39:26move the pointer over the bars and
  2344. 1:39:28inspect the corresponding values. This
  2345. 1:39:31gives us a quick way to explore our
  2346. 1:39:33aggregated data. Now, let's try another
  2347. 1:39:36visual type. I will open the
  2348. 1:39:38visualization type drop down. Here
  2349. 1:39:40Databricks provide us several options.
  2350. 1:39:43Let's select a line chart. Notice that
  2351. 1:39:45the same aggregated data is now
  2352. 1:39:47displayed as a line. The underlying data
  2353. 1:39:51frame hasn't changed. We are only
  2354. 1:39:54changing the way of the result as
  2355. 1:39:56represented. Line charts are commonly
  2356. 1:39:59used when we want to examine changes
  2357. 1:40:01across an ordered sequence, particularly
  2358. 1:40:04over the time. However, for order and
  2359. 1:40:07order categories, a bar chart is usually
  2360. 1:40:10easier to interpret. In this example, we
  2361. 1:40:13are exploring the visualization option
  2362. 1:40:15available in data bricks. Now, let's
  2363. 1:40:18look at the another chart type. Next, I
  2364. 1:40:20will open the visualization type
  2365. 1:40:22drop-down again. This time, I will be
  2366. 1:40:25selecting a pie chart. As you can see,
  2367. 1:40:27data bricks display the result using a
  2368. 1:40:29different color segment. Each segment
  2369. 1:40:32represent a group in our aggregated
  2370. 1:40:35data. The size of each data set or
  2371. 1:40:38segment is based on the corresponding
  2372. 1:40:40value. Here, the chart is displayed in a
  2373. 1:40:43donut style layout. This makes it easier
  2374. 1:40:46to see the relative distribution of a
  2375. 1:40:49value across the groups. We can also see
  2376. 1:40:52the legends on the right side. The
  2377. 1:40:54legend identifies the groups represented
  2378. 1:40:57by the different colors. Now, let's look
  2379. 1:41:00at the percentage displayed on the
  2380. 1:41:02chart. This percentage helps us to
  2381. 1:41:05understand how much each group is
  2382. 1:41:06contributing to our total. This type of
  2383. 1:41:09visualization is very important when we
  2384. 1:41:12want to compare the relative proportions
  2385. 1:41:15of small number of categories. One thing
  2386. 1:41:18to keep in mind that pie charts become
  2387. 1:41:20harder to read when we have too many
  2388. 1:41:22categories. For larger number of groups,
  2389. 1:41:25a bar chart is generally a better
  2390. 1:41:26choice.
  2391. 1:41:28Now, let's review the chart setting.
  2392. 1:41:31Here, we can configure the column used
  2393. 1:41:33by the visualization and I adjust the
  2394. 1:41:36available display options.
  2395. 1:41:38Once we are satisfied with the
  2396. 1:41:41visualization, we can save it. Now,
  2397. 1:41:43let's return to our notebook.
  2398. 1:41:46Back in our notebook, we can see the
  2399. 1:41:48aggregated results again. Notice that
  2400. 1:41:51the output is still available in tabular
  2401. 1:41:54format. This is very useful because the
  2402. 1:41:57same data frame results can be explored
  2403. 1:41:59in different ways. We can expect the
  2404. 1:42:02actual values in the table and we can
  2405. 1:42:05and create a visualization to understand
  2406. 1:42:08the distribution more quickly. Now,
  2407. 1:42:10let's continue with another data set. I
  2408. 1:42:13will be moving to the next session of
  2409. 1:42:15the notebook. Here, we are going to
  2410. 1:42:17inspect us our sales-related data set.
  2411. 1:42:20Again, I will be using a group by
  2412. 1:42:22function and I will be doing a some
  2413. 1:42:25visualization.
  2414. 1:42:27You can play with it and you can check a
  2415. 1:42:30result as per your need. Now, let's go
  2416. 1:42:33back to our notebook. We can see the
  2417. 1:42:36aggregated result. After inspecting the
  2418. 1:42:39transformed data frames and perform
  2419. 1:42:41aggregation to summarize data, finally
  2420. 1:42:44we use the data bricks visualization to
  2421. 1:42:46explore the aggregated result using a
  2422. 1:42:49bar chart, line charts, and donut
  2423. 1:42:52charts. So, this completes our silver
  2424. 1:42:54layer transformation and data
  2425. 1:42:56exploration section demonstrated in our
  2426. 1:42:59notebook.
  2427. 1:43:00And with that, we have reached the end
  2428. 1:43:02of our Azure Data Engineering project.
  2429. 1:43:05Throughout this tutorial, we have built
  2430. 1:43:07a data pipeline using Azure Data
  2431. 1:43:09Factory, Azure Data Lake Storage Gen2,
  2432. 1:43:12and Azure Data Bricks. We We started by
  2433. 1:43:15ingesting our source file into Azure
  2434. 1:43:18Data Factory and storing raw data into a
  2435. 1:43:20bronze layer. Next, we configured the
  2436. 1:43:23connection between Azure Data Bricks and
  2437. 1:43:25Azure Data Lake Storage. Then, using
  2438. 1:43:28PySpark, we performed several
  2439. 1:43:30transformation including removing
  2440. 1:43:32duplicates, handling missing values,
  2441. 1:43:34standardizing the column names,
  2442. 1:43:36converting data types, and enriching our
  2443. 1:43:38data sets. Finally, we store our
  2444. 1:43:41transformed data into a silver layer
  2445. 1:43:43using a parquet format. So, we have
  2446. 1:43:45successfully implemented the data
  2447. 1:43:47ingestion, storage, and transformation
  2448. 1:43:50stages of our Azure data engineering
  2449. 1:43:52pipeline.
  2450. 1:43:53In a larger production architecture, we
  2451. 1:43:56could explain this solution with a
  2452. 1:43:58serving layer using the Azure Synapse
  2453. 1:44:01Analytics and reporting through Power
  2454. 1:44:03BI. However, those components are
  2455. 1:44:06outside the scope of this tutorial. I
  2456. 1:44:08hope this tutorial help you understand
  2457. 1:44:11how these Azure services work together
  2458. 1:44:14in a practical data engineering project.
  2459. 1:44:17If you found this video helpful, don't
  2460. 1:44:19forget to like, subscribe, and share it.
  2461. 1:44:23Thanks for watching, and I will see you
  2462. 1:44:25in the next video.

About this transcript

This page contains the full transcript of End-to-End Azure Data Engineering Project | Build a Complete Data Pipeline from Scratch by Tech with Amol, generated from the public captions YouTube serves with the video. The transcript has 14,259 words across 2,462 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.

What you can do with it

Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.

Free YouTube transcript tool

YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.