<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>data engineering on Digi Hunch</title><link>https://static.digihunch.com/tag/data-engineering/</link><description>Recent content in data engineering on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Sat, 20 Jul 2024 16:51:03 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/data-engineering/index.xml" rel="self" type="application/rss+xml"/><item><title>Intro to Data Analytics Platform on Azure</title><link>https://static.digihunch.com/2021/03/intro-to-data-analytics-platform/</link><pubDate>Sun, 21 Mar 2021 21:57:00 -0400</pubDate><guid>https://static.digihunch.com/2021/03/intro-to-data-analytics-platform/</guid><description>&lt;p class="wp-block-paragraph"&gt;Having been in transactional data world for almost the entire career, recently I have to pick up quite a few things to catch up on the analytical workload. The main purpose of data analytics project is to build analysis services models and manage deployed databases. Later in this post I&amp;#8217;ll discuss some useful Azure resources for data analytics.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-data-model"&gt;Data Model&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Data are typically organized in relational model for better transactional performance, following the normalization forms. The relational model, however, might not be the most appropriate schema for analytics. In this case, it is better to use a separate non-relational repositories that can store information in a format that better aligns with its semantics, and hence more friendly to analytical applications.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A model consists of: data sources, tables, relationships, measures, KPIs, roles, etc. The model can be deployed to analysis database (e.g. SSAS). When deploying, queries (from source) and calculations are done. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Data modelling is the process of determining how your tables are related to each other. This process is done by defining and creating relationships between the tables. From that point, you can enhance the model by defining metrics and adding custom calculations to enrich your data. Creating an effective and proper data model is a critical step in helping organizations understand and gain valuable insights into the data.&amp;nbsp;The model is another critical component that has a direct effect on the performance of your report and overall data analysis. The process of preparing data and modelling data is an iterative process.&amp;nbsp;&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-data-warehouse"&gt;Data Warehouse&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Moreover, organizations have multiple data stores, with varying formats and different structures such as live stream, sensor, etc. They all need to be combined to generate insights. The process of combining all of the local data source is known as data warehousing. The process of analyzing streaming data and data from the Internet is known as Big Data Analytics.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A data warehouse gathers data from many sources within an organizations. This data is then used as the source for analysis, reporting and OLAP. The focus of a data warehouse is to provide answers to complex queries. A modern data warehouse might contain a mixture of relational and non-relational data, including files, social media streams, IoT sensor data.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-warehouse/media/sql-data-warehouse-overview-what-is/data-warehouse-solution.png" alt="Data warehouse solution"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The diagram above is platform neutral. If you take Azure for example, a typical data warehouse platform involves the following components:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Azure Data Factory: ingestion of data (integration service)&lt;/li&gt;&lt;li&gt;Azure Data Lake Storage: store large quantity of data before analyzing&lt;/li&gt;&lt;li&gt;Azure Databricks: other forms of data preparation (transformation, cleaning) by Spark&lt;/li&gt;&lt;li&gt;Azure Synapse Analytics: store cleansed data, for Azure Analysis Service to consume&lt;/li&gt;&lt;li&gt;Azure Analysis Service: query Synapse Analytics for detailed analysis and generate insights&lt;/li&gt;&lt;li&gt;Power BI: Generate graphs, charts and reports by using information from Azure Analysis service&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This is the diagram of those components as seen on Azure &lt;a href="https://docs.microsoft.com/en-us/azure/architecture/solution-ideas/articles/modern-data-warehouse" class="rank-math-link"&gt;documentation&lt;/a&gt;:&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://docs.microsoft.com/en-us/azure/architecture/solution-ideas/media/modern-data-warehouse.png" alt="Architecture diagram"/&gt;&lt;figcaption&gt;Modern Data Warehouse&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s discuss each components.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-data-factory-adf"&gt;Azure Data Factory (ADF)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Big data requires a service that can orchestrate and operationalize process to refine the enormous stores of raw data into actionable business insights. ADF is managed cloud service built for complex hybrid ETL, ELT and data integration projects.&amp;nbsp; ADF retrieves data from one or more data sources, and convert it into a format you can process. The data sources might present data in different ways, and contain noises that need to be discarded. For example, the source data may contain dates with bad format. ADF can unify the data structure. In ADF, you define the work performed as a pipeline of operations. A pipeline can run continuously, or triggered by schedule.&lt;br&gt;A linked service provides the information needed for ADF to connect to a source or destination. A pipeline is a logical grouping of activities that together perform a task.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The ADF UX (user interface experience) lets you visually author and deploy resources for your data factory without having to write any code. You can drag activities to a pipeline canvas, perform test runs, debug iteratively, and deploy&amp;nbsp; and monitor your pipeline runs.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-data-lake-storage-adls"&gt;Azure Data Lake Storage (ADLS)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A data lake is a repository for large quantities of raw data. Because the data is raw and unprocessed, it&amp;#8217;s very fast to load and update, but the data hasn&amp;#8217;t been put into a structure for efficient analysis. You can think of a data lake as a staging point for your ingested data, before it&amp;#8217;s massaged and converted into a format suitable for performing analytics. Note that a data warehouse also stores large quantities of data, but the data in a warehouse has been converted into a format for efficient analysis. Data lake holds raw data, whereas data warehouse holds structured information.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Data Lake Storage is essentially an extension of Azure Blob storage, organized as a near-infinite file system. It supports POSIX file and directory structure for storage and RBAC. ADLS is also compatible with HDFS, a popular open-source solution to store large quantities of data.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-databricks"&gt;Azure Databricks&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apache &lt;a href="https://docs.microsoft.com/en-us/azure/synapse-analytics/spark/apache-spark-overview#what-is-apache-spark"&gt;Spark&lt;/a&gt; is in-memory cluster computing technology, much faster than disk-based applications, and works with multiple programming languages to let you manipulate distributed data sets (DDS). There is no need to structure everything as map and reduce operations. Databricks develops a web-based platform for working with Spark cluster. It provides automated cluster management and IPython-style notebooks.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Databricks is a managed Apache Spark environment running on Azure to provide big data processing, streaming, and machine learning. Apache Spark is a highly efficient data processing engine, with rich selections of libraries, that can consume and process large amounts of data very quickly. Azure Databricks also supports structured stream processing.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Delta Lake is an open-source storage layer in Azure Databricks that brings reliability to data lakes. Delta Lake provides ACID transactions, scalable metadata handling and unifies streaming and batch data processing. Delta Lake runs on top of your existing data lake and is fully compatible with Apache Spark APIs.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-synapse-analytics"&gt;Azure Synapse Analytics &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Synapse is an end-to-end solution. It unifies data analysis, integration and orchestration, Data Lake, Data Warehouse, ELT/ELT, ML capabilities and visualization. With Synapse, you can process large amounts of data very quickly. You can ingest data from external sources (e.g. flat file, ADLS, other DBMS) and then transform and aggregate the data into a format suitable for analytics processing. You can also use this data as input to further analytical processing using Azure Analysis Services. Azure Synapse is a comprehensive service with the following components:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Synapse Analytics &amp;#8211;&amp;nbsp; a successor of SQL DW technology. Synapse analytics has inherited its MPP capability.&lt;/li&gt;&lt;li&gt;Data Exploration &amp;#8211; Synapse Studio makes data exploration in Data lakes, SQL engine and Spark very easy.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Data Integration &amp;#8211; inherited ADF’s data movement and transformation components, which allows building complex ETL pipelines without code&lt;/li&gt;&lt;li&gt;Development &amp;#8211;&amp;nbsp; supports Spark, Python, Scala, Spark notebooks, SQL&lt;/li&gt;&lt;li&gt;Data visualization &amp;#8211; Synapse Studio allows user to connect to Power BI workspace and get the same report development experience&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The most critical component, Synapse Analytics is analytics engine, designed to process large amounts of data very quickly. Synapse Analytics leverages a MPP (massively parallel processing) architecture, including a control node and a pool of compute nodes. When you submit a processing request, the control node transforms it into smaller requests and send them to compute nodes. Each compute node runs the queries over the portion of data that they each hold. When each node has finished its processing, the results are sent back to the control node where they&amp;#8217;re combined into an overall result.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Synapse Analytics supports two computational models: SQL pools and Spark pools. In a SQL pool, each compute node uses an Azure SQL Database and Azure Storage to handle a portion of the data. You can submit queries in the form of T-SQL statement. Synapse Analytics uses a technology named PolyBase to retrieve data from a wide variety of sources (e.g. Blob, ADSL, CSV). You can save the data read in as SQL tables in Synapse Analytics service. In a Spark pool, the nodes are replaced with Spark cluster. You run Spark jobs comprising code written in Notebooks (in Python, Scala, or Spark SQL). The Spark cluster splits the work out into a series of parallel tasks that can be performed concurrently. You can save data generated by your notebooks in Azure Storage or ADLS. To scale Spark pool, you can specify the cluster size, or turn on autoscaling.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-analysis-service-aas"&gt;Azure Analysis Service (AAS)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AAS is a fully managed PaaS that enables you to build tabular models to support OLAP queries. You can combine data from multiple sources (e.g. Azure SQL Database, ADLS, Cosmos DB, etc). You use those data sources to build models that incorporate your business knowledge. A model is essentially a set of queries and expressions that retrieve data from various data sources and generate results. The results can be cached in-memory for later use, or they can be calculated dynamically, directly from underlying data sources. AAS has significant functional overlap with Synapse Analytics, but it&amp;#8217;s more suited for processing on a smaller scale. The comparison below outlines the difference:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Synapse Analytics&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Azure Analysis Service (AAS)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;#8211; very high volumes of data (multi-terabyte to petabyte sized datasets)&lt;br&gt;&amp;#8211; very complex queries and aggregations&lt;br&gt;&amp;#8211; data minding, and data exploration&lt;br&gt;&amp;#8211; complex ETL operations&lt;br&gt;&amp;#8211; low to mid concurrency (127 users or fewer)&lt;/td&gt;&lt;td&gt;&amp;#8211; smaller volumes of data (a few terabytes)&lt;br&gt;&amp;#8211; multiple resources that can be correlated&lt;br&gt;&amp;#8211; high read concurrency&lt;br&gt;&amp;#8211; detailed analysis, and drilling into data, using functions in Power BI&lt;br&gt;&amp;#8211; rapid dashboard development from tabular data&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many scenarios can benefit from using Synapse Analytics and Analysis Services together. If you have large amounts of ingested data that requires preprocessing, you can use Synapse Analytics to read this data and manipulate it into a model that contains business information rather than a large amount of raw data. The scalability of Synapse Analytics gives it the ability to process and reduce many terabytes of data down into a smaller, succinct dataset that summarizes and aggregates much of this data. You can then use AAS to perform detailed interrogation of this information, and visualize the results of these inquiries with Power BI.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-hdinsight"&gt;Azure HDInsight&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure HDInsight is a managed analytics service based on Apache Hadoop, a collection of open-source tools and utilities that enable you to run processing tasks over large amounts of data. HDInsight uses a clustered model, similar to that of Synapse Analytics. HDInsight stores data using ADLS. You can use HDInsight to analyze data using frameworks such as Hadoop Map/Reduce, Apache Spark, Apache Hive, Apache Kafka, Apache Storm and more.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-power-bi"&gt;Power BI&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Microsoft PowerBI is a collection of software services, apps and connectors. It consists of a Microsoft Windows Desktop application Power BI Desktop, an online SaaS service Power BI service, and mobile Power BI apps available on any device. These three elements are designed to let people create, share and consume business insights. A common workflow with Power BI can be outlined as:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&lt;li&gt;Bring data into Power BI Desktop, and create a report&lt;/li&gt;&lt;li&gt;Publish to the Power BI service, where you can create new visualizations or build dashboards&lt;/li&gt;&lt;li&gt;Share dashboard with others, especially people who are on the go&lt;/li&gt;&lt;li&gt;View and interact with shared dashboards and reports in Power BI mobile apps.&lt;/li&gt;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Basic building blocks in Power BI include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;visualizations: chart, colour-coded map, etc&lt;/li&gt;&lt;li&gt;datasets;&lt;/li&gt;&lt;li&gt;reports: a collection of visualizations that appear together on one or more pages;&lt;/li&gt;&lt;li&gt;dashboards: when you&amp;#8217;re ready to share a report, or a collection of visualizations, you create a dashboard, much like the dashboard in a car, a Power BI dashboard is a collection of visuals from a single page that you can share with others. Often, it&amp;#8217;s a selected group of visuals that provide uick insight into the data or story you&amp;#8217;re trying to present.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/03/git-branching-strategy/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Git Branching Strategy&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/04/public-key-infrastructure-pki/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Public Key Infrastructure (PKI) – Introduction&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Census Data from Statistics Canada</title><link>https://static.digihunch.com/2021/02/interpret-census-data-from-statistics-canada/</link><pubDate>Thu, 25 Feb 2021 21:18:09 -0400</pubDate><guid>https://static.digihunch.com/2021/02/interpret-census-data-from-statistics-canada/</guid><description>&lt;p class="wp-block-paragraph"&gt;&lt;a class="rank-math-link" href="http://www.statcan.gc.ca"&gt;Statistics Canada&lt;/a&gt; carries census every 5 years, with 2016 being the last run. The census data by Statistics Canada provides a wealth of insights but are published in raw format. Post-processing work is needed to extrapolate information, such as median income of a neighbourhood, age distribution of a city, etc. For someone like myself without any background in geographical informatics, it took a bit of learning to see how these work together. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The following information are typically included in the Census data:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Population&lt;/li&gt;&#10;&lt;li&gt;Population density&lt;/li&gt;&#10;&lt;li&gt;Age&lt;/li&gt;&#10;&lt;li&gt;Structural type of dewellings&lt;/li&gt;&#10;&lt;li&gt;Family size&lt;/li&gt;&#10;&lt;li&gt;Marital status&lt;/li&gt;&#10;&lt;li&gt;Language&lt;/li&gt;&#10;&lt;li&gt;Income&lt;/li&gt;&#10;&lt;li&gt;Place of birth&lt;/li&gt;&#10;&lt;li&gt;Level of education&lt;/li&gt;&#10;&lt;li&gt;Occupation&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We will start with level of Geographics. The level of geographics may change slightly between census programs in different years. The most recent 2016 census uses the following &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/figures/f1_1-eng.cfm" class="rank-math-link"&gt;diagram &lt;/a&gt;to depict levels of geographics:&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/figures/f1_1-eng.jpg" alt="Figure 1.1 Hierarchy of standard geographic areas for dissemination, 2016 Census"/&gt;&lt;figcaption class="wp-element-caption"&gt;Geographic Levels&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This diagram reflects a number of different hierarchies of geographic units. The best resource to understand each block, is the &lt;a href="https://www150.statcan.gc.ca/n1/pub/92-195-x/92-195-x2016001-eng.htm" class="rank-math-link"&gt;illustrated glossary&lt;/a&gt; and the chapter &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/98-304/chap12-eng.cfm" class="rank-math-link"&gt;Census Geography&lt;/a&gt; in comprehensive &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/98-304/index-eng.cfm" class="rank-math-link"&gt;Guide to the Census Population&lt;/a&gt;. For example, the chain on the far left of the diagram runs across these levels:&lt;/p&gt;&#10;&lt;p class="has-white-background-color has-background wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="121px" viewBox="-0.5 -0.5 121 321" style="max-width:100%;max-height:321px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;path d="M 60 40 L 60 60 L 60 50 L 60 63.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 68.88 L 56.5 61.88 L 60 63.63 L 63.5 61.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="0" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 20px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Canada&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="24" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Canada&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 110 L 60 130 L 60 120 L 60 133.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 138.88 L 56.5 131.88 L 60 133.63 L 63.5 131.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="70" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 90px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Geographical Region of Canada&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="94" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Geographical Region&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 180 L 60 200 L 60 190 L 60 203.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 208.88 L 56.5 201.88 L 60 203.63 L 63.5 201.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="140" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 160px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Province or Territory&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="164" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Province or Territory&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 250 L 60 270 L 60 260 L 60 273.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 278.88 L 56.5 271.88 L 60 273.63 L 63.5 271.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="210" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 230px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Forward Sortation Area&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="234" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Forward Sortation Ar&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="280" width="120" height="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 300px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Postal Code&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="304" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Postal Code&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this hierarchy, the level of &lt;a href="https://www150.statcan.gc.ca/n1/pub/92-195-x/2011001/geo/region/region-eng.htm" class="rank-math-link"&gt;Geographical Region&lt;/a&gt; of Canada is standardized in &lt;a href="https://www150.statcan.gc.ca/n1/pub/92-195-x/2011001/other-autre/sgc-cgt/sgc-cgt-eng.htm" class="rank-math-link"&gt;Standard Geographic Classification&lt;/a&gt; (SGC), in which the provinces and territories are also &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/geo038-eng.cfm" class="rank-math-link"&gt;encoded&lt;/a&gt;. Note that each Census include a &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/az1-eng.cfm" class="rank-math-link"&gt;dictionary &lt;/a&gt;where all sorts of codes are kept. The dictionary also includes definition of the rest two levels: FSA (forward sortation area as the first three digits of postal code) and &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/geo035-eng.cfm" class="rank-math-link"&gt;postal code&lt;/a&gt; (all six digits). Note that postal code is a mark of Canada Post Corporation, and you may translate postal code into other levels in standard geographic areas, such as CD. This is not straightforward though. You will need a product called &lt;a href="https://www150.statcan.gc.ca/n1/en/catalogue/92-154-X" class="rank-math-link"&gt;Postal Code Conversion File&lt;/a&gt; (PCCF) for the conversion. Statistics Canada does not directly distribute this product. It works with its &lt;a href="https://www.statcan.gc.ca/eng/dli/dli" class="rank-math-link"&gt;Data Liberation Initiative&lt;/a&gt; (DLI) partners to deliver this product.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the diagram there are also other path to run down the hierarchy. For example, from Canada down to federal electoral district (aka ridings). However, the census is not carried out by either election ridings or postal code. Instead, it is carried out by its own collection of levels dedicated for census purpose. When using census data, we need to be familiar with these units.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Census metropolitan area (CMA) and census agglomeration (CA)&lt;/strong&gt;: formed by one or more adjacent municipalities centred on a population centre (known as the core), such as Chatham-Kent CA, Kitchener-Cambridge-Waterloo CMA. Note that CMA and CA can expand across provincial borders, such as Ottawa &amp;#8211; Gatineau CMA. So CMA or CA is not a unit under province or territory.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Census Division (CD, essentially a region or county)&lt;/strong&gt;: general term for provincially legislated areas (such as county, municipalité régionale de comté and regional district) or their equivalents.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Census Subdivision (CSD, essentially a city)&lt;/strong&gt;: the general term for municipalities or areas treated as municipal equivalents for statistical purposes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;&lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/ref/dict/geo013-eng.cfm" class="rank-math-link"&gt;Census Tract&lt;/a&gt; (CT)&lt;/strong&gt;: small, relatively stable geographic areas that usually have a population of less than 10,000 persons, based on data from the previous Census of Population Program.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Dissemination Area (DA)&lt;/strong&gt;: &amp;nbsp;is a small, relatively stable geographic unit composed of one or more adjacent dissemination blocks with an average population of&amp;nbsp;400 to 700&amp;nbsp;persons based on data from the previous Census of Population Program. It is the smallest standard geographic area for which &lt;span style="text-decoration: underline;"&gt;all census data&lt;/span&gt; are disseminated.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Dissemination Block (DB)&lt;/strong&gt;: an area bounded on all sides by roads and/or boundaries of standard geographic areas. The dissemination block is the smallest geographic area for which &lt;span style="text-decoration: underline;"&gt;population &lt;/span&gt;and dwelling counts are disseminated.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With these in mind, we can build two hierarchies closely related to census data:&lt;/p&gt;&#10;&lt;p class="has-white-background-color has-background wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="291px" viewBox="-0.5 -0.5 291 331" style="max-width:100%;max-height:331px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;path d="M 60 30 L 60 50 L 60 40 L 60 53.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 58.88 L 56.5 51.88 L 60 53.63 L 63.5 51.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="0" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 15px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Canada&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="19" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Canada&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 90 L 60 110 L 60 100 L 60 113.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 118.88 L 56.5 111.88 L 60 113.63 L 63.5 111.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="60" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 75px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;CMA/CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="79" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;CMA/CA&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 150 L 60 170 L 60 160 L 60 173.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 178.88 L 56.5 171.88 L 60 173.63 L 63.5 171.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="120" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 135px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Census Tract&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="139" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Census Tract&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 210 L 60 230 L 60 220 L 60 233.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 60 238.88 L 56.5 231.88 L 60 233.63 L 63.5 231.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="0" y="180" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 195px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Dissemination Area&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="199" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Dissemination Area&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="240" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 255px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Dissemination Block&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="259" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Dissemination Block&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 30 L 230 50 L 230 40 L 230 53.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 58.88 L 226.5 51.88 L 230 53.63 L 233.5 51.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="170" y="0" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 15px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Canada&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="19" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Canada&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 90 L 230 110 L 230 100 L 230 113.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 118.88 L 226.5 111.88 L 230 113.63 L 233.5 111.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="170" y="60" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 75px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Geo. Region&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="79" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Geo. Region&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 150 L 230 170 L 230 160 L 230 173.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 178.88 L 226.5 171.88 L 230 173.63 L 233.5 171.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="170" y="120" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 135px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Census Division&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="139" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Census Division&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 210 L 230 230 L 230 220 L 230 233.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 238.88 L 226.5 231.88 L 230 233.63 L 233.5 231.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="170" y="180" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 195px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Census Subdivision&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="199" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Census Subdivision&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 270 L 230 290 L 230 280 L 230 293.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 298.88 L 226.5 291.88 L 230 293.63 L 233.5 291.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="170" y="240" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 255px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Dissemination Area&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="259" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Dissemination Area&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="170" y="300" width="120" height="30" rx="4.5" ry="4.5" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 315px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Dissemination Block&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="319" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Dissemination Block&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now we download &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/dp-pd/prof/details/download-telecharger/comp/page_dl-tc.cfm?Lang=E" class="rank-math-link"&gt;census profile&lt;/a&gt; &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/dp-pd/prof/index.cfm?Lang=E" class="rank-math-link"&gt;data &lt;/a&gt;from &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/dp-pd/index-eng.cfm" class="rank-math-link"&gt;Statistics Canada&lt;/a&gt;. In the dropdown you can pick from the many of the aforementioned geographic levels.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1158" height="245" src="https://static.digihunch.com/wp-content/uploads/2021/02/image.png" alt="" class="wp-image-2176"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you pick Census tracts (CT), there is one data file. The CSV file is about 160M. Also note that under geographic level column, it indicates two levels: CA/CMA and CT, which is important to keep in mind as we go through the data. In the content of the CSV, under the GEO_LEVEL column, value 1 stands for CA/CMA and value 2 stands for CT. Therefore, when GEO_LEVEL=1, the GEO_CODE value is a &lt;a href="https://www23.statcan.gc.ca/imdb/p3VD.pl?Function=getVD&amp;amp;TVD=314312&amp;amp;CVD=314313&amp;amp;CPV=B&amp;amp;CST=01012016&amp;amp;CLV=1&amp;amp;MLV=3" class="rank-math-link"&gt;CA&lt;/a&gt;/&lt;a href="https://www23.statcan.gc.ca/imdb/p3VD.pl?Function=getVD&amp;amp;TVD=314312&amp;amp;CVD=314313&amp;amp;CPV=A&amp;amp;CST=01012016&amp;amp;CLV=1&amp;amp;MLV=3" class="rank-math-link"&gt;CMA&lt;/a&gt; &lt;a href="https://www23.statcan.gc.ca/imdb/p3VD.pl?Function=getVD&amp;amp;TVD=314312" class="rank-math-link"&gt;code &lt;/a&gt;based on &lt;a href="https://www.statcan.gc.ca/eng/subjects/standard/sgc/2016/introduction" class="rank-math-link"&gt;Statistical Area Classification&lt;/a&gt;; when GEO_LEVEL=2, the GEO_CODE value is a CT numerical name (preceded by CMA/CA code). What CT numerical name represents what geographic area, is all defined in &lt;a href="https://www12.statcan.gc.ca/census-recensement/2011/geo/map-carte/ref/cma_ca_ct-rmr_ar_sr/index-eng.cfm" class="rank-math-link"&gt;Census Tract Reference Map&lt;/a&gt;. There is no textual name for each census tract.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To take another example, select Dissemination areas (DAs) from the dropdown. Now the size of the CSV becomes 1.6G, but smaller data files are provided by province and territories. Select the data file for Ontario only.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="916" height="965" src="https://static.digihunch.com/wp-content/uploads/2021/02/image-1.png" alt="" class="wp-image-2177"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that there are five geographic levels as indicated: Canada, provinces/territories, CDs, CSDs and DAs. This suggests we will see 5 different values under the GEO_LEVEL column in the data file:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;0 &amp;#8211; Canada&lt;/li&gt;&#10;&lt;li&gt;1 &amp;#8211; Provinces and Territories&lt;/li&gt;&#10;&lt;li&gt;2 &amp;#8211; CDs&lt;/li&gt;&#10;&lt;li&gt;3 &amp;#8211; CSDs&lt;/li&gt;&#10;&lt;li&gt;4 &amp;#8211; DAs&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Read the &lt;a href="https://www.statcan.gc.ca/eng/subjects/standard/sgc/2016/introduction" class="rank-math-link"&gt;SGC documentation&lt;/a&gt; to understand the code from level Canada to level CSD. DA is similar to CT because the code is defined in &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/geo/ADA/ADA-eng.cfm" class="rank-math-link"&gt;reference map&lt;/a&gt; here. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from DA and CT, there are other levels (such as ridings) with reference maps, as outlined in the &lt;a href="https://www12.statcan.gc.ca/census-recensement/2016/geo/index-eng.cfm" class="rank-math-link"&gt;Census geography&lt;/a&gt; page.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With all the above information, we can parse the data programmatically. Of course, the schema and coding information applies to Canada. Outside of Canada, pretty much all states have a counterpart government agency that manages census and statistics, just with different formats to understand from ground up. A lot of census geography concepts applies to other countries as well. For example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://www.census.gov/" class="rank-math-link"&gt;Census Bureau&lt;/a&gt; of United States&lt;/li&gt;&#10;&lt;li&gt;Australian &lt;a href="https://www.abs.gov.au/" class="rank-math-link"&gt;Bureau of Statistics&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.ons.gov.uk/census" class="rank-math-link"&gt;Office for National Statistics&lt;/a&gt; (UK)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://ec.europa.eu/eurostat/web/main" class="rank-math-link"&gt;Eurostat &lt;/a&gt;(European Union)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Welcome to the world of data.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/02/basic-resource-object-in-kubernetes-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Basic Resource Object in Kubernetes 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/03/git-branching-strategy/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Git Branching Strategy&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Spark, Cassandra and Python</title><link>https://static.digihunch.com/2020/09/spark-cassandra-and-python/</link><pubDate>Tue, 15 Sep 2020 16:24:09 -0400</pubDate><guid>https://static.digihunch.com/2020/09/spark-cassandra-and-python/</guid><description>&lt;p class="wp-block-paragraph"&gt;In this &lt;a href="https://static.digihunch.com/2020/09/intro-to-big-data-projects/"&gt;post&lt;/a&gt; we touch briefly on &lt;a href="https://en.wikipedia.org/wiki/Apache_Spark"&gt;Apache Spark&lt;/a&gt; as a cluster computing framework that supports a number of drivers to pipe data in, and that its stunning performance thanks much to resilient distributed dataset (RDD) as its architectural foundation. In this hands-on guide, we expand on how to configure Spark, and use Python to connect to Cassandra data source. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Spark supports Sala, Java and Python shells. I&amp;#8217;m not familiar with Scala but I have had Python background and know it&amp;#8217;s importance in big data processing. One key data structure with big data processing in Python is Pandas &lt;a href="https://www.digitalvidya.com/blog/dataframes-in-python/"&gt;data frame&lt;/a&gt;. Spark has the ability to map its &lt;a href="https://www.analyticsvidhya.com/blog/2016/10/spark-dataframe-and-operations/"&gt;own data frame&lt;/a&gt; to Pandas data frame.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Spark also needs a third party connector to connect to Cassandra. This connector is provided by Datastax in this open-source project called &lt;a href="https://github.com/datastax/spark-cassandra-connector"&gt;spark-cassandra-connector&lt;/a&gt;. The Github page includes a README with compatibility matrix, which is very important to understand before any configuration works. However, the Github is only the source code repository for anyone to build the project themselves. An alternative source of the dependency is this &lt;a href="https://mvnrepository.com/artifact/com.datastax.spark/spark-cassandra-connector_2.11/2.5.1"&gt;page&lt;/a&gt; from Maven repository. When running Spark we can simply reference that page URL as dependency.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Suppose we install spark onto CentOS, we download and unzip &lt;a href="https://spark.apache.org/downloads.html"&gt;this&lt;/a&gt; package to somewhere such as user directory (~). Assuming we already have Open JDK 1.8 installed, when we run spark binary, it places cache and jar files in ~/.ivy2, potentially we need to manually move the following dependencies to ~/.ivy2/jars:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;org.codehaus.groovy_groovy-json-2.5.7.jar&lt;/li&gt;&lt;li&gt;com.github.jnr_jffi-1.2.19.jar&lt;/li&gt;&lt;li&gt;org.codehaus.groovy_groovy-2.5.7.jar&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These jar files are available for download from Maven&amp;#8217;s repository as well if you wish provide them as package dependencies. We have two flavours of interactive shells to connect to Spark: the Scala shell (spark-shell) and python shell (PySpark)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Scala Shell&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can enter the default scala shell by &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./bin/spark-shell --packages com.datastax.spark:spark-cassandra-connector_2.11:2.5.1 --conf spark.cassandra.connection.host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;10.10.10.151 --verbose&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;During the start, note a stdout line that says:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Spark context Web UI available at http://spark-host:4040&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we can open that tcp port on iptables and view that job in browser. From within scala shell we can test connectivity to Cassandra with the following commands:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; val new_exam = spark.read.format(&amp;#34;org.apache.spark.sql.cassandra&amp;#34;).options(Map(&amp;#34;table&amp;#34; -&amp;gt; &amp;#34;new_exam&amp;#34;,&amp;#34;keyspace&amp;#34; -&amp;gt; &amp;#34;examarchive&amp;#34;)).load()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Python Shell&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Python Shell (aka &lt;a href="https://realpython.com/pyspark-intro/"&gt;PySpark&lt;/a&gt;) brings Python shell which is known to many engineers from system admin or development background. By default, python 2 will be used. To specify python version, set some environment variables before we start pyspark with cassandra connector package specified:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ export PYSPARK_PYTHON&lt;span style="color:#f92672"&gt;=&lt;/span&gt;python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ export PYSPARK_DRIVER_PYTHON&lt;span style="color:#f92672"&gt;=&lt;/span&gt;python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ export SPARK_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/dhunch/spark-2.4.6-bin-hadoop2.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$SPARK_HOME/bin:$PATH&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./bin/pyspark --packages com.datastax.spark:spark-cassandra-connector_2.11:2.5.1 --conf spark.cassandra.connection.host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;10.10.10.151&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once you&amp;#8217;re in the interactive shell, you can start with loading required python libraries, and test your connectivity:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; from pyspark import SparkContext, SparkConf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; from pyspark.sql import SQLContext&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; load_options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;new_exam&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;keyspace&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;examarchive&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; df&lt;span style="color:#f92672"&gt;=&lt;/span&gt;spark.read.format&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;org.apache.spark.sql.cassandra&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.options&lt;span style="color:#f92672"&gt;(&lt;/span&gt;**load_options&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.load&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; df.show&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; df.write.csv&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/tmp/mycsv.csv&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color:#75715e"&gt;#df.registerTempTable(&amp;#34;ne&amp;#34;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; df.createTempView&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ne&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; tw1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext.sql&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;select count(*) from ne&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; tw1.show&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; qrdf2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext.sql&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;select study_key, image_count from ne where current_exam_version=exam_version&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; qrdf2.write.csv&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/tmp/tw2&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that the load method returns type pyspark.sql.dataframe.DataFrame, which is already a distributed data structure. So there is no need to parallelize it with parallelize() method. As of Spark 2.0, we are supposed to use createTempView() method instead of the old registerTempTables() method. Read &lt;a href="https://dwgeek.com/spark-sql-create-temporary-tables-syntax-and-examples.html/"&gt;this&lt;/a&gt; for further information.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Python Application&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With interactive shell you run one or several commands at a time. We can build a python script and submit the whole script as an application. This is an example command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./bin/spark-submit --packages com.datastax.spark:spark-cassandra-connector_2.11:2.5.1 sample.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that the sample.py script name must be provided after &amp;#8211;packages switch. Otherwise, you will get an error saying missing dependency (Failed to find data source: org.apache.spark.sql.cassandra). In the script, we can manipulate the data from Cassandra with greater flexibility. For example, we can map one field to several fields. For example, if one of the fields stores an XML document, the script can drill down the XML tree structure parse out values at different levels of child nodes, into separate data base columns. Here is an example of python script where we register a custom UDF declared in python and apply it to some existing columns to build new columns:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#! /usr/bin/python3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# To submit this script as an application to spark:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ./bin/spark-submit --packages com.datastax.spark:spark-cassandra-connector_2.11:2.5.1 examstat.py&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Note that the script name must be placed after --packages &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;,&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;,&lt;/span&gt;re&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xml.etree.ElementTree &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ET&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pyspark &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SparkContext, SparkConf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pyspark.sql &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SQLContext, SparkSession&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pyspark.sql.functions &lt;span style="color:#f92672"&gt;import&lt;/span&gt; udf &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pyspark.sql.types &lt;span style="color:#f92672"&gt;import&lt;/span&gt; StringType,StructType,StructField&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cluster_seeds&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#39;dest_cass_host&amp;#39;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pTrimExamCode&lt;/span&gt;(raw_code):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;NULL&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; raw_code &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt; &lt;span style="color:#f92672"&gt;or&lt;/span&gt; raw_code&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;None&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; str(raw_code)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;replace(&lt;span style="color:#e6db74"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rstrip(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_valid_date&lt;/span&gt;(date_str):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isValidDate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;bool(re&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;match&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;^(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$&amp;#34;&lt;/span&gt;,date_str))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; isValidDate:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime(int(date_str[:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;]),int(date_str[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;]),int(date_str[&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;]))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ValueError&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isValidDate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; isValidDate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pPullTags&lt;/span&gt;(study_key,raw_xml_field):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ns&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;vc&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;http://medical.nema.org/mint&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StudyDateTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;None&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StudyDescriptionTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;None&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; raw_xml_field &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; summary_tree&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ET&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fromstring(str(raw_xml_field)) &lt;span style="color:#75715e"&gt;# str function outputs &amp;#39;None&amp;#39; or null object&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xml_find_res&lt;span style="color:#f92672"&gt;=&lt;/span&gt;summary_tree&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find(&lt;span style="color:#e6db74"&gt;&amp;#34;vc:attributes/vc:attr[@tag=&amp;#39;00080020&amp;#39;]&amp;#34;&lt;/span&gt;,ns)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; xml_find_res &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;: StudyDateTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;str(xml_find_res&lt;span style="color:#f92672"&gt;.&lt;/span&gt;attrib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#39;val&amp;#39;&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xml_find_res&lt;span style="color:#f92672"&gt;=&lt;/span&gt;summary_tree&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find(&lt;span style="color:#e6db74"&gt;&amp;#34;vc:attributes/vc:attr[@tag=&amp;#39;00081030&amp;#39;]&amp;#34;&lt;/span&gt;,ns)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; xml_find_res &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;: StudyDescriptionTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;str(xml_find_res&lt;span style="color:#f92672"&gt;.&lt;/span&gt;attrib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#39;val&amp;#39;&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;-----------------------&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; examstat: error parsing metadta for study_key &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;study_key)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (StudyDateTag,StudyDescriptionTag)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# custom StructType for the output tuple&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XMLExtractType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;StructType([&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StructField(&lt;span style="color:#e6db74"&gt;&amp;#34;StudyDate&amp;#34;&lt;/span&gt;,StringType(),&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StructField(&lt;span style="color:#e6db74"&gt;&amp;#34;StudyDescription&amp;#34;&lt;/span&gt;,StringType(),&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;)])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sparkSession&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SparkSession&lt;span style="color:#f92672"&gt;.&lt;/span&gt;builder \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt;appName(&lt;span style="color:#e6db74"&gt;&amp;#39;examstat&amp;#39;&lt;/span&gt;) \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt;config(&lt;span style="color:#e6db74"&gt;&amp;#39;spark.cassandra.connection.host&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;join(cluster_seeds)) \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt;master(&lt;span style="color:#e6db74"&gt;&amp;#39;local[*]&amp;#39;&lt;/span&gt;) \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt;getOrCreate()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;new_exam&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;keyspace&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;examarchive&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlContext&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SQLContext(sparkSession)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# pyspark.sql.dataframe.DataFrame is already a distributed data structure. No need to parallelize it.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df0&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(&lt;span style="color:#e6db74"&gt;&amp;#39;org.apache.spark.sql.cassandra&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;options(&lt;span style="color:#f92672"&gt;**&lt;/span&gt;load_options)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;load()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df0&lt;span style="color:#f92672"&gt;.&lt;/span&gt;createTempView(&lt;span style="color:#e6db74"&gt;&amp;#34;new_exam&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# pyspark.sql.functions.udf(python function,output type)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sparkSession&lt;span style="color:#f92672"&gt;.&lt;/span&gt;udf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;register(&lt;span style="color:#e6db74"&gt;&amp;#34;uTrimExamCode&amp;#34;&lt;/span&gt;,udf(pTrimExamCode,StringType()))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sparkSession&lt;span style="color:#f92672"&gt;.&lt;/span&gt;udf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;register(&lt;span style="color:#e6db74"&gt;&amp;#34;uPullTags&amp;#34;&lt;/span&gt;,udf(pPullTags,XMLExtractType))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# use custom UDFs uTrimExamCode and uPullTags to calculate new columns and remove dups and deleted studies&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sql(&lt;span style="color:#e6db74"&gt;&amp;#34;select study_key as StudyKey,uTrimExamCode(exam_id) as ExamCode,image_count as ImgCnt,Total_pixel_data_size as PixelSize, uPullTags(study_key,metadata_summary) as XMLExtract, metadata_summary from new_exam where exam_version=current_exam_version and is_deleted=False&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;createTempView(&lt;span style="color:#e6db74"&gt;&amp;#34;uniq_study&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# map the four fields in XMLExtract to separate columns. we take this as separate step as we don&amp;#39;t want uPullTags to execute multiple times in previous step &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sql(&lt;span style="color:#e6db74"&gt;&amp;#34;select StudyKey,ExamCode,ImgCnt,PixelSize,XMLExtract.StudyDate as StudyDate,XMLExtract.StudyDescription as StudyDescription from uniq_study&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;createTempView(&lt;span style="color:#e6db74"&gt;&amp;#34;uniq_study_stat&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Run analytical query&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sqlContext&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sql(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT ExamCode, round(avg(PixelSize)/1024/1024) as avg_size_mb, round(sum(PixelSize)/1024/1024/1024,2) as total_size_gb,count(StudyKey) as study_count FROM uniq_study_stat GROUP BY ExamCode order by study_count desc&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#data frames are lazily loaded and processing not started until the following call&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df3&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write&lt;span style="color:#f92672"&gt;.&lt;/span&gt;csv(&lt;span style="color:#e6db74"&gt;&amp;#39;/tmp/examstat_&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%m&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%H%M%S&amp;#34;&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;It is important to understand the concept of lazy evaluation in Spark RDD here. The execution of function to RDD does not start until an action is triggered (eg. show method, or write method). Spark maintains the record of which operation is being called through DAG (&lt;a href="https://data-flair.training/blogs/dag-in-apache-spark/"&gt;directed acyclic graph&lt;/a&gt;). Such record is referred to as a transformation. We need to understand whether each RDD method is a transformation, or an action so we know whether it will be lazily evaluated (&lt;a href="https://data-flair.training/blogs/spark-rdd-operations-transformations-actions/"&gt;here&amp;#8217;s&lt;/a&gt; more information).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This is a &lt;a href="https://data-flair.training/blogs/spark-vs-hadoop-mapreduce/"&gt;major difference&lt;/a&gt; between Apache Spark and Hadoop MapReduce. With MapReduce, developer spend a lot of time in minimizing the number of MapReduce passes. It happens by clubbing the operations together. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/09/intro-to-big-data-projects/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Intro to Big Data Projects&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/09/log-file-navigator-lnav/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Log file navigator (lnav)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>DataStax Python Driver</title><link>https://static.digihunch.com/2020/06/iterate-through-cassandra-table-with-datastax-python-driver/</link><pubDate>Sat, 27 Jun 2020 14:20:34 -0400</pubDate><guid>https://static.digihunch.com/2020/06/iterate-through-cassandra-table-with-datastax-python-driver/</guid><description>&lt;p class="wp-block-paragraph"&gt;For someone with relational database background, analyzing data in Cassandra isn&amp;#8217;t intuitive. There are two reasons. First, Cassandra data table is hardly updated or deleted in avoidance of tombstones. Insertion is the only action on the table resulting in multiple versions of each record all stored in the same table, thus a much longer table than its relational counterpart. Second, Cassandra schema is designed around how end-user will query the database, rather than a modelling of entity-relations. There are less fields, but some field may contain large data chunk, such as an entire XML document being stored in a column.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Data engineers with Cassandra may need to run full table scan, and extract values from wide columns of XML document by drilling down the XML tree structure, in order to produce a data frame (two-dimensional mutable, possibly heterogeneous tabular data structure with labeled rows and columns). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;ve came across this task in the past and the duration of a full table scan on Cassandra table is in the order of hours, which is beyond what the built-in cqlsh tool can handle. I had to use Python to iterate through 200 million rows. Datastax Provides Cassandra client driver as a Python3 package, known as &lt;a href="https://docs.datastax.com/en/developer/python-driver/index.html"&gt;DataStax Python Driver&lt;/a&gt;. It allows us to build a simple Python3 script to complete a full table scan. The driver can be installed with pip3:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install cassandra-driver&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With the driver installed, we can start to pull data from Cassandra table into Python client class. here is a basic example of how to print the rows into a file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#! /usr/bin/python3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra.query &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SimpleStatement&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra.cluster &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra &lt;span style="color:#f92672"&gt;import&lt;/span&gt; ConsistencyLevel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; datetime&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cluster &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Cluster([&lt;span style="color:#e6db74"&gt;&amp;#39;cass_host&amp;#39;&lt;/span&gt;],port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9042&lt;/span&gt;,protocol_version&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print (datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; %H:%M:%S&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; start&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; cluster&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect(&lt;span style="color:#e6db74"&gt;&amp;#39;myownkeyspace&amp;#39;&lt;/span&gt;, wait_for_all_pools&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM mytable&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; statement &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SimpleStatement(query, fetch_size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, consistency_level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ConsistencyLevel&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ONE)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; csv_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; open(&lt;span style="color:#e6db74"&gt;&amp;#39;result.csv&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; csv_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(&lt;span style="color:#e6db74"&gt;&amp;#34;header&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; tbrow &lt;span style="color:#f92672"&gt;in&lt;/span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(statement,timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2.0&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; csv_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(tbrow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_id&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ex:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(ex)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;KeyboardInterrupt&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Task Interrupted by SIGINT.&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;finally&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cluster&lt;span style="color:#f92672"&gt;.&lt;/span&gt;shutdown()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; csv_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print (datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; %H:%M:%S&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; finish&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that the fetch_size can be set to larger number, but it may increase the chance of server read timeout (code=1200) in the middle of execution.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The processing logic can be implemented in the loop while each record in the table is being pulled out. The logic is repeated for every row so it will have a significant impact on the overall execution time.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Some the data needs to be ported into pandas data frame for further engineering, instead of being printed out to file. The following snippet will do the trick:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#! /usr/bin/python3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra.query &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SimpleStatement&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra.cluster &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; cassandra &lt;span style="color:#f92672"&gt;import&lt;/span&gt; ConsistencyLevel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; datetime&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pandas_factory&lt;/span&gt;(colnames,rows):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(rows, columns&lt;span style="color:#f92672"&gt;=&lt;/span&gt;colnames))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; res&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cluster &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Cluster([&lt;span style="color:#e6db74"&gt;&amp;#39;cass_host&amp;#39;&lt;/span&gt;],port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9042&lt;/span&gt;,protocol_version&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print (datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; %H:%M:%S&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; start&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; cluster&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect(&lt;span style="color:#e6db74"&gt;&amp;#39;myownkeyspace&amp;#39;&lt;/span&gt;, wait_for_all_pools&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;row_factory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pandas_factory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM mytable&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; statement &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SimpleStatement(query, consistency_level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ConsistencyLevel&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ONE,fetch_size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df&lt;span style="color:#f92672"&gt;=&lt;/span&gt;pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; tbrow &lt;span style="color:#f92672"&gt;in&lt;/span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(statement):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df&lt;span style="color:#f92672"&gt;=&lt;/span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(tbrow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_id,ignore_index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ex:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(ex)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;KeyboardInterrupt&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Task Interrupted by SIGINT.&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;finally&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cluster&lt;span style="color:#f92672"&gt;.&lt;/span&gt;shutdown()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print (datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; %H:%M:%S&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; finish&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In my test environment with 180 million rows in the table, the execution of the first script takes 37 minutes (of course there&amp;#8217;s a lot of factors at play). I experimented several approaches to improve the speed, such as tuning the &lt;a href="https://medium.com/@bramblexu/understand-the-buffer-policy-in-python-78e91e7759ca"&gt;buffering options&lt;/a&gt; for file write. However, It turns out that the speed bottleneck of the script is not even file IO, but rather pulling data out of Cassandra.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The output can be stored as CSV file, which can be lately loaded to relational database for analysis. PostgreSQL would be a good open-source choice because it is both transactional and analytical.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/06/performance-analysis-tools/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Performance Analysis&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/07/dockersnetwork/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Docker network in different modes&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>