<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ahmed Rachid Hazourli on Medium]]></title>
        <description><![CDATA[Stories by Ahmed Rachid Hazourli on Medium]]></description>
        <link>https://medium.com/@ahmedrachidhazourli?source=rss-e06d99af9c2b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*vQunFn07XgXLGx4wC8REnA.jpeg</url>
            <title>Stories by Ahmed Rachid Hazourli on Medium</title>
            <link>https://medium.com/@ahmedrachidhazourli?source=rss-e06d99af9c2b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 23:52:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ahmedrachidhazourli/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Self-serve Analytics application in minutes with Snowflake Cortex Analyst ❄️]]></title>
            <link>https://medium.com/snowflake/self-serve-analytics-application-in-minutes-with-snowflake-cortex-analyst-%EF%B8%8F-8bdc65638cb3?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/8bdc65638cb3</guid>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[snowflake-data-cloud]]></category>
            <category><![CDATA[text-to-sql]]></category>
            <category><![CDATA[cortex]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Tue, 22 Oct 2024 14:37:37 GMT</pubDate>
            <atom:updated>2024-10-22T14:37:37.967Z</atom:updated>
            <content:encoded><![CDATA[<h3>“Chat with Your Data” application in minutes with Snowflake Cortex Analyst ❄️</h3><blockquote>In this blog post, you’ll be able to build a Streamlit application that empowers users to ask questions in natural language, gain instant insights and interact with their data in less than two minutes, using Snowflake Cortex Analyst ❄️</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tDZYvDfn4X6Dp1mERWTF8g.gif" /><figcaption>Figure 1. Self-service analytics app using Cortex Analyst</figcaption></figure><h4>Introduction:</h4><p>In today’s data-driven world, companies are investing heavily in LLM-powered conversational self-service analytics tools to empower business users with real-time insights. Traditionally, business users have relied on BI dashboards to answer their data questions, leaving them dependent on data analysts and engineers, which can take long days.</p><p>Building such tools is complex, and many self-service analytics initiatives fail due to poor quality and inaccurate insights, which may lead to significant business consequences. Trust and accuracy are the key metrics that make business users rely on these tools.</p><h4>What is Cortex Analyst ?</h4><p>With the promise of delivering accurate self-service analytics to businesses, Snowflake has released <a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst"><strong><em>Cortex Analyst</em></strong></a> (currently in Public Preview). This fully managed LLM-powered feature helps organizations create applications capable of reliably answering business questions based on the structured data stored in Snowflake, with no SQL knowledge required, achieving over 90%+ accuracy in real-world use cases better than other Text-to-SQL solutions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ogGn7vhyOBrBDgOW" /><figcaption>Figure 2. SQL generation accuracy for Cortex Analyst vs. alternatives (source: Snowflake.com)</figcaption></figure><p>Powered by state-of-the-art large language models such as Meta, Llama3 and Mistral, Cortex Analyst is delivered as a REST API, making it easy to integrate to existing workflows, business tools and applications like Streamlit and custom chat interfaces, while maintaining data security and governance. <a href="https://www.snowflake.com/en/blog/cortex-analyst-ai-self-service-analytics/"><em>Learn more about Cortex Analyst accuracy</em></a></p><h4>Cortex Analyst semantic model</h4><p>Similar to how a data analyst writes a SQL query after understanding business logic and the meanings of tables and columns, Cortex Analyst uses a semantic model to capture the business meaning and provide a richer description of the data’s semantic information. This ensures high-precision SQL generation and accurate results. The semantic model is a YAML file containing metadata such as table names, column names, value types, descriptions, verified queries, filters, and more.</p><p>Below is a sample semantic model YAML file:</p><pre>name: Sales Data<br>tables:<br>- name: sales_data<br>  base_table:<br>    database: sales<br>    schema: public<br>    table: sd_data<br><br>  dimensions:<br>    - name: state<br>      description: The state where the sale took place.<br>      expr: d_state<br>      data_type: TEXT<br>        unique: false<br>        sample_values:<br>          - &quot;CA&quot;<br>          - &quot;IL&quot;<br><br>    # Time dimension columns in the logical table.<br>    time_dimensions:<br>      - name: sale_timestamp<br>        synonyms:<br>          - &quot;time_of_sale&quot;<br>          - &quot;transaction_time&quot;<br>        description: The time when the sale occurred. In UTC.<br>        expr: dt<br>        data_type: TIMESTAMP<br>        unique: false<br><br>    # Measure columns in the logical table.<br>    measures:<br>      - name: profit<br>        synonyms:<br>          - &quot;earnings&quot;<br>          - &quot;net income&quot;<br>        description: The profit generated from a sale.<br>        expr: amt - cst<br>        data_type: NUMBER<br>        default_aggregation: sum<br><br>verified_queries:<br>  - name: &quot;California profit&quot;<br>    question: &quot;What was the profit from California last month?&quot;<br>    verified_at: 1714497970<br>    verified_by: Jane Doe<br>    sql: &quot;<br>SELECT sum(profit)<br>FROM __sales_data<br>WHERE state = &#39;CA&#39;<br>    AND sale_timestamp &gt;= DATE_TRUNC(&#39;month&#39;, DATEADD(&#39;month&#39;, -1, CURRENT_DATE))<br>    AND sale_timestamp &lt; DATE_TRUNC(&#39;month&#39;, CURRENT_DATE)<br>&quot;</pre><h4>Create a Streamlit app to Chat with Any Data Accurately in Minutes</h4><p>Creating a semantic model requires time to fill in the necessary metadata. To accelerate the delivery of a self-service analytics application, a Streamlit application can automate the generation of the semantic model, uploads it to a stage, and enables you to start conversing with your data in natural language within minutes. <em>This app is inspired from </em><a href="https://github.com/daniel10lacouture/personal/tree/main/Streamlit%20in%20Snowflake/YAML%20file%20generator?source=post_page-----2b78e930e688--------------------------------"><em>Github repository</em></a></p><p>This application uses metadata information (retrieved using the <a href="https://docs.snowflake.com/en/sql-reference/sql/desc-table"><strong><em>DESCRIBE TABLE</em></strong></a> command) about the selected tables to fill in required information in the semantic model, such as column names and column types. Table and column descriptions are generated by <a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions#label-cortex-llm-complete"><strong><em>Cortex LLM’s COMPLETE</em></strong></a> function using the <em>Llama3–70b model</em>, as shown in the architecture below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WwIZz_RfIwdqJlEuv7RvPw.png" /><figcaption>Figure 3. Streamlit App — Architecture Overview</figcaption></figure><p>To use this application:</p><ol><li>Download the streamlit_app.py file from the <a href="https://github.com/sfc-gh-ahazourli/snowflake-cortex-analyst-demo">GitHub repository</a>.</li><li><strong>Login</strong> to Your Snowflake Account: Head over to “<strong><em>Projects</em></strong>.”</li><li><strong>Select</strong> “<strong><em>Streamlit”</em></strong>: You will see a list of applications.</li><li><strong>Create a New Streamlit App: </strong>Click on <strong><em>“+ Streamlit App”. </em></strong>Provide a title, location, and warehouse for your application. Click on <strong><em>“Create” </em></strong>and paste the Python code from streamlit_app.py.</li><li><strong>Run</strong> the Application.</li><li><strong>Getting Started:</strong> Once the Streamlit app is running, navigate to “<strong><em>Getting Started</em></strong>” page. Provide a name and description for your semantic model, then click on <em>“</em><strong><em>Save Semantic Model Info</em></strong><em>”</em></li><li><strong>Click</strong> on <strong><em>“Table Definition”:</em></strong> Select the databases, schemas, and tables you want to query in natural language by clicking on <strong><em>“Add table to YAML”. </em></strong>You also need to select the stage where to save the semantic model YAML file that will be used to request the Cortex Analyst REST API. The application auto-populates the semantic model YAML file with table descriptions, column metadata, and descriptions generated using the Llama3 model.</li><li><strong>Upload to Stage: </strong>Once you’ve added all tables, click on <strong><em>“Upload to Stage.” </em></strong>You will find a new YAML file in the stage you’ve previously selected.</li><li><strong>Chat with Your Data:</strong> You’re all set! Go to the “<strong><em>Chat with your data</em></strong>” page and start asking questions about the tables you’ve selected.</li><li><strong>Reset the App:</strong> You can reset the app to its initial state, clearing all input and saved data to start fresh.</li></ol><p>Below is a demo showing all the steps above:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tDZYvDfn4X6Dp1mERWTF8g.gif" /><figcaption>Figure 4. Demo Steps</figcaption></figure><blockquote><em>This application can be further improved by adding verified queries, synonyms, and sample values to enhance the accuracy of the results.</em></blockquote><p>Hope you find this useful !</p><h4>Conclusion</h4><p>AI for BI has traditionally been challenging. Snowflake Cortex Analyst represents a significant step forward in data analytics. With it, you can effortlessly build production-ready text-to-SQL services that deliver highly accurate results, enabling organizations to make data-driven decisions more efficiently and transforming the way they interact with their data.</p><p><em>Some useful links:</em></p><ul><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst">Cortex Analyst documentation</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst/semantic-model-spec">Semantic Model spec</a></li><li><a href="https://www.snowflake.com/engineering-blog/snowflake-cortex-analyst-behind-the-scenes/">Learn more about Cortex Analyst architecture and its key components.</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions">Cortex LLM functions</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8bdc65638cb3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/self-serve-analytics-application-in-minutes-with-snowflake-cortex-analyst-%EF%B8%8F-8bdc65638cb3">Self-serve Analytics application in minutes with Snowflake Cortex Analyst ❄️</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why VMware Greenplum as a Massive Vector Database for your Analytical needs ?]]></title>
            <link>https://medium.com/aimonks/why-vmware-greenplum-as-a-massive-vector-database-for-your-analytical-needs-870dcde1cedc?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/870dcde1cedc</guid>
            <category><![CDATA[pgvector]]></category>
            <category><![CDATA[vector-database]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[greenplum]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Tue, 08 Aug 2023 22:24:33 GMT</pubDate>
            <atom:updated>2023-08-10T15:06:36.665Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why VMware Greenplum as a Massive Vector Database for your Analytical needs ?</h3><h3>Introduction</h3><p>Greenplum 7, the upcoming release of the Greenplum data warehouse based on PostgreSQL v12, marking a huge milestone for the Greenplum community. This release will support many new extensions for AI/ML, such as pgvector and postgresML.</p><blockquote>The latest beta5 release has introduced support for the popular <strong>#pgvector</strong> extension, enabling large-scale vector similarity search.</blockquote><blockquote>More details here: <a href="https://docs.vmware.com/en/VMware-Greenplum/7/greenplum-database/relnotes-release-notes.html">https://docs.vmware.com/en/VMware-Greenplum/7/greenplum-database/relnotes-release-notes.html</a></blockquote><p>This advancement seamlessly complements Greenplum’s existing capabilities by facilitating support for unstructured data within the data warehouse through vector embeddings. It extends to data federation, enabling seamless querying (both read and write operations) across various databases and datalakes, streaming capabilities to ingest real-time data from Kafka and RabbitMQ, in addition to geospatial analytics through PostGIS and text analytics through Full-text search and GPText (built upon Apache SolR).</p><p>This expansive feature set is further enhanced by a wide array of in-database machine learning capabilities, which include support for Python, R, MADlib extension, and Containers. These capabilities enable the training, fine-tuning, and deployment of models within the Greenplum environment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*embDRAty2PLagLsdiG9JXA.png" /></figure><p>In this blog post, we will delve into the revolutionary impact of pgvector on Greenplum, exploring the new horizons it opens.</p><p>Furthermore, we will demonstrate why VMware Greenplum stands as a great choice for companies in search of a Modern Data Warehouse/Platform equipped with Vector Search capabilities tailored for analytical excellence.</p><h3>pgvector — a PostgreSQL vector search extension</h3><p>pgvector is an open-source vector database extension for PostgreSQL. It enables you to store vector embeddings and perform vector similarity search in PostgreSQL. It is particularly useful for applications involving natural language processing, such as those built on top of OpenAI’s GPT models.</p><p>pgvector extension brings great new capabilities to PostgreSQL, to become a Vector Database, it became a great choice for developers seeking to develop new AI-applications empowered with vector similarity search while keeping ACID compliance of an object-relational database like PostgreSQL.</p><p>The versatility and efficiency of vector databases make them valuable for a wide range of applications across various industries. Some of the prominent ones are:</p><ul><li><strong>Natural language processing (NLP): </strong>Vector databases facilitate semantic search and text analysis through efficient handling of word embeddings or document vectors. They enable tasks like document classification, sentiment analysis, and keyword extraction, helping organizations make sense of massive volumes of textual data from sources like social media, forums, customer interactions — and currently most importantly — LLM prompt inputs.</li><li><strong>Image search and recognition: </strong>reverse image search, object detection, and facial recognition…</li><li><strong>Recommendation systems:</strong> for modern e-commerce and content platforms, analyze user preferences and content features to generate personalized and highly relevant recommendations to users in real-time.</li></ul><h3>VMware Greenplum + pgvector: a Massive Vector Database for Analytics</h3><p>Thanks to the vector capabilities introduced by pgvector, Greenplum takes a giant leap forward, positioning itself as a unique data warehouse and a great vector database for analytical purposes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mqZRQMTe39xG3Ozvd7R1wA.png" /></figure><p>However, you may wonder, “Does Greenplum truly fulfill the criteria of a robust and proven vector database?”</p><p>Revisiting the fundamentals, vector databases possess the ability to store and retrieve vectors as multidimensional points.</p><p>They amplify their capabilities by enabling efficient and rapid lookup of nearest neighbors within the N-dimensional space. Typically driven by k-nearest neighbor (k-NN) indexes and bolstered by algorithms such as Hierarchical Navigable Small World (HNSW) and Inverted File Index (IVF), vector databases offer additional functionalities like data management, fault tolerance, access control, and an adept query engine.</p><p>From the description above, we can extract the requirements for an advanced vector database, which ideally encompasses:</p><p>1. Vector-Store.</p><p>2. Vector Similarity Search with Diverse Distance Metrics.</p><p>3. Indexing.</p><p>4. Speed.</p><p>5. Reliability (Fault Tolerance and High Availability).</p><p>6. Distributed Architecture.</p><p>7. Scalability.</p><p>With this framework in mind, let’s delve into how Greenplum fulfills each of these requisites:</p><h4>1. Vector-Store (<strong>Storing vectors and embeddings):</strong></h4><p>Before storing vectors inside Greenplum, you should enable the pgvector extension by running the following CREATE EXTENSION statement:</p><pre>CREATE EXTENSION vector;</pre><p>To create a table for storing vectors, use the following SQL command, adjusting the dimensions as needed.</p><pre>CREATE TABLE vectors_table (<br>      id BIGSERIAL PRIMARY KEY,<br>      embedding VECTOR(3)<br>);</pre><p>The command generates a table named vectors_table with an embedding column capable of storing vectors with 3 dimensions.</p><p>You can store vectors in your table, execute an INSERT statement similar to the following to store embeddings:</p><pre>INSERT INTO vectors_table (embedding) VALUES (&#39;[1,2,3]&#39;), (&#39;[4,5,6]&#39;);</pre><p>This command inserts two new rows into the vectors_table table with the provided embeddings.</p><h4>2. Vector Similarity Search with Diverse Distance Metrics:</h4><p>To retrieve vectors and calculate similarity, use SELECT statements and the built-in vector operators.</p><p>For instance, you can find the most similar item to a given embedding using the following query:</p><pre>SELECT * FROM vectors_table ORDER BY embedding &lt;-&gt; &#39;[3,1,2]&#39; LIMIT 1;</pre><p>This query computes the Euclidean distance (L2 distance) between the given vector and the vectors stored in the vectors_table table, sorts the results by the calculated distance, and returns the top 5 most similar vectors.</p><ul><li>pgvector also supports inner product (&lt;#&gt;) and cosine distance (&lt;=&gt;).</li></ul><p><strong>3. Indexing:</strong></p><p>Using an index on the vector column can improve query performance with a minor cost in recall.</p><p>You can add an index for each distance function you want to use. For example, the following query adds an index to the embedding column for the L2 distance function:</p><pre>CREATE INDEX ON vectors_table USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);</pre><p>pgvector currently supports Inverted File Flat (ivfflat) indexing algorithm for approximate nearest neighbor search.</p><h4>4. Speed:</h4><p>The integration of pgvector fortifies Greenplum’s capacity for vector semantic searches.</p><p>Rigorous performance testing conducted within our Greenplum lab cluster, involving three segment hosts on GCP compute engines of c2-standard-16c, yielded remarkable results.</p><p>Our cluster demonstrated less than 250 milliseconds for a Cosine search in Greenplum across a Vector Table containing 500 million rows, each vectors with 512 dimensions !</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Nr4oFKvneU2e7zav" /></figure><blockquote>Stay Tuned ! an upcoming blog post will provide further insights on Greenplum’s vector search performance.</blockquote><h4>5.<strong> </strong>Reliability (Fault Tolerance and High Availability):</h4><p>Greenplum data warehouse is a reliable distributed system, it has automated Fault Detection and Self-Healing.</p><ul><li>Failover and Load Balancing: Mirroring enables automatic failover mechanisms, where if a primary segment becomes inaccessible, traffic can be redirected to the mirrored segment. This load balancing ensures that queries and workloads continue to be processed even during failures.</li><li>Improved Data Integrity: Mirroring enhances data integrity by providing a second copy of the data that can be used for validation and comparison. This helps identify and rectify discrepancies or errors that may occur in the primary copy. Even if one copy of the data is compromised, the mirrored copy remains intact.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*Aw78Reo-m3jmCfsl" /></figure><h4>6. Distributed Architecture:</h4><p>Greenplum’s Massively Parallel Processing (MPP) architecture divides data and tasks across multiple nodes, enabling parallel processing. This design enhances query performance and fault tolerance, as tasks can be distributed and executed simultaneously.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/626/0*hqF8a-iMd20mJJN_" /></figure><h4>7. Scalability:</h4><p>Greenplum’s elastic scalability allows for easy expansion by adding more nodes, accommodating growing data and user demands without compromising performance.</p><h3>Conclusion:</h3><p>Through these comprehensive demonstrations, we not only validated the technological capabilities of VMware Greenplum and the pgvector extension but also demonstrated why it stands as great choice for companies willing to augment their data platforms for new AI/ML workloads.</p><p>As a modern data warehouse and a massive vector database, Greenplum offers an unmatched suite of features encompassing vector storage, lightning-fast query performance, fault tolerance, high availability, scalability, and more.</p><p>In the ever-evolving landscape of data analytics, Greenplum data platform does not only meet but exceeds the demands of modern businesses seeking advanced analytical capabilities. Its integration with the pgvector extension propels it to the forefront of the industry, equipping organizations with the tools they need to extract meaningful insights from vast amounts of vector data.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=870dcde1cedc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/aimonks/why-vmware-greenplum-as-a-massive-vector-database-for-your-analytical-needs-870dcde1cedc">Why VMware Greenplum as a Massive Vector Database for your Analytical needs ?</a> was originally published in <a href="https://medium.com/aimonks">𝐀𝐈 𝐦𝐨𝐧𝐤𝐬.𝐢𝐨</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Streaming CDC events from Any Database to Greenplum Data Warehouse using RabbitMQ and Debezium]]></title>
            <link>https://medium.com/greenplum-data-clinics/streaming-cdc-events-from-any-database-to-greenplum-data-warehouse-using-rabbitmq-and-debezium-5eccc678dfae?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/5eccc678dfae</guid>
            <category><![CDATA[rabbitmq]]></category>
            <category><![CDATA[change-data-capture]]></category>
            <category><![CDATA[debezium]]></category>
            <category><![CDATA[greenplum]]></category>
            <category><![CDATA[postgresql]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Sun, 23 Jul 2023 13:49:35 GMT</pubDate>
            <atom:updated>2023-07-24T15:06:26.686Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>Real-time analytics and seamless data integration are crucial for making informed business decisions in today&#39;s data-driven world. Change Data Capture (CDC) is a fundamental technology to capture and propagate data changes from various databases in real time. This blog post will explore how to achieve real-time CDC from any database to the Greenplum data warehouse using RabbitMQ Streams and Debezium.</blockquote><p>In this post, we will explore how Greenplum, an innovative and high-performance data warehouse for big data analytics and machine learning, can unleash the power of big data in real time. Additionally, we will delve into its advanced streaming capabilities that enable real-time data ingestion, processing, and analytics.</p><p>We will walk through the technical configuration and step-by-step instructions to set up this data pipeline.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kU7hJOKfR1fh9-crd3iXTQ.png" /></figure><h4>Understanding Change Data Capture (CDC)</h4><p>Change Data Capture is a technique used to capture and record changes made to a database, allowing applications to respond quickly to those changes. It tracks insert, update, and delete operations on database tables and transforms them into events. Downstream systems can then ingest this event stream for various purposes, including real-time analytics, data warehousing, and data integration.</p><h4>Introducing RabbitMQ (Streaming Events through RabbitMQ)</h4><p>RabbitMQ is a widely adopted message broker that facilitates the reliable exchange of messages between applications.</p><p>Last year, <a href="https://www.rabbitmq.com/streams.html">streams</a> were introduced, and today, RabbitMQ can be used to support many use cases, whether as a message broker, for message streams, or doing both in unison. It supports multiple messaging protocols and communication patterns, making it an ideal choice for streaming data from various sources to a destination like Greenplum.</p><p>Using the RabbitMQ streaming layer, we can decouple the data source from the data warehouse, ensuring better scalability, reliability, and fault tolerance.</p><h4>Leveraging Debezium for Change Data Capture</h4><p>Debezium is an open-source platform that specialises in CDC for databases. It supports various database management systems, including DB2, MySQL, PostgreSQL, MongoDB, Oracle, and SQL Server.</p><p>Debezium captures row-level changes from database transaction logs and transforms them into a CDC event stream. It also ensures data integrity and consistency during the capture process.</p><h4>Greenplum Streaming Capabilities</h4><p>Greenplum, a PostgreSQL-based massively parallel processing (MPP) data warehouse, offers a powerful streaming capability that enables real-time data ingestion from external sources.</p><p>With Greenplum Streaming Server (GPSS), organisations can efficiently process data streams and integrate them directly into the Greenplum database.</p><p>In our real-time CDC setup, GPSS plays a vital role in ingesting the data from RabbitMQ, as captured by Debezium, and populating CDC events to tables in Greenplum to INSERT, UPDATE or DELETE records.</p><p>As an integral part of Greenplum’s ecosystem, GPSS delivers unmatched streaming capabilities that streamline data pipelines and supercharge analytical insights. It can handle massive volumes of streaming data with exceptional scalability (proven with 10 million events per second with more than 500 Billion rows per day in a Multi-Trillion Greenplum Database and Running Analytics and ML on top of this Database).</p><h3>Real-time CDC from Any Database to Greenplum data warehouse</h3><p>As a source database, we will use PostgreSQL and enable real-time CDC to Greenplum; the following components are used in the configuration:</p><ul><li>PostgreSQL 15 database</li><li>Debezium Server 2.4</li><li>RabbitMQ 3.12.2</li><li>Greenplum 6.24 ( + Greenplum Streaming Server 1.10.1)</li></ul><p>To facilitate the execution of this demo, all components will be deployed using docker-compose:</p><pre>version: &quot;3.9&quot;<br>services:<br>  gpdb:<br>    image: docker.io/ahmedrachid/gpdb_demo:6.21<br>    depends_on:<br>      - rabbitmq<br>    privileged: true<br>    entrypoint: /usr/lib/systemd/systemd<br>    ports:<br>      - 5433:5432<br>    volumes:<br>      - ${PWD}/greenplum-db-6.24.0-rhel8-x86_64.rpm:/home/gpadmin/greenplum-db-6.24.0-rhel8-x86_64.rpm<br>      - ${PWD}/gpss-gpdb6-1.10.1-rhel8-x86_64.gppkg:/home/gpadmin/gpss-gpdb6-1.10.1-rhel8-x86_64.gppkg<br>      - ${PWD}/script_gpdb.sh:/home/gpadmin/script_gpdb.sh<br>  rabbitmq:<br>    image: rabbitmq:3-management-alpine<br>    container_name: rabbitmq<br>    ports:<br>      - 5672:5672<br>      - 15672:15672<br>      - 5552:5552<br>    environment:<br>      RABBITMQ_DEFAULT_PASS: root<br>      RABBITMQ_DEFAULT_USER: root<br>      RABBITMQ_DEFAULT_VHOST: vhost<br>  postgres:<br>    image: quay.io/debezium/example-postgres:2.1<br>    container_name: postgres<br>    ports:<br>      - 5432:5432<br>    environment:<br>      - POSTGRES_USER=postgres<br>      - POSTGRES_PASSWORD=postgres<br>  debezium-server:<br>    image: quay.io/debezium/server:2.4<br>    container_name: debezium-server<br>    ports:<br>      - 8080:8080<br>    volumes:<br>      - ./conf:/debezium/conf<br>    depends_on:<br>      - rabbitmq<br>      - gpdb<br>      - postgres</pre><p>The main configuration file for Debezium is conf/application.properties:</p><pre>debezium.sink.type=rabbitmq<br>debezium.sink.rabbitmq.connection.host=rabbitmq<br>debezium.sink.rabbitmq.connection.port=5672<br>debezium.sink.rabbitmq.connection.username=root<br>debezium.sink.rabbitmq.connection.password=root<br>debezium.sink.rabbitmq.connection.virtual.host=vhost<br>debezium.sink.rabbitmq.connection.port=5672<br>debezium.source.connector.class=io.debezium.connector.postgresql.PostgresConnector<br>debezium.source.offset.storage.file.filename=data/offsets.dat<br>debezium.source.offset.flush.interval.ms=0<br>debezium.source.database.hostname=postgres<br>debezium.source.database.port=5432<br>debezium.source.database.user=postgres<br>debezium.source.database.password=postgres<br>debezium.source.database.dbname=postgres<br>debezium.source.topic.prefix=tutorial<br>debezium.source.table.include.list=inventory.customers<br>debezium.source.plugin.name=pgoutput<br>debezium.source.tombstones.on.delete=false<br>debezium.sink.rabbitmq.routingKey=inventory_customers</pre><p>As you can see, we’re using Debezium to stream CDC events from a PostgreSQL table called inventory.customers to our RabbitMQ cluster.</p><h4>Deploy PostgreSQL database:</h4><p>Run the following Docker command to install &amp; deploy a preconfigured PostgreSQL container:</p><pre>docker compose up postgres -d</pre><p>You can now connect to the database and explore the table we’re using to stream CDC events:</p><pre>$ docker-compose exec postgres env PGOPTIONS=&quot;--search_path=inventory&quot; bash -c &#39;psql -U $POSTGRES_USER postgres -c &quot;SELECT * FROM customers;&quot;&#39;<br>  id  | first_name | last_name |         email<br>------+------------+-----------+-----------------------<br> 1001 | Sally      | Thomas    | sally.thomas@acme.com<br> 1002 | George     | Bailey    | gbailey@foobar.com<br> 1003 | Edward     | Walker    | ed@walker.com<br> 1004 | Anne       | Kretchmar | annek@noanswer.org<br>(4 rows)</pre><h4>Setup &amp; Configure RabbitMQ:</h4><p>To deploy our RabbitMQ cluster, we’ll use the same docker compose command as below:</p><pre>docker compose up rabbitmq -d</pre><p>Once you have deployed RabbitMQ using Docker Compose, you can configure it to suit your needs.</p><p>RabbitMQ provides a web-based management interface that you can use to configure various aspects of the RabbitMQ server.</p><p>To access the management interface, open a web browser and navigate to the IP address or domain name of your RabbitMQ instance, followed by the management port number (by default, 15672). In this example, you can access the management interface by navigating to <a href="http://localhost:15672.">http://localhost:15672</a></p><p>Once you have accessed the management interface, you can log in with the default credentials (root/root) or with the username and password specified in the Docker Compose file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/932/1*sK5Vgpoq3OcZaOZC4h58zA.png" /></figure><p>From the management interface, you should create the following:</p><ul><li>A new <strong>RabbitMQ</strong> <strong>Exchange</strong> called tutorial.inventory.customers</li><li>A new <strong>RabbitMQ</strong> <strong>Stream</strong> called inventory.customersand <em>bind</em> it to the tutorial.inventory.customers exchange using the <strong>routingKey</strong> inventory_customers</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZCNnVwSVm7OE51e0M4ET3Q.png" /></figure><h4>Setup &amp; Configure Debezium Server:</h4><p>At this point, our PostgreSQL and RabbitMQ containers are running, but we haven’t started our Debezium Server yet. To do so, we will run the following:</p><pre>docker compose up debezium-server -d</pre><p>Once done, you should see a new open connection to the RabbitMQ cluster:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ly9qIQ96iTW3gb95sV-wpw.png" /></figure><p>You should also see new messages in the RabbitMQ Stream ready to be consumed:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FDbIm6G61pDZLMmaMCtAAg.png" /></figure><h4>Setup Greenplum to ingest real-time CDC events:</h4><p>To enable real-time CDC from RabbitMQ to Greenplum, we have a Greenplum 6.24 instance, pre-configured with Greenplum Streaming Server 1.10.1:</p><p>Firstly, we need to deploy the Greenplum container:</p><pre>docker compose up gpdb -d</pre><p>Once done, we should now create a customers table to load CDC events:</p><pre>$ docker compose exec -ti gpdb bash<br>$ su - gpadmin<br>$ psql postgres -c &#39;CREATE TABLE public.customers (id INT, first_name TEXT, last_name TEXT, email TEXT) DISTRIBUTED BY (id);&#39;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9PRd7wFk32vP2AqQhWe-cg.png" /></figure><p>GPSS or Greenplum Streaming Server efficiently consumes and processes data streams streaming from Kafka and RabbitMQ (from a RabbitMQ queue or a RabbitMQ stream) into Greenplum Database.</p><p>It provides a flexible, scalable architecture that enables high-throughput data ingestion with minimal latency. GPSS is designed to handle various data formats, including TEXT, CSV, JSON, Avro, and more, making it well-suited for real-time CDC scenarios.</p><p>To start loading CDC events from RabbitMQ Stream, we should start our GPSS process using the following:</p><pre>nohup gpss &amp; </pre><p>Then, create our GPSS job with the configuration below:</p><pre>DATABASE: postgres<br>USER: gpadmin<br>HOST: localhost<br>PORT: 5432<br>VERSION: 2<br>RABBITMQ:<br>  INPUT:<br>    SOURCE:<br>      SERVER: root:root@rabbitmq:5552<br>      STREAM: inventory.customers<br>      VIRTUALHOST: vhost<br>    DATA:<br>      COLUMNS:<br>        - NAME: j<br>          TYPE: json<br>      FORMAT: json<br>    ERROR_LIMIT: 25<br>  OUTPUT:<br>      TABLE: customers<br>      MODE: MERGE<br>      MATCH_COLUMNS:<br>        - id<br>      DELETE_CONDITION: ((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;op&#39;)=&#39;d&#39;<br>      MAPPING:<br>           - NAME: id<br>             EXPRESSION: CASE WHEN ((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;op&#39;)=&#39;d&#39; THEN (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;before&#39;)::json-&gt;&gt;&#39;id&#39;)::int ELSE (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;after&#39;)::json-&gt;&gt;&#39;id&#39;)::int END<br>           - NAME: first_name<br>             EXPRESSION: CASE WHEN ((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;op&#39;)=&#39;d&#39; THEN (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;before&#39;)::json-&gt;&gt;&#39;first_name&#39;)::text ELSE (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;after&#39;)::json-&gt;&gt;&#39;first_name&#39;)::text END<br>           - NAME: last_name<br>             EXPRESSION: CASE WHEN ((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;op&#39;)=&#39;d&#39; THEN (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;before&#39;)::json-&gt;&gt;&#39;last_name&#39;)::text ELSE (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;after&#39;)::json-&gt;&gt;&#39;last_name&#39;)::text END<br>           - NAME: email<br>             EXPRESSION: CASE WHEN ((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;op&#39;)=&#39;d&#39; THEN (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;before&#39;)::json-&gt;&gt;&#39;email&#39;)::text ELSE (((j-&gt;&gt;&#39;payload&#39;)::json-&gt;&gt;&#39;after&#39;)::json-&gt;&gt;&#39;email&#39;)::text END</pre><p>Submit the GPSS job configuration:</p><pre>$ gpsscli submit gpss_job.yaml</pre><p>Start the GPSS job to begin capturing and processing data from RabbitMQ Stream:</p><pre>$ gpsscli start gpss_job</pre><p>Once started, you should now see customers job running:</p><pre>[gpadmin@df7ac82e5633 ~]$ gpsscli list<br><br>JobName                             JobID                               GPHost          GPPort  DataBase        Schema          Table                           Topic           Status<br>gpss_job                            7f40703e01734ad570c31b028fdfc615    localhost       5432    postgres        public          customers                                       JOB_RUNNING</pre><h4>Insert data into the PostgreSQL customers table:</h4><p>You should now see some data (4 records) coming into the Greenplum table, and you can also generate many CDC events by running INSERT/UPDATE or DELETEs on the source database.</p><p>Let’s insert some data dynamically:</p><pre>INSERT INTO customers (id, first_name, last_name, email)<br>SELECT i, <br>&#39;First_&#39; || i,<br>&#39;Last_&#39; || i,<br>&#39;first&#39; || i || &#39;.last&#39; || i || &#39;@example.com&#39; AS email<br>FROM generate_series(1010, 1000004) AS i;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OBr7iECpUY6N02_IBSM2uw.png" /></figure><h4>Real-time CDC data being applied on Greenplum:</h4><ul><li>After executing the <strong><em>INSERT INTO</em></strong> command, the CDC events are promptly applied to the Greenplum customers table in real time.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VC-2e8MynP86EoYPl5uEMg.png" /></figure><ul><li>On the other hand, you can <strong><em>UPDATE</em></strong> a record on the PostgreSQL source database:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NDOmcvvFzWSz1Vaf1deXsA.png" /></figure><p>As a result of this process, you can observe that the <strong><em>UPDATE</em></strong> event has been successfully applied on the Greenplum side, ensuring data consistency and synchronisation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QC1JEmaOB0Pw7qn637O0eQ.png" /></figure><h3>Conclusion</h3><p>Greenplum’s streaming capabilities, RabbitMQ Streams and Debezium together, form a robust and efficient real-time CDC pipeline from any database to Greenplum.</p><p>This setup empowers organisations to harness the power of real-time data analytics, making informed decisions based on the latest data insights. By leveraging Greenplum’s streaming capability, businesses can gain a competitive edge in today’s data-driven landscape.</p><h3>Authors</h3><p>This blog post was <strong>co-written</strong> with my colleague:<strong> </strong><a href="https://www.linkedin.com/in/martin-visser-65079326"><strong>Martin Visser</strong></a></p><h3>📝 References :</h3><ol><li>Open-source Greenplum data warehouse: <a href="https://greenplum.org/">https://greenplum.org/</a></li><li>VMware Greenplum data warehouse: <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html">https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html</a></li><li>Greenplum Streaming Server: <a href="https://docs.vmware.com/en/VMware-Greenplum-Streaming-Server/index.html">https://docs.vmware.com/en/VMware-Greenplum-Streaming-Server/index.html</a></li><li>RabbitMQ: <a href="https://www.rabbitmq.com/">https://www.rabbitmq.com/</a></li><li>Debezium: <a href="https://debezium.io/">https://debezium.io/</a></li></ol><blockquote><em>Thanks for reading! Any comments or suggestions are welcome! Check out other Greenplum articles </em><a href="https://medium.com/greenplum-data-clinics"><em>here</em></a><em>.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5eccc678dfae" width="1" height="1" alt=""><hr><p><a href="https://medium.com/greenplum-data-clinics/streaming-cdc-events-from-any-database-to-greenplum-data-warehouse-using-rabbitmq-and-debezium-5eccc678dfae">Streaming CDC events from Any Database to Greenplum Data Warehouse using RabbitMQ and Debezium</a> was originally published in <a href="https://medium.com/greenplum-data-clinics">Greenplum Data Clinics</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building large scale AI-powered search in Greenplum using pgvector and OpenAI]]></title>
            <link>https://medium.com/greenplum-data-clinics/building-large-scale-ai-powered-search-in-greenplum-using-pgvector-and-openai-4f5c5811f54a?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/4f5c5811f54a</guid>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[postgresql]]></category>
            <category><![CDATA[vector-database]]></category>
            <category><![CDATA[vector-search]]></category>
            <category><![CDATA[greenplum]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Mon, 29 May 2023 08:48:07 GMT</pubDate>
            <atom:updated>2023-06-10T12:33:54.141Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building large-scale AI-powered search in Greenplum using pgvector and OpenAI</h3><blockquote>The exponential progress of AI models over the past year, such as ChatGPT, inspired many organisations to enhance user experiences and unlock the full potential of their unstructured data, from texts to images to videos, by unleashing Generative AI and Large Language Models (LLMs).</blockquote><blockquote>In this blog post, you’ll learn how to harness the power of vector similarity search of <a href="https://github.com/pgvector/pgvector"><strong>pgvector</strong></a> extension within <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html"><strong>Greenplum</strong></a> data warehouse and combine it with OpenAI models to extract valuable insights from textual data at <em>Petabytes</em> <em>large</em> <em>scale</em> and take advantage of Greenplum’s incredible MPP architecture.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zob6O3iedyn2-csq3Wyg9w.png" /></figure><h3>Introduction:</h3><p>Companies started looking for technologies and ways to augment their data platforms for AI and use large language models for their Chatbots, Recommendation Systems or Search Engines…</p><p>But one specific challenge has been managing and deploying these AI models and storing and querying ML-generated <strong><em>embeddings</em></strong> at scale.</p><h3><strong>What are embeddings?</strong></h3><p><em>Embeddings</em> refer to transforming data or complex objects like texts, images or audio into a list of numbers in a high-dimensional space.</p><figure><img alt="Embeddings" src="https://cdn-images-1.medium.com/max/964/0*OTthsrDbQgZ5Suuv" /><figcaption>Source: <a href="https://openai.com/blog/introducing-text-and-code-embeddings">OpenAI</a></figcaption></figure><p>This technique is used in every machine learning (ML) or Deep Learning (DL) algorithm that enables capturing / understanding of the meaning and context of data (semantic relationships) and knowledge of complex relationships and patterns within the data (syntactic relationships).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*uMA9f5JnM39wE3DM" /><figcaption>Source: <a href="https://www.pinecone.io/learn/vector-embeddings/">https://www.pinecone.io/learn/vector-embeddings/</a></figcaption></figure><p>You can use the resulting vector representations for various applications, such as information retrieval, image classification, natural language processing, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AY67-3Y8H4M3WmYc" /><figcaption>Source: <a href="https://dev.to/josethz00/vector-databases-5df1">https://dev.to/josethz00/vector-databases-5df1</a></figcaption></figure><p>The following diagram visually represents what this looks like for word embeddings in 2D space.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4mR9_OGtOCWg0cnFVaRRjg.png" /><figcaption>Source: <a href="https://neon.tech/blog/building-an-ai-powered-chatbot-using-vercel-openai-and-postgres">https://neon.tech/blog/building-an-ai-powered-chatbot-using-vercel-openai-and-postgres</a></figcaption></figure><p>You can notice that semantically similar words are close together in the embedding. For example: “<em>apple</em>” word is closer to “<em>orange</em>” than “<em>dog</em>” or “<em>cat</em>”.</p><p>After generating embeddings, companies can perform similarity searches within the vector space and build an AI applications such as product recommendation systems ...</p><h3>Storing embeddings in Greenplum using pgvector</h3><p><a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html"><strong>Greenplum</strong></a><strong> 7</strong> is well equipped and ready to store and query Vector Embeddings at large scale thanks to <a href="https://github.com/pgvector/pgvector"><strong><em>pgvector</em></strong></a><strong><em> extension</em></strong>. This brings vector database capabilities to the Greenplum data warehouse, which enables users to perform fast retrieval and efficient similarity searches.</p><p>Using <a href="https://github.com/pgvector/pgvector">pgvector</a> in Greenplum, you can set up, operate, and scale databases for your ML-enabled applications.</p><p>For example, a streaming service can use pgvector to provide a list of film recommendations similar to the one you just watched.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yOgZzhqRop_7zOQv2YrHEA.png" /></figure><h3>Why Greenplum &amp; pgvector?</h3><p>Many companies would like to store, query and perform vector semantic searches within their Entreprise Data Warehouse without managing another Vector database.</p><p>Fortunately, combining Greenplum and pgvector lets you build fast + scalable applications using embeddings from AI models and get to production sooner.</p><h3>Build an AI-Assitant for your product documentation in Greenplum using pgvector and OpenAI.</h3><h4>Context:</h4><p>We have all used a Chatbot like ChatGPT before and found it great for casual, general-purpose question-answers, but you may have also noticed that ChatGPT falls short when deep and domain-specific knowledge is needed. Also, it makes up answers to fill its knowledge gaps and never cites its sources.</p><p><em>But how can we improve this? How can we build a ChatGPT that accurately searches suitable data sources and answers questions?</em></p><p><strong>TThe answer is:</strong> that making product documentation searchable and supplying a task-specific prompt to OpenAI can result in more reliable results. In other words, we will ask pgvector to search for a suitable dataset from the Greenplum table when a user asks a question. Then, we will provide it to OpenAI as a reference document to answer the users’ queries.</p><h4>Embeddings in practice:</h4><p>In this section, we will see embeddings in practice and learn how to use the open-source pgvector extension for Greenplum, which facilitates the storage of embeddings and enables querying for a vector’s nearest neighbours.</p><p>We demonstrate this functionality by building an Intelligent Chatbot using OpenAI and empowering it with Semantic Text Search to have more domain-specific knowledge about <a href="https://www.vmware.com/solutions/data-solutions.html"><strong><em>VMware Data Solutions</em></strong></a><strong><em>,</em></strong> capable of answering deep technical questions about <strong><em>Greenplum, RabbitMQ, Gemfire, VMware SQL </em>and<em> VMware Data Service Manager, </em></strong><em>as in the following figure:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y2c48NJzBTn0m1QUpLC1Bw.png" /></figure><p>The main steps are:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9XUkYYKnR5NWrrBBvYW-Uw.png" /></figure><ol><li><strong>Install &amp; Enable the pgvector extension.</strong></li></ol><p>Following successful <a href="https://github.com/pgvector/pgvector">installation</a>, you can start the storage of vector embeddings in Greenplum and perform semantic searches by enablingpgvectorrunning:</p><pre>CREATE EXTENSION vector;</pre><p><strong>2. Create a Product Documentation table with VECTOR data-type</strong></p><p>Next, let’s create a table to store our products documentation and their embeddings:</p><pre>CREATE TABLE tanzu_documents (<br>  id bigserial primary key,<br>  content text,<br>  embedding vector(1536)<br>)<br>DISTRIBUTED BY (id)<br>;</pre><p>pgvector introduces a new data type called a vector. We create an embedding column with the vector data type in the code above. The size of the vector defines how many dimensions the vector holds. OpenAI&#39;s text-embedding-ada-002 model outputs 1536 dimensions, so that we will use that for our vector size.</p><p>Since we’re using OpenAI API in this post, install the openai package on every Greenplum host running:</p><pre>gpssh -f gphostsfile -e &#39;pip3 install -y openai&#39;</pre><p>We also create a text column named content to store the original product documentation text that produced this embedding.</p><blockquote><strong>Note:</strong> The table above is distributed by<strong> the “id”</strong> column across Greenplum segments,pgvectorextension works seamlessly and perfectly with Greenplum features. Hence, adding pgvector’s efficiency in managing and searching through massive amounts of data to Greenplum’s MPP capabilities from distribution to partitioning enable Greenplum users to build scalable AI applications.</blockquote><p><strong>3. Greenplum PL/Python Function to get OpenAI embeddings</strong></p><p>Now, we should generate embeddings for our documents; here, we’ll use the OpenAI text-embedding-ada-002 model API to generate embeddings from the text.</p><p>The best way to do it is by creating a Python function inside Greenplum database leveraging<strong>PL/Python3u </strong>Procedural Language. The following Greenplum Python function returns a <strong>vector</strong>embeddings for each input document.</p><pre>CREATE OR REPLACE FUNCTION get_embeddings(content text)<br>RETURNS VECTOR<br>AS<br>$$<br><br>  import openai<br>  import os<br>  text = content<br>  openai.api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)<br>  response = openai.Embedding.create(<br>         model=&quot;text-embedding-ada-002&quot;,<br>         input = text.replace(&quot;\n&quot;,&quot; &quot;)<br>     )<br>  <br>  embedding = response[&#39;data&#39;][0][&#39;embedding&#39;]<br>  return embedding<br><br>$$ LANGUAGE PLPYTHON3U;</pre><p><strong>4. Data Loading to Greenplum table</strong></p><p>Load original texts into tanzu_documents table, specifically to<strong>content</strong> column, then update <strong>embedding</strong> column and generate OpenAI embeddings for every content using the previously created get_embeddings Python function :</p><pre>UPDATE tanzu_documents SET embedding  = get_embeddings(content);</pre><p><strong>5. First Semantic Search Query</strong></p><p>Let’s build our first semantic search query using <em>pgvector’s</em> <strong>cosine distance</strong> (using<strong> &lt;=&gt;</strong> <strong>operator</strong>) and find the most similar text to our question (i.e., the text with min distance): How to install Greenplum?</p><pre>WITH cte_question_embedding AS <br>  (<br>SELECT get_embeddings(&#39;How to create an external table in Greenplum using PXF to read from an Oracle database ?&#39;) <br>        AS question_embeddings <br>) <br><br>SELECT id, content, embedding &lt;=&gt; cte_question_embedding.question_embeddings AS distance <br>  FROM tanzu_documents, cte_question_embedding  <br>    ORDER BY embedding &lt;=&gt; cte_question_embedding.question_embeddings <br> ASC LIMIT 1 ;</pre><blockquote>pgvector introduces three new operators that can be used to calculate similarity: Euclidean distance (L2 distance) &lt;-&gt; , negative inner product&lt;#&gt;and cosine distance &lt;=&gt;</blockquote><p>The SELECT statement should return the following output:</p><pre>id       | 640<br>content  | title: Accessing External Data with PXF --- Data managed by your organisation may already reside in external sources such as Hadoop, object stores, and other SQL databases. The Greenplum Platform Extension Framework \(PXF\) provides access to this external data via built-in connectors that map an external data source to a Greenplum Database table definition. PXF is installed with Hadoop and Object Storage connectors. These connectors enable you to read external data stored in text, Avro, JSON, RCFile, Parquet, SequenceFile, and ORC formats. You can use the JDBC connector to access an external SQL database. &gt; **Note** In previous versions of the Greenplum Database, you may have used the `gphdfs` external table protocol to access data stored in Hadoop. Greenplum Database version 6.0.0 removes the `gphdfs` protocol. Use PXF and the `pxf` external table protocol to access Hadoop in Greenplum Database version 6.x. The Greenplum Platform Extension Framework includes a C-language extension and a Java service. After configuring and initialising PXF, you start a single PXF JVM process on each Greenplum Database segment host. This long-running process concurrently serves multiple query requests. For detailed information about the architecture of and using PXF, refer to the [Greenplum Platform Extension Framework \(PXF\)](https://docs.vmware.com/en/VMware-Greenplum-Platform-Extension-Framework/6.6/greenplum-platform-extension-framework/overview_pxf.html) documentation. **Parent topic:** [Working with External Data](../external/g-working-with-file-based-ext-tables.html) **Parent topic:** [Loading and Unloading Data](../load/topics/g-loading-and-unloading-data.html)<br>distance | 0.12006528354516588</pre><p><strong>6. Similarity Search SQL Function:</strong></p><p>Since we’re going to perform a similarity search over many embeddings. Let’s create a SQL function for that:</p><pre>CREATE OR REPLACE FUNCTION match_documents (<br>  query_embedding VECTOR(1536),<br>  match_threshold FLOAT,<br>  match_count INT<br>)<br><br>RETURNS TABLE (<br>  id BIGINT,<br>  content TEXT,<br>  similarity FLOAT<br>)<br><br>AS $$<br><br>  SELECT<br>    documents.id,<br>    documents.content,<br>    1 - (documents.embedding &lt;=&gt; query_embedding) AS similarity<br>  FROM tanzu_documents documents<br>  WHERE 1 - (documents.embedding &lt;=&gt; query_embedding) &gt; match_threshold<br>  ORDER BY similarity DESC<br>  LIMIT match_count;<br><br>$$ LANGUAGE SQL STABLE;</pre><p>We will be using the <em>match_documents</em> function and provide the most similar text to the OpenAI model as the following:</p><pre>SELECT t.id, t.content, t.similarity<br>  FROM match_documents(<br>          (select get_embeddings(&#39;How to create an external table in Greenplum using PXF to read from an Oracle database ?&#39;)) <br>           , 0.8<br>           , 1) t<br>; </pre><pre>id         | 640<br>content    | title: Accessing External Data with PXF --- Data managed by your organisation may already reside in external sources such as Hadoop, object stores, and other SQL databases. The Greenplum Platform Extension Framework \(PXF\) provides access to this external data via built-in connectors that map an external data source to a Greenplum Database table definition. PXF is installed with Hadoop and Object Storage connectors. These connectors enable you to read external data stored in text, Avro, JSON, RCFile, Parquet, SequenceFile, and ORC formats. You can use the JDBC connector to access an external SQL database. &gt; **Note** In previous versions of the Greenplum Database, you may have used the `gphdfs` external table protocol to access data stored in Hadoop. Greenplum Database version 6.0.0 removes the `gphdfs` protocol. Use PXF and the `pxf` external table protocol to access Hadoop in Greenplum Database version 6.x. The Greenplum Platform Extension Framework includes a C-language extension and a Java service. After configuring and initialising PXF, you start a single PXF JVM process on each Greenplum Database segment host. This long-running process concurrently serves multiple query requests. For detailed information about the architecture of and using PXF, refer to the [Greenplum Platform Extension Framework \(PXF\)](https://docs.vmware.com/en/VMware-Greenplum-Platform-Extension-Framework/6.6/greenplum-platform-extension-framework/overview_pxf.html) documentation. **Parent topic:** [Working with External Data](../external/g-working-with-file-based-ext-tables.html) **Parent topic:** [Loading and Unloading Data](../load/topics/g-loading-and-unloading-data.html)<br>similarity | 0.8775289173395486</pre><p><strong>7. Vectors Indexing:</strong></p><p>Our table may grow over time with embeddings, and we will likely want to perform a semantic search across billions of vectors.</p><p>What’s excellent about <em>pgvector</em> is its <strong>indexing</strong> capabilities to speed up queries and enable faster searching.</p><p>Vector indexes perform an exact nearest neighbour search (ANN/KNN); they are important to make ordering faster (<em>ORDER BY</em>clause) because vectors are not grouped by similarity, so finding the closest by <em>sequential</em> <em>scan</em> is a slow operation.</p><p>Each distance operator requires a different type of index. A good starting number of lists is rows / 1000 for up to 1M rows and sqrt(rows) for over 1M. Since we order by cosine distance, then we will usevector_cosine_ops index.</p><pre>-- Create a Vector Index <br>CREATE INDEX ON tanzu_documents <br>USING ivfflat (embedding vector_cosine_ops)<br>WITH<br>  (lists = 300);<br><br>-- Analyze table<br>ANALYZE tanzu_documents;</pre><blockquote>Read more about pgvector indexing here: <a href="https://github.com/pgvector/pgvector#indexing">https://github.com/pgvector/pgvector#indexing</a></blockquote><p><strong>8. Provide an OpenAI model with the right dataset for a relevant answer</strong></p><p>Build a PL/Python function that takes as input both: the user’s input and the most similar text to it then asks the OpenAI model to answer:</p><pre>CREATE FUNCTION ask_openai(user_input text, document text)<br>RETURNS TEXT<br>AS<br>$$<br><br>   import openai<br>   import os<br><br>   openai.api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)<br>   search_string = user_input<br>   docs_text = document<br><br>   messages = [{&quot;role&quot;: &quot;system&quot;,<br>                &quot;content&quot;: &quot;You concisely answer questions based on text provided to you.&quot;}]<br><br>   prompt = &quot;&quot;&quot;Answer the user&#39;s prompt or question:<br><br>   {search_string}<br><br>   by summarising the following text:<br><br>   {docs_text}<br><br>   Keep your answer direct and concise. Provide code snippets where applicable.<br>   The question is about a Greenplum / PostgreSQL database. You can enrich the answer with other<br>   Greenplum or PostgreSQL-relevant details if applicable.&quot;&quot;&quot;.format(search_string=search_string, docs_text=docs_text)<br><br>   messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: prompt})<br><br>   response = openai.ChatCompletion.create(model=&quot;gpt-3.5-turbo&quot;, messages=messages)<br>   return response.choices[0][&quot;message&quot;][&quot;content&quot;]<br><br>$$ LANGUAGE PLPYTHON3U;</pre><p><strong>9. Building a smarter search function</strong></p><p>As we mentioned before, ChatGPT doesn’t just return existing documents. It’s able to assimilate various information into a single, cohesive answer. To do this, we need to provide GPT with some relevant documents and a prompt that it can use to formulate this answer.</p><p>As a final step, we should combine previous functions into a single process to serve our Intelligent AI-Assitant application.</p><p>Our previous functions and Embeddings can help solve this by splitting prompts into a two-phased process:</p><ol><li>Query our embedding database for the most relevant documents related to the question.</li><li>Inject these documents as context for the OpenAI model to reference in its answer.</li></ol><pre>CREATE OR REPLACE FUNCTION intelligent_ai_assistant(<br>  user_input TEXT<br>)<br><br>RETURNS TABLE (<br>  content TEXT<br>)<br>LANGUAGE SQL STABLE<br>AS $$<br><br>  SELECT<br>    ask_openai(user_input, <br>              (SELECT t.content <br>                FROM match_documents(<br>                      (SELECT get_embeddings(user_input)) , <br>                        0.8, <br>                        1) t<br>                )<br>    );<br><br>$$;</pre><p>The SQL function above takes user input, converts it to embeddings, performs a semantic text search using <em>pgvector</em>on <em>tanzu_documents</em> table to find the most relevant documentation, and lastly feeds it as a reference text to OpenAI API call, which returns the final answer.</p><p><strong>10. Build our own Chatbot 🤖 empowered with Semantic Text Search capability using <em>OpenAI</em> and <em>Streamlit</em> 🎈</strong></p><p>Finally, we’ve developed a <em>Streamlit</em> <strong>🎈 </strong>Chatbot <strong>🤖 </strong>that understands our documents and uses the <em>Greenplum</em> data warehouse with <em>pgvector </em>semantic text search.</p><p><strong><em>This Chatbot Streamlit application is available here: </em></strong><a href="https://greenplum-pgvector-chatbot.streamlit.app/"><strong><em>https://greenplum-pgvector-chatbot.streamlit.app/</em></strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GpB3Q5gfTwdj3F66WkTxUw.png" /></figure><blockquote>You can find the source code here: <a href="https://github.com/ahmedrachid/streamlit-chatbot-greenplum">https://github.com/ahmedrachid/streamlit-chatbot-greenplum</a></blockquote><h3>🚀 Conclusion</h3><p>To conclude, companies wishing to build scalable AI applications can unleash <em>Greenplum</em> performance and massively parallel processing capabilities, combine it with the pgvectorto process, and perform fast retrieval, similarity and semantic search over massive amounts of vector embeddings and unstructured data.</p><h3>📝 References :</h3><ol><li>Open-source Greenplum data warehouse: <a href="https://greenplum.org/">https://greenplum.org/</a></li><li>VMware Greenplum data warehouse: <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html">https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html</a></li><li>pgvector extension - Open-source vector similarity search for Postgres: <a href="https://github.com/pgvector/pgvector">https://github.com/pgvector/pgvector</a></li></ol><blockquote><em>Thanks for reading! Any comments or suggestions are welcome! Check out other Greenplum articles </em><a href="https://medium.com/greenplum-data-clinics"><em>here</em></a><em>.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f5c5811f54a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/greenplum-data-clinics/building-large-scale-ai-powered-search-in-greenplum-using-pgvector-and-openai-4f5c5811f54a">Building large scale AI-powered search in Greenplum using pgvector and OpenAI</a> was originally published in <a href="https://medium.com/greenplum-data-clinics">Greenplum Data Clinics</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Greenplum for Data Science Blog Series Part 3: Scalable in-database Machine Learning & NLP with…]]></title>
            <link>https://medium.com/greenplum-data-clinics/greenplum-for-data-science-blog-series-part-3-scalable-in-database-machine-learning-nlp-with-f4ffba5eec1e?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/f4ffba5eec1e</guid>
            <category><![CDATA[sentiment-analysis]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[greenplum]]></category>
            <category><![CDATA[data-warehouse]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Thu, 30 Mar 2023 07:41:18 GMT</pubDate>
            <atom:updated>2023-03-30T07:41:18.226Z</atom:updated>
            <content:encoded><![CDATA[<h3>Greenplum for Data Science Blog Series Part 3: <strong>Scalable in-database Machine Learning &amp; NLP with PL/Python</strong></h3><blockquote>This blog constitutes the third part of the “Greenplum for End-to-End Data Science &amp; ML” series. In this article, we demonstrate combining <a href="https://www.vmware.com/products/greenplum.html">Greenplum Data Warehouse</a> MPP capabilities with Python’s rich ecosystem to make the end-to-end Machine Learning / NLP model development experience significantly faster.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fuHS6HVS5GRpmfOEnEslfw.png" /></figure><p>The figure below illustrates a much-needed paradigm shift when training and inferencing ML models on real-life, large datasets.</p><ul><li><strong>In-client</strong> machine learning requires data movement from the data source to the computing environment, but this approach becomes prohibitive when the amount of data used is large (e.g. 10s of GBs ~ PBs).</li><li><strong>In-database</strong> machine learning pushes the computing down to the data source, eliminating data movement and significantly increasing scalability and performance.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A9DoohDuEf9n9Yr6tWa1eA.png" /></figure><h3>Setup and connectivity</h3><h4>1. Install Packages</h4><pre>pip install ipython-sql pandas numpy sqlalchemy plotly-express sql_magic pgspecial</pre><h4>2. Import Packages</h4><pre>import pandas as pd<br>import numpy as np<br>import os<br>import sys<br>import plotly_express as px<br># For DB Connection<br>from sqlalchemy import create_engine<br>import psycopg2<br>import pandas.io.sql as psql<br>import sql_magic</pre><h4>3. Database Connectivity</h4><p>There are several ways to establish a connection to Greenplum. With a Jupyter notebook, one can use SQL magic. This allows running SQL queries in a Jupyter cell. Link to documentation: <a href="https://pypi.org/project/ipython-sql/">https://pypi.org/project/ipython-sql/</a> Installation on the client:</p><pre>pip install ipython-sql</pre><p>For use at the notebook level, it suffices to establish the connection:</p><pre>%load_ext _ sql<br>%sql postgresql://&lt;user&gt;:&lt;password&gt;@&lt;IP_address&gt;:&lt;port&gt;/&lt;database_name&gt;</pre><p>Then run the SQL commands in a cell like this:</p><pre>%%sql <br>SELECT version ();</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/997/1*L1sg0AR63BU5xW6_tTYUlQ.png" /></figure><p><em>You can also use the </em><a href="https://pypi.python.org/pypi/psycopg2"><em>psycopg2</em></a><em> connector or pyodbc (there are also other options via JDBC, for instance)</em></p><h3>Dataset Overview</h3><p>The dataset consists of 1967 stock market financial news written in English and categorised by sentiment.</p><p>Data Fields are:</p><ul><li><strong>docid</strong>: the unique identifier of financial news</li><li><strong>original_news</strong>: raw text of financial news</li><li><strong>label</strong>: a label corresponding to the class as a string: <strong><em>positive</em></strong> or <strong><em>negative</em></strong></li></ul><pre>%%sql<br>SELECT * FROM ds_demo.sentiment_news<br>LIMIT 5;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1004/1*rFY_i1Nmv4D4dYRMYbF-jA.png" /></figure><pre>%sql SELECT count(*) FROM ds_demo.sentiment_news;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/708/1*qz1EHfbl6ThIeuUWbR-pSw.png" /></figure><h3>NLP — Sentiment Analysis with PL/Python</h3><p><em>Sentiment analysis</em> aims to determine the sentiment strength from a textual source for sound decision-making; it’s widely used in financial companies to predict whether the news may positively or negatively influence the future stock price.</p><p>First, we’ll explore and visualise our dataset, combining <em>SQL</em> with <em>Pandas &amp; Plotly</em> Python packages.</p><h4>1. Sentiment classes distribution of our dataset:</h4><pre>%%read_sql df_count_sentiment<br>SELECT label, count(*) AS number_of_news<br>FROM ds_demo.sentiment_news<br>GROUP BY 1<br>ORDER BY 2 ASC</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/210/1*VI6IB856gYjo2oi2RbKRdQ.png" /></figure><pre>color_discrete_map = {&#39;negative&#39;: &#39;rgb(255,0,0)&#39;, <br>                      &#39;positive&#39;: &#39;rgb(0,255,0)&#39; }<br><br>px.pie(df_count_sentiment,<br>        values = &#39;number_of_news&#39;, <br>        names = &#39;label&#39;, <br>        color = &#39;label&#39;, <br>        color_discrete_map=color_discrete_map)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*mMkpt66XS1Z5A9t38_RGow.png" /></figure><p>The chart shows that our dataset is imbalanced; we have twice as positive news than negative news. This can impact our model performance and might result in underfitting in real-life data science projects.</p><h4>2. Number of Characters</h4><pre>%%read_sql df_max_length<br>SELECT max(length(original_news))<br>FROM ds_demo.sentiment_news;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/658/1*MrcSbCN66FLcaMzIk25ifw.png" /></figure><p>The most extended news of our dataset has less than 300 characters, which means that the sentiment can be captured from a short and synthetic text.</p><h4>3. Number of characters by sentiment class:</h4><pre>%%read_sql df_len_news<br>SELECT original_news, <br>       label, <br>       length(original_news) * 1.0 / max(length(original_news)) <br>       OVER (partition by NULL) AS ratio_chars<br>FROM ds_demo.sentiment_news</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/488/1*hns1-ukK9b_obPKb4UyS5w.png" /></figure><pre>px.box(df_len_news, <br>       y=&quot;ratio_chars&quot;, <br>       x =&#39;label&#39;,<br>       color=&#39;label&#39;, <br>       title = &#39;Number of characters distribution by sentiment class&#39;,<br>       color_discrete_map=color_discrete_map)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*HxTACFovpWsnSgw1aigFRQ.png" /></figure><h4>4. Number of words by sentiment class:</h4><pre>%%read_sql df_len_words<br>SELECT original_news, label, <br>       ARRAY_LENGTH(STRING_TO_ARRAY(original_news, &#39; &#39;), 1) <br>       AS number_of_words<br>FROM ds_demo.sentiment_news</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/515/1*KtO11U6CuNKBzR_MfVqWWA.png" /></figure><pre>px.box(df_len_words, <br>       y=&quot;number_of_words&quot;, <br>       x =&#39;label&#39;, <br>       color=&#39;label&#39;, <br>       title = &#39;Number of words distribution by sentiment class&#39;, <br>       color_discrete_map=color_discrete_map)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*YhvTre5_iJIDLFfnZsB9OA.png" /></figure><p>Positive news tends to have slightly more words and characters than negative news, but overall we can’t base our analysis on length.</p><h3>Data Preprocessing — Text Cleaning</h3><p>Text cleaning here refers to removing or transforming specific parts of the text so that the text becomes more easily understandable for NLP models learning the text. This often enables NLP models to perform better by reducing noise in text data.</p><p>To do that, we create a PL/Python and apply simple preprocessing actions:</p><ul><li>Firstly, change texts to lowercase.</li><li>Then, delete any special characters and URLs.</li><li>Finally, delete any multiple spaces.</li></ul><pre>%%sql <br>DROP FUNCTION IF EXISTS text_prepare(text);<br>CREATE OR REPLACE FUNCTION text_prepare( content text)<br>RETURNS text<br>AS $$<br>    import re     <br>    text = content<br>    replace_by_space_re = re.compile(&#39;[/(){}\[\]\|@,;]&#39;)<br>    bad_symbols_re = re.compile(&#39;[^0-9a-z #+_]&#39;)<br>    links_re = re.compile(&#39;(www|http)\S+&#39;)<br><br>    text = text.lower()  # lowercase text<br>    text = re.sub(replace_by_space_re,&quot; &quot;,text) <br>    text = re.sub(bad_symbols_re, &quot;&quot;,text) <br>    text = re.sub(links_re, &quot;&quot;,text) <br>    text = re.sub(&#39; +&#39;, &#39; &#39;, text)<br>    return text.strip()<br>$$ LANGUAGE plpython3u<br>;</pre><p>We store processed news in a new column called cleaned_text, which will be used for model training.</p><pre>%%sql <br>ALTER TABLE ds_demo.sentiment_news ADD COLUMN cleaned_text text;<br>UPDATE ds_demo.sentiment_news <br> SET cleaned_text = text_prepare(original_news::text);</pre><p>A quick overview of cleansed news:</p><pre>%sql SELECT * FROM ds_demo.sentiment_news LIMIT 2;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*Sp9FlOTcr-4XvDTW9eNo0g.png" /></figure><h3>Train a Sentiment Analysis model with PL/Python</h3><p>Training a Natural Language Processing model to automatically predict the Sentiment of financial news can help traders and investors to build their trading/quantitative strategies.</p><p>Sentiment analysis is a text classification task. In this section, we use the <strong>Bag of Words technique</strong> to convert texts into numerical representation such that the same can be used to train a <strong>Logistic Regression</strong> model.</p><h4>Model training — Term Frequency Logistic Regression</h4><p>Let’s write PL/Python function that can be called like any other SQL function. The integration is effortless, as Python has endless libraries for Machine Learning.</p><p>Moreover, besides giving full support to Python, PL/Python also provides convenient functions to run any parametrised query. So, executing Machine Learning algorithms can be a question of a couple of lines.</p><p>Let’s take a look:</p><pre>%%sql <br>DROP FUNCTION IF EXISTS train_sentiment_news(text[],text[]);<br>DROP TYPE IF EXISTS news_type;<br>-- Create a new type for our PL/Python function output<br>CREATE type news_type AS (content text, label text, prediction text);<br>-- PL/Python function using Python3.9<br>CREATE FUNCTION train_sentiment_news( cleaned_text text[], label text[])<br>RETURNS SETOF news_type<br>AS $$<br>    import pandas as pd<br>    from sklearn.feature_extraction.text import CountVectorizer<br>    from sklearn.model_selection import train_test_split<br>    from sklearn.linear_model import LogisticRegression<br><br>    X = cleaned_text<br>    y = label<br>    df= pd.DataFrame()<br>    df[&#39;content&#39;] = X<br>    df[&#39;label&#39;] = y<br>    X_train, X_test, y_train, y_test = train_test_split(df[&#39;content&#39;], df[&#39;label&#39;], test_size=0.2, random_state=42)<br><br>    vectorizer = CountVectorizer(min_df=4, stop_words=&#39;english&#39;)<br><br>    X_train = vectorizer.fit_transform(X_train)<br>    X_test = vectorizer.transform(X_test)<br><br>    # LOGISTIC REGRESSION<br>    logreg = LogisticRegression()<br>    # TRAIN <br>    logreg.fit(X_train, y_train)<br>    X = vectorizer.transform(df[&#39;content&#39;])<br>    # PREDICTIONS ON FULL DATASET <br>    lr_prediction = logreg.predict(X)<br>    df[&#39;prediction&#39;] = lr_prediction<br>    <br>    return [{&#39;content&#39;: str(row[&#39;content&#39;]), <br>             &#39;label&#39;: str(row[&#39;label&#39;]), <br>             &#39;prediction&#39;: str(row[&#39;prediction&#39;])} <br>            for index, row in df.iterrows()]<br><br>$$ LANGUAGE plpython3u;</pre><p>As you can see, PL/Python is straightforward.</p><ul><li>Firstly, we import the packages we need; we use pandas and scikit-learn libraries.</li><li>We need to load inputs (news and labels) into a dataframe and transform the numeric variables into numeric type using <em>Bag of Words / CountVectorizer</em></li><li>Then, we call <em>Logistic Regression</em> and train it on the training set (80% of our dataset).</li><li>Finally, we return the prediction on the whole dataset as a list of news_type types.</li></ul><p>The final line specifies the extension language: in this case, we are using Python3, and for that reason, the extension is called plpython3u. If you want to execute it in Python2, use the extension language named plpythonu.</p><p>Greenplum also provides another language handler, PL/Container, which runs PL/Container in a Docker. The execution could indeed be safer.</p><h4>Show predictions</h4><p>We can check predictions made by our model.</p><p>The function train_sentiment_news() takes two arrays as inputs, so we need to apply ARRAY_AGG() function to concatenate all records of columns cleaned_text and labels together as two arrays.</p><p>Furthermore, since train_sentiment_news() returns a set of new_type, we need to decompose every record of results into different columns using CTEs (Common Table Expression).</p><pre>%%read_sql df_preds<br>WITH cte_data_array_agg AS (<br>        SELECT ARRAY_AGG(cleaned_text) AS contents, <br>                ARRAY_AGG(label) AS labels <br>        FROM ds_demo.sentiment_news<br>    ),<br>    cte_predictions AS (<br>        SELECT train_sentiment_news(t.contents, t.labels) <br>        FROM cte_data_array_agg<br>    )<br>SELECT (train_sentiment_news::news_type).* FROM cte_predictions;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/461/1*dZ-lWTW1-bWwEs7TCJ2aOg.png" /></figure><h4>Model Evaluation</h4><p>Now, let’s evaluate our model by calculating: <em>Accuracy, F1-score, Precision, Recall</em></p><pre>%%sql <br>DROP FUNCTION IF EXISTS metrics_report(text[],text[]);<br>DROP TYPE IF EXISTS prediction_type;<br>CREATE type prediction_type AS (accuracy float, f1_score float, precision float, recall float);<br>CREATE OR REPLACE FUNCTION metrics_report(label text[], prediction text[])<br>RETURNS prediction_type<br>AS $$<br>    from sklearn.metrics import precision_recall_fscore_support as score<br>    from sklearn.metrics import accuracy_score<br>    import numpy as np<br><br>    y_true = label<br>    y_pred = prediction<br><br>    accuracy = accuracy_score(y_true, y_pred)<br>    precision, recall, f1_score, support = score(y_true, y_pred)<br><br>    precision = float(np.mean(precision))<br>    f1_score = float(np.mean(f1_score))<br>    recall = float(np.mean(recall))<br>    accuracy = float(accuracy)<br><br>    return {&#39;accuracy&#39;: accuracy,<br>            &#39;f1_score&#39;: f1_score,<br>            &#39;precision&#39;: precision,<br>            &#39;recall&#39;: recall<br>    }<br>$$ LANGUAGE plpython3u<br>;</pre><p>We apply ARRAY_AGG() to concatenate columns and decompose composite-type results using CTEs.</p><pre>%%read_sql df_preds<br>WITH<br>  cte_data_array_agg AS (<br>    SELECT ARRAY_AGG(cleaned_text) AS contents, ARRAY_AGG(label) AS labels <br>      FROM ds_demo.sentiment_news<br>  ),<br>  cte_predictions AS (<br>      SELECT train_sentiment_news(t.contents, t.labels) <br>      FROM cte_data_array_agg<br>  ),<br>  cte_label_pred AS (<br>    select (train_sentiment_news::news_type).* <br>      FROM cte_predictions<br>  ),<br>  cte_metrics_report AS (<br>      SELECT metrics_report(array_agg(label), array_agg(prediction)) <br>      FROM cte_label_pred<br>  )<br><br>SELECT (metrics_report::prediction_type).* FROM cte_metrics_report</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/289/1*1pfl10VHrX0nhJ50vJckUQ.png" /></figure><p>The model has achieved an accuracy of 92.93%, whereas recall and precision are slightly lower than accuracy.</p><h3>Model Deployment — Storing the model</h3><p>It doesn’t make much sense to create a model and not do anything with it. So, we will need to store it as binaries using the <strong><em>“bytea”</em></strong> data type.</p><h4>Store it as binary in a SQL table</h4><pre>%%sql <br>DROP FUNCTION IF EXISTS save_nlp_models(text[],text[]);<br>DROP TYPE IF EXISTS model_type CASCADE;<br>CREATE TYPE model_type as (model_logreg bytea, model_bow bytea);<br>CREATE FUNCTION save_nlp_models(cleaned_text text[], label text[])<br>RETURNS model_type<br>AS $$<br><br>    import pandas as pd<br>    from sklearn.feature_extraction.text import CountVectorizer<br>    from sklearn.model_selection import train_test_split<br>    from sklearn.linear_model import LogisticRegression<br>    import pickle<br>    <br>    X = cleaned_text<br>    y = label<br>    df= pd.DataFrame()<br>    df[&#39;content&#39;] = X<br>    df[&#39;label&#39;] = y<br>    X_train, X_test, y_train, y_test = train_test_split(df[&#39;content&#39;], <br>                                                        df[&#39;label&#39;], <br>                                                        test_size=0.2, <br>                                                        random_state=42)<br><br>    vectorizer = CountVectorizer(min_df=4, stop_words=&#39;english&#39;)<br><br>    X_train = vectorizer.fit_transform(X_train)<br>    X_test = vectorizer.transform(X_test)<br><br>    # LOGISTIC REGRESSION<br>    logreg = LogisticRegression()<br>    logreg.fit(X_train, y_train)<br>    X = vectorizer.transform(df[&#39;content&#39;])<br>    lr_prediction = logreg.predict(X)<br>    df[&#39;prediction&#39;] = lr_prediction<br>    <br>    # Save Logistic Regression model<br>    model_logreg = pickle.dumps(logreg)<br>    # Save CountVectorizer <br>    model_countvectorizer = pickle.dumps(vectorizer)<br>    <br>    return {&#39;model_logreg&#39;: model_logreg<br>            ,&#39;model_bow&#39;: model_countvectorizer}<br>$$ LANGUAGE plpython3u<br>;</pre><p>To do so, let’s create a table ds_demo.saved_models to save the model first:</p><pre>%%sql<br>DROP TABLE IF EXISTS ds_demo.saved_models;<br>CREATE TABLE ds_demo.saved_models (model_logreg bytea, <br>                                   model_bow bytea, <br>                                   model_name text);</pre><p>In this case, our table has just a model_name and two byte array fields (one for Logistic Regression and the other for Bag of Words) that is the actual model serialised. Please note that it is the same data type as the one that our defined Scikit-learn models return.</p><p>Once we have the table, we can easily insert a new record with the model:</p><pre>%%sql<br>WITH cte_models AS (<br>        SELECT save_nlp_models(t.contents, t.labels) <br>    FROM (<br>        SELECT ARRAY_AGG(cleaned_text) AS contents, <br>               ARRAY_AGG(label) AS labels <br>          FROM ds_demo.sentiment_news) t<br>      ),<br>    cte_casted_model AS (<br>        SELECT (save_nlp_models::model_type).* <br>        FROM cte_models)<br>    <br>INSERT INTO ds_demo.saved_models <br>SELECT model_logreg, model_bow, &#39;nlp_sentiment_analysis_bow_logreg&#39; AS model_name FROM cte_casted_model;</pre><h4>Show binaries</h4><pre>%%sql <br>SELECT model_name, model_logreg::text, model_bow::text <br>FROM ds_demo.saved_models;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/1*1_KrlcS_wUydhNNEY84JKQ.png" /></figure><h4>Displaying Model Info</h4><p>So far, we have been able to create a model and store it. But getting it directly from the database isn’t very useful.</p><p>Therefore, we must return to Python to display useful information about our model. This is the function we are going to use:</p><pre>%%sql<br>DROP FUNCTION get_model_info(text,text,text);<br>CREATE OR replace FUNCTION get_model_info(model_table text, model_column text, model_name text) <br>RETURNS text<br>AS $$<br>    from pandas import DataFrame<br>    import pickle<br>    rv = plpy.execute(&#39;SELECT %s FROM %s WHERE model_name = %s;&#39; % (plpy.quote_ident(model_column), model_table, &quot;&#39;&quot;+model_name+&quot;&#39;&quot;))<br>    model = pickle.loads(rv[0][model_column])<br>    <br>    return str(model.get_params())<br> <br>$$ LANGUAGE plpython3u;</pre><p>Let’s start from the beginning: we are passing, again, the table containing the models and the column that holds the binary. The pickle.load() function reads the output.</p><p>(<em>Here, you can see how results from a plpython query </em><em>plpy.execute are loaded into Python</em>).</p><p>Once the model is loaded, we return model.get_params(), where our logistic regression parameters are stored.</p><p>This is just an example of how to output a specific model feature. You can create similar functions to return other features or even all features.</p><p>Let’s take a look at what it returns:</p><pre>%%sql<br>select get_model_info(&#39;ds_demo.saved_models&#39;,&#39;model_logreg&#39;,&#39;nlp_sentiment_analysis_bow_logreg&#39;);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/999/1*50zl1LvLIvNH_fT7xoDqqg.png" /></figure><h3>Model inference — predict new data-feed</h3><p>Now that we have a model let’s use it to make predictions! Invoking the model is simple and can be done in SQL using PL/Python.</p><pre>%%sql <br>DROP FUNCTION IF EXISTS predict_sentiment(text, bytea, bytea);<br>CREATE FUNCTION predict_sentiment(cleaned_text text, model_logreg bytea, model_bow bytea)<br>RETURNS text<br>AS $$<br>    import pickle<br>    <br>    logreg = model_logreg<br>    vectorizer = model_bow<br>    texts = cleaned_text<br>    <br>    # Save Logistic Regression model<br>    model_logreg_bytes = pickle.loads(logreg)<br>    # Save CountVectorizer <br>    model_countvectorizer = pickle.loads(vectorizer)<br>    <br>    return list(model_logreg_bytes.predict(model_countvectorizer.transform([texts])))[0]<br>$$ LANGUAGE plpython3u<br>;</pre><p>Compared to the previous function, we add one input parameter (cleaned_text), passing the input representing a piece of financial news for which we want to get the sentiment.</p><pre>%%sql<br>SELECT content, predict_sentiment(text_prepare(t.content), b.model_logreg, b.model_bow)<br>FROM<br>   ds_demo.financial_news t,<br>    ds_demo.saved_models b <br>LIMIT 5;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/379/1*UUVpLGiQ0Ok0L7RHsPbKJw.png" /></figure><p>We can now process larger datasets and show positive/negative news distribution.</p><pre>%%sql<br>SELECT predict_sentiment, count(*)<br>FROM (<br>  SELECT content, predict_sentiment(t.content, b.model_logreg, b.model_bow)<br>  FROM<br>    ds_demo.financial_news t,<br>    ds_demo.saved_models b <br>    LIMIT 10000<br>  ) results<br>GROUP BY 1;</pre><h3>Conclusion</h3><p>We have seen in this article that you can train and use NLP &amp; Machine Learning without leaving the <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-overview.html"><strong>Greenplum data warehouse</strong></a>. Greenplum has strong analytical capabilities that make them well suited for data science problems at a massive scale.</p><p>Using <a href="https://greenplum.org/">Greenplum’s</a> in-database Machine Learning capabilities in <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-pl_python.html"><em>PL/Python</em></a> and <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-pl_r.html"><em>PL/R</em></a><em> </em>enable data scientists to harness the vast ecosystem of machine-learning libraries in <em>Python and R</em> to analyse massive datasets.</p><blockquote>If you have enjoyed this post, stay tuned for our next entry in the series on Data Science with <a href="https://greenplum-db.github.io/GreenplumPython/stable/"><strong>GreenplumPython</strong></a>, a Python wrapper for Greenplum and PostgresQL, which further enhances the data scientist’s user experience when working with big data.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f4ffba5eec1e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/greenplum-data-clinics/greenplum-for-data-science-blog-series-part-3-scalable-in-database-machine-learning-nlp-with-f4ffba5eec1e">Greenplum for Data Science Blog Series Part 3: Scalable in-database Machine Learning &amp; NLP with…</a> was originally published in <a href="https://medium.com/greenplum-data-clinics">Greenplum Data Clinics</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Greenplum for Data Science Blog Series Part 1: Big Data Analysis with SQL and Python]]></title>
            <link>https://medium.com/greenplum-data-clinics/greenplum-for-data-science-blog-series-part-1-big-data-analysis-with-sql-and-python-e034203ecba9?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/e034203ecba9</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[greenplum]]></category>
            <category><![CDATA[sql]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Thu, 16 Mar 2023 15:03:39 GMT</pubDate>
            <atom:updated>2023-03-20T11:34:56.746Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This article is the first part of the “Greenplum for End-to-End Data Science &amp; ML” blog series, which covers how to use <strong>Greenplum’s Integrated In-Database Analytics</strong> functions to tackle data science projects from experimentation to massive deployment.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8_mOLUJ_JvgDOxhKhpbUxA.png" /></figure><h3>The Growth, Challenge, and Opportunity of Data</h3><p>We are in the digital age, and everything we do with our smartphones, tablets, computers, and even household appliances produces an enormous amount and variety of data. While this may sound exciting, collecting data for the sake of having more data is not a meaningful exercise or a productive one. We need to understand what user goals or business outcomes might benefit from this data and invest the time and effort to extract value from the data. And this is where data scientists come into the picture.</p><h3>How Data Scientists Might Help</h3><p>Among all fields related to data, data science is a field of study that leverages data and quantitative modelling to build meaningful outcomes for users. The data scientist engages in a wide range of activities in this context, including but not limited to the following:</p><ol><li>Partnering with designers to build empathy with users to understand their needs and explore how we might use data and algorithms to delight them</li><li>Prioritise what to build next with product managers.</li><li>Collaborate with data engineers on identifying and preparing data for analysis.</li><li>Explore data and build machine models to serve user needs — most commonly coding in Python, R, or SQL.</li><li>Integrate with software engineers to deploy models as services to be consumed by applications or directly by users.</li><li>Iteratively repeat (1)-(5) to continuous drive value for users</li></ol><h3>Focus for this Series: Technical Approaches &amp; Tools to Extract value from Big Data</h3><p>The activities listed above include aspects related to how data scientists work (e.g., user-centred, lean, agile) and also the tools &amp; technologies needed to be most productive. We focus this technical blog series on the tooling component primarily related to (4) in the list above.</p><p>Specifically, we explore scenarios where the data scientist explores data and builds machine-learning models with a massive set of data. In this context, the data scientist may encounter particular technical challenges, including the following:</p><ul><li>Slow data science pipeline with large data volumes</li><li>Hitting the ceilings of memory and computing in traditional Python/R runtimes</li><li>Limited analytical functionality in platforms that enable big data computing</li></ul><p>This series of technical blog posts addresses these challenges, focusing on <a href="https://www.vmware.com/products/greenplum.html#:~:text=VMware%20Greenplum%20is%20a%20massively,premises%20and%20in%20the%20cloud."><strong>VMware Greenplum</strong></a> as a critical enabling technology.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*BN02VnzwkXj_O99m" /></figure><h3>Why Greenplum?</h3><p>Exporting data from a database and importing it into a server or desktop environment with commonly used tools for data science (e.g. Python, R) is not an ideal workflow for big data analytics. As described above, data scientists may need help with these tools&#39; memory and scalability limitations and restrictive bottlenecks associated with transferring large amounts of data between different platforms.</p><p>This is where leveraging the right tool becomes an important decision for the data scientist. In this post, we focus on <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-landing-index.html">Greenplum</a>, a massively parallel processing PostgreSQL engine which provides built-in tools for data scientists for high-scale data exploration and model training. These tools and extensions include:</p><ul><li><a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-madlib.html"><strong><em>Apache MADlib</em></strong></a> for machine learning</li><li><a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-intro.html"><strong><em>Procedural language extensions</em></strong></a> to massively parallelise Python &amp; R</li><li><a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-analytics-postGIS.html?hWord=N4IghgNiBcIA4HsDOAXA5gSySAvkA"><strong><em>PostGIS</em></strong></a> for geospatial analytics and <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum-Text/3.10/tanzu-greenplum-text/GUID-topics-intro.html"><strong><em>GPText</em></strong></a> for text search and processing</li><li>Interoperability with dashboarding tools such as Tableau, PowerBI…</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sA9sXLXgF7J3S8YEUybXfQ.jpeg" /></figure><p>In this post, we describe how to start with Greenplum and share examples of how a data scientist might use the abovementioned tools.</p><h3>Part 1: Setup and connectivity</h3><ol><li><em>Install packages:</em></li></ol><pre>!pip install ipython-sql pandas numpy sqlalchemy plotly-express sql_magic pgspecial</pre><p><em>2. Import packages:</em></p><pre>import pandas as pd<br>import numpy as np<br>import os<br>import sys<br>import plotly_express as px<br># For DB Connection<br>from sqlalchemy import create_engine<br>import psycopg2<br>import pandas.io.sql as psql<br>import sql_magic</pre><p><em>3. Greenplum Database Connectivity:</em></p><p>There are several ways to establish a connection to Greenplum. With a Jupyter notebook, one can use <a href="https://pypi.org/project/ipython-sql/">SQL magic</a>. This allows running SQL queries in a Jupyter cell.</p><ul><li>Installation on the client:</li></ul><pre>!pip install ipython-sql</pre><p>For use at the notebook level, it suffices to establish the connection:</p><pre>% load_ext _ sql<br>% sql postgresql://&lt;user&gt;:&lt;password&gt;@&lt;IP_address&gt;:&lt;port&gt;/&lt;database_name&gt;</pre><p>Then run the SQL commands in a cell like this:</p><pre>%% sql <br>SELECT version ();</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qXifaDd4v3CGPJ24OS5ENA.png" /></figure><p><em>You can also use the </em><a href="https://pypi.org/project/psycopg2/"><em>psycopg2 connector</em></a><em> or pyodbc (there are also other options via JDBC, for instance)</em></p><h3>Part 2: Dataset Overview</h3><p>In this blog series, a <a href="https://www.kaggle.com/datasets/miguelaenlle/massive-stock-news-analysis-db-for-nlpbacktests"><strong>Daily Financial News for stocks</strong></a> dataset from Kaggle with Licence <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0: Public Domain</a> has been selected for use. We will use Greenplum and follow the data science cycle (Data Exploration — Data Preparation — Data Modelling — Model Evaluation — Model Deployment) to train an NLP model to process Sentimental Analysis for news.</p><p>The dataset contains Raw headlines from <em>Benzinga.com</em> and its partners. Its size is augmented up to around <strong>four million rows</strong>, which is quite an extensive dataset for manipulation, and it has <strong>seven columns</strong>:</p><ul><li><em>docid</em> — integer: index unique</li><li><em>title</em> — text: headline of Row</li><li><em>content</em> — text: equivalent to the title</li><li><em>url</em> — text: link related to News</li><li><em>publisher</em> — text: News publisher</li><li><em>date</em> — date: publish date</li><li><em>stock</em> — text: stock tickers symbol related to News</li></ul><p>To begin with this dataset, we will process an <strong>Exploratory Data Analysis with SQL</strong> command, including Greenplum Functions, without using other extensions (which will be discovered in the following blogs of the series).</p><h3>Part 3: Data Preparation</h3><p>The dataset is saved in the table source_financial_news. Let&#39;s take a look at one row of this table:</p><pre>%%sql<br>SELECT * FROM source_financial_news LIMIT 1;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qf1U368OhbwNaJumM2TroA.png" /></figure><p>How many rows it contains precisely:</p><pre>%%sql<br>SELECT count(*) FROM source_financial_news;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/99/1*5XoZ4h0gt8BU9OMDC1__4Q.png" /></figure><h4>Partitioned table for better analytical performance</h4><p>Since old news won’t be used frequently, let’s create a table ds_demo.financial_news partitioned by datewhere we are interested only in News published after 2010.</p><p>Setting the distributed key to the unique index docid allows data to be distributed equitably across different segments.</p><p>Moreover, setting storage to column-oriented and <em>appendoptimized</em> to True improves the analytical performance overall.</p><pre>%%sql <br>DROP TABLE IF EXISTS ds_demo.financial_news;<br>CREATE TABLE ds_demo.financial_news <br>(<br>    LIKE source_financial_news<br>)<br>WITH (appendoptimized=true, orientation=column)<br>DISTRIBUTED BY(docid)<br>PARTITION BY RANGE (date)<br>(<br>    START (date &#39;2010-01-01&#39;) INCLUSIVE<br>    END (date &#39;2024-01-01&#39;) EXCLUSIVE<br>    EVERY (INTERVAL &#39;1 month&#39;), <br>    DEFAULT PARTITION old_news<br>);<br><br>-- Insert data from the source table into a newly created partitioned table<br>INSERT INTO ds_demo.financial_news SELECT * FROM source_financial_news;</pre><p>Thanks to command \d+, a description of the newly created Analytical table is shown below:</p><pre>%sql \d+ ds_demo.financial_news</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/1*_4rApcZbf4dGr0I9hL3FzQ.png" /></figure><p><strong>Note:</strong> <em>With Greenplum 7, partitions don’t need to follow the same settings, and users can customise them according to their needs.</em></p><h4>Check that our table is evenly distributed</h4><p>Now our new table has been created, let’s check its distribution by calculating the standard deviation of the number of rows per segment.</p><pre>%%sql<br>-- Standard deviation to check table distribution<br>SELECT STDDEV(count) <br>FROM (<br>    SELECT gp_segment_id, COUNT(*)<br>    FROM ds_demo.financial_news<br>    GROUP BY 1<br>) table_distribution ;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/159/1*CUUlN0Ef5z_5injMlGH-GQ.png" /></figure><p>The standard deviation score is low (399.5784) compared to the mean 163383.333. Our table is evenly distributed!</p><h4>Partitions to scan only needed data</h4><p>With Partitions, there is no need to scan the older partitions at all to answer the query below.</p><pre>%%sql<br>-- Show the execution plan &quot;EXPLAIN&quot; and check scanned partitions<br>EXPLAIN SELECT COUNT(*) <br>        FROM ds_demo.financial_news <br>          WHERE date &gt;= &#39;2020-01-01&#39;::date</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/772/1*-QzvOvrCgBa5zyc4CoPiow.png" /></figure><p>Furthermore, if we add a superior condition sup_date on date, there is no need to scan partitions with date superior to sup_date</p><h3>Part 4: Exploratory Data Analysis with SQL &amp; MADlib</h3><p>After preparing our ds_demo.financial_news table, we will use SQL (sqlmagic for interactive results with the Greenplum database) and <strong>MADlib</strong>, an open-source SQL-based library for <strong>scalable in-database analytics</strong>.</p><p>It provides <strong>data-parallel implementations</strong> of mathematical, statistical, graph and machine learning methods for structured and unstructured data.</p><h4>1. Another overview of the first two rows of Table</h4><pre>%%sql <br>SELECT * FROM ds_demo.financial_news LIMIT 2 ;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*q5EyKIHv-geAe34ftvayEA.png" /></figure><h4>2. Apache MADlib for robust and powerful statistics using SQL</h4><ul><li>Make sure that the MADlib extension is enabled!</li></ul><pre>%sql SELECT madlib.version();</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sgrMBzNMQgWFhzrbK0CC7Q.png" /></figure><p><strong><em>2.1. Statistical description of the table — MADlib</em></strong></p><p>MADlib’s summary() function produces summary statistics for any data table. The function invokes various methods from the MADlib library to provide the data overview.</p><pre>%%sql<br>DROP TABLE IF EXISTS ds_demo.financial_news_summary;<br>SELECT * FROM madlib.summary( <br>        &#39;ds_demo.financial_news&#39;, &#39;ds_demo.financial_news_summary&#39;  <br>);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/1*5GQM_AnhWRJj6MkyegJyTw.png" /></figure><p>The output of the function summary() is saved in the table ds_demo.financial_news_summary.</p><pre>%%sql<br>SELECT <br>    target_column, distinct_values, missing_values, blank_values, <br>    min, max, mean, median, variance, most_frequent_values<br>FROM ds_demo.financial_news_summary;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2vkWyK9WdgspAvmtggjC_w.png" /></figure><h4>3. Number of news per date</h4><p>To see the evolution of the number of news over the months:</p><ol><li>Firstly, convert the date column into Year-Month format using the to_char SQL function.</li><li>Then, group by the formatted date and calculate the frequencies using COUNT(*)</li><li>Order final results based on the date.</li></ol><pre>%%read_sql df_news_per_date<br>SELECT <br>    to_char(date,&#39;YYYY-MM&#39;) as date, <br>    COUNT(*) <br>FROM ds_demo.financial_news <br>    WHERE date IS NOT NULL<br>GROUP BY 1<br>ORDER BY 1<br>DESC;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/646/1*EFWAgsXV2QkVd9J4LwT4Wg.png" /></figure><p>Let’s now visualise the aggregated results using <a href="https://plotly.com/">Plotly</a>:</p><pre>px.line(df_news_per_date, <br>        x = &#39;date&#39;, <br>        y = &#39;count&#39;, <br>        title=&#39;Evolution of number of Stock Market News over time&#39;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*HOw2YIx7enKqdeHzhYXkJA.png" /></figure><h4>4. Histogram of Financial News Length</h4><p>Visualise the distribution of stock market news length:</p><pre>%%read_sql df_histogram<br>WITH drb_stats AS (<br>    SELECT min(length(title)) AS min,<br>           max(length(title)) AS max<br>      FROM ds_demo.financial_news<br>),<br>     histogram AS (<br>   SELECT width_bucket(length(title), min, max, 10) AS bucket,<br>          int4range(MIN(length(title)), MAX(length(title)), &#39;[]&#39;) AS range,<br>          COUNT(*) AS freq<br>     FROM ds_demo.financial_news, drb_stats<br>     GROUP BY bucket<br>     ORDER BY bucket<br>)<br><br>SELECT bucket, range, freq,<br>        repeat(&#39;■&#39;,<br>               (   freq::FLOAT<br>                 / MAX(freq) OVER()<br>                 * 30<br>               )::INT<br>        ) AS bar<br>FROM histogram<br>ORDER BY bucket ASC<br>;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/563/1*X8PlTpxqyzot9EviCPi6ZQ.png" /></figure><pre>fig = px.histogram(y = df_histogram.freq, <br>                   x = df_histogram.range.astype(str), <br>                   nbins=10, <br>                   title = &#39;News titles length histogram&#39;)<br>fig.update_layout(yaxis_title=&quot;Frequencies&quot;, xaxis_title = &#39;Bucket (range)&#39;)<br>fig.show()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*YSu2yRRT9BMcTdutSxUa5w.png" /></figure><h4>5. Number of news per stock</h4><p>Use MADlib summary results to visualise the most frequent stocks.</p><pre>%%read_sql df_stock_frequencies<br>SELECT most_frequent_values, mfv_frequencies <br>FROM ds_demo.financial_news_summary <br>  WHERE target_column = &#39;stock&#39;;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/765/1*lxdwmIumlaes_zBTC4T9Kw.png" /></figure><pre>px.bar(y = df_stock_frequencies.most_frequent_values.values[0], <br>       x = df_stock_frequencies.mfv_frequencies.values[0], <br>       color = df_stock_frequencies.most_frequent_values.values[0],<br>       labels={&#39;x&#39;:&#39;News frequency&#39;, &#39;y&#39;: &#39;Stock&#39;},text_auto=&#39;.2s&#39;,<br>       title=&quot;10 Most Frequent Stocks&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*8aJ3YVXyJcDj4WbBlc5xNg.png" /></figure><h4>6. Number of news per publisher (source)</h4><p>Let’s find the most dominant publishers in our dataset:</p><pre>%%read_sql df_publisher_frequencies<br>SELECT most_frequent_values, mfv_frequencies <br>FROM ds_demo.financial_news_summary <br>  WHERE target_column = &#39;publisher&#39;;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/764/1*f_K8Emby6XcoE2uUAipHrw.png" /></figure><pre>px.bar(y = df_publisher_frequencies.most_frequent_values.values[0], <br>       x = df_publisher_frequencies.mfv_frequencies.values[0], <br>       color = df_publisher_frequencies.most_frequent_values.values[0],<br>       labels={&#39;x&#39;:&#39;News frequency&#39;, &#39;y&#39;: &#39;Publisher&#39;},text_auto=&#39;.2s&#39;,<br>       title=&quot;Top 10 - Frequent News sources&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/985/1*4HjPG2RENcDho5GhiJpkJA.png" /></figure><h4>7. Which website is most present in our dataset?</h4><pre>%%read_sql df_url_domain<br>SELECT <br>        split_part(REGEXP_REPLACE(url, &#39;^(https?://)?(www\.)?&#39;, &#39;&#39;), &#39;/&#39;, 1) AS source_url,<br>        count(*) as frequency<br>FROM (SELECT <br>        CASE WHEN url IS NOT NULL THEN url ELSE &#39;Other&#39; END <br>        AS url <br>      FROM ds_demo.financial_news<br>      ) t<br>GROUP BY 1<br>ORDER BY 2 ASC;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/301/1*gB7woDcckoqMsCQU2K37vA.png" /></figure><pre>fig = px.pie(df_url_domain, <br>             names = &#39;source_url&#39;, values = &#39;frequency&#39;,  <br>             width=800, height=600, <br>             title=&#39;Source websites of Stock Market News&#39;)<br><br>fig.update_traces(textposition=&#39;inside&#39;, textinfo=&#39;percent+label&#39;)<br>fig.show()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*Je2JzxeCWj74auETP5gn0Q.png" /></figure><h3>Conclusion</h3><p>To conclude, Data Analysts &amp; Scientists can unleash <strong>Greenplum</strong> performance and massively parallel processing capabilities to process and explore large datasets using built-in analytics functions by combining SQL &amp; Apache MADlib and visualising the results using <strong>Python</strong>.</p><p>In a later blog, we will discover how Greenplum enables <em>Advanced Text Analytics &amp; Text Search</em> by processing mass quantities of textual data using its <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum-Text/index.html"><strong><em>GPText (Greenplum Text)</em></strong></a> solution.</p><blockquote><em>Thanks for reading! Any comments or suggestions are welcome! Check out other Greenplum articles </em><a href="https://medium.com/greenplum-data-clinics"><em>here</em></a><em>.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e034203ecba9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/greenplum-data-clinics/greenplum-for-data-science-blog-series-part-1-big-data-analysis-with-sql-and-python-e034203ecba9">Greenplum for Data Science Blog Series Part 1: Big Data Analysis with SQL and Python</a> was originally published in <a href="https://medium.com/greenplum-data-clinics">Greenplum Data Clinics</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Accelerate Analytics with Greenplum Data-Warehouse & dbt]]></title>
            <link>https://medium.com/greenplum-data-clinics/accelerate-analytics-with-greenplum-data-warehouse-dbt-629da21160ae?source=rss-e06d99af9c2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/629da21160ae</guid>
            <category><![CDATA[greenplum]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[dbt]]></category>
            <category><![CDATA[analytics-engineering]]></category>
            <category><![CDATA[data-warehouse]]></category>
            <dc:creator><![CDATA[Ahmed Rachid Hazourli]]></dc:creator>
            <pubDate>Mon, 06 Mar 2023 22:36:33 GMT</pubDate>
            <atom:updated>2023-03-06T22:36:33.504Z</atom:updated>
            <content:encoded><![CDATA[<h4>A hands-on tutorial to help you build &amp; deploy your first dbt project on the Greenplum data warehouse.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bg6SQxoiIJSzQpP3OBEiuA.png" /></figure><p><strong>dbt</strong> or <strong>data-build-tool</strong> is a transformation tool in the EL<strong>T</strong> pipeline that lets teams transform data, following software engineering best practices. Through native support for connectivity to many data warehouses, dbt runs SQL queries against a database warehouse platform or query engine to materialise data as tables and views.</p><p>It is used to modularise and centralise your data-warehouse analytics code, enabling teams to collaborate on data models, version them, and test and document queries before safely deploying them to production, with monitoring and visibility.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*z8KbjopW7tn65gpc" /></figure><blockquote>In this blog post, we will see how <strong>Greenplum </strong>and <strong>dbt</strong> can operate together to handle reliable and high-performance Big Data workloads and data transformations with simplicity and elasticity thanks to the <strong><em>dbt-greenplum</em></strong> adapter built by the Greenplum community.</blockquote><h3>What is Greenplum Data Warehouse?</h3><p><a href="https://greenplum.org/">Greenplum</a> is an advanced, fully featured, open-source MPP data warehouse based on PostgreSQL. It provides powerful and rapid analytics on petabyte-scale data volumes. Uniquely geared toward big data analytics.</p><p>Greenplum is powered by the world&#39;s most advanced cost-based query optimiser delivering high analytical query performance on large data volumes.</p><p>For more details, take a look at <a href="https://docs.vmware.com/en/VMware-Tanzu-Greenplum/index.html">VMware Greenplum docs</a></p><p><strong>Key Features of Greenplum</strong></p><ol><li>Cloud-agnostic for flexible deployment in the public cloud, private cloud, or on-premise</li><li>Analytics from business intelligence to artificial intelligence</li><li>Handle streaming data and enterprise ETL with ease</li><li>Maximise uptime and protect data integrity</li><li>Industry-leading performance</li><li>Scales to petabytes of data</li><li>Based on open-source projects like PostgreSQL offers an open ecosystem and integration with popular tools.</li><li>Massively parallel, highly concurrent architecture</li><li>Comes with libraries for advanced analytics to process geospatial, text, machine learning, graph, time series, and artificial intelligence</li><li>Parallel, high throughput data access and federated query processing across heterogeneous data sources from object storage like AWS S3, GCS, and Azure Blob Storage to external databases like PostgreSQL, SQL Server, and Oracle</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T7yvRqczjkzcDP9N" /><figcaption>Overview of VMware Greenplum</figcaption></figure><h3><strong>dbt + Greenplum integration:</strong></h3><p>Using Greenplum and dbt together enables organisations to focus on data without worrying about performance tuning, resource allocation, testing, change management, documentation…</p><p>Since Greenplum is a PostgreSQL-based data warehouse, customers can use the <strong><em>dbt-postgres</em></strong> adapter developed and maintained by dbt Labs. Yet, users can now use the <strong><em>dbt-greenplum</em></strong> adapter: <a href="https://docs.getdbt.com/reference/warehouse-setups/greenplum-setup">https://docs.getdbt.com/reference/warehouse-setups/greenplum-setup</a>.</p><p>It unlocks the benefits of a mighty data warehouse. It is easy to set up, connecting to Greenplum has never been simpler, and it provides better defaults.</p><h3>Getting started:</h3><h4><strong><em>Step 1: Setup environment</em></strong></h4><p><strong><em>Installing dbt-greenplum:</em></strong></p><ol><li>First, we must create a new Python environment and then install <strong><em>dbt-greenplum</em></strong> using <em>pip3; it</em> is the easiest way to install the adapter.</li></ol><p>Installing <strong><em>dbt-greenplum</em></strong> will also install <strong><em>dbt-core</em></strong> and any other dependencies.</p><pre>$ python3 -m venv dbt-env<br>$ source dbt-env/bin/activate<br>$ pip install dbt-greenplum</pre><p>2. You can now check if everything works by running the <strong>dbt — version</strong>.</p><pre>$ dbt --version<br>Core:<br>  - installed: 1.2.0<br>  - latest:    1.4.1 - Update available!<br><br>  Your version of dbt-core is out of date!<br>  You can find instructions for upgrading here:<br>  https://docs.getdbt.com/docs/installation<br><br>Plugins:<br>  - postgres:  1.2.0 - Update available!<br>  - greenplum: 1.2.0 - Up to date!<br><br>  At least one plugin is out of date or incompatible with dbt-core.<br>  You can find instructions for upgrading here:<br>  https://docs.getdbt.com/docs/installation</pre><p>3. Initiate the greenplum_demo project using the <em>init</em> command, then move into it:</p><pre>$ dbt init greenplum_demo<br>$ cd greenplum_demo</pre><p>You can now see the dbt&#39;s project structured like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PNNPolKZ7S6DvCW7" /><figcaption>dbt Project Structure</figcaption></figure><p><strong><em>Connect to Greenplum Configuration:</em></strong></p><p>In this step, we configure the connection between dbt and Greenplum using a <a href="https://docs.getdbt.com/docs/get-started/connection-profiles">profile</a> and a YAML file with all the connection details to the Greenplum data warehouse.</p><ol><li>Create a file in the <em>~/.dbt/</em> directory named <em>profiles.yml</em>.</li></ol><pre>$ vi ~/.dbt/profile.yml</pre><p>2. Copy the following and paste it into the new <em>profiles.yml</em> file. Make sure you update the values where noted.</p><pre>greenplum_demo:<br>  target: dev<br>  outputs:<br>    dev:<br>      type: greenplum<br>      host: [hostname]<br>      user: [username]<br>      password: [password]<br>      port: [port]<br>      database: [database name]<br>      schema: [dbt schema]</pre><p>Here&#39;s the profile file used for this blog:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_441iqDtage2bjqK" /><figcaption>profile.yml file</figcaption></figure><p>3. Run the debug command from your project to confirm that you can successfully connect:</p><pre>$ dbt debug</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9yGMOG7AlVXF906G" /></figure><h4>Step 2: Perform your first dbt run<a href="https://docs.getdbt.com/docs/get-started/getting-started-dbt-core#perform-your-first-dbt-run">​</a></h4><p>dbt project has some example models in it. We will check that we can run them to confirm everything is in order.</p><ol><li>Enter the run command to build example models:</li></ol><pre>$ dbt run</pre><p>It would be best if you had an output that looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZLHdqzHrOgecJhaC" /></figure><h4>Step 3: Build your first dbt-greenplum models<a href="https://docs.getdbt.com/docs/get-started/getting-started-dbt-core#build-your-first-models">​</a>:</h4><p>The <strong><em>dbt-greenplum</em> </strong>adapter guides users to an improved experience with less effort to achieve better performance. Users can materialise their tables in the best possible way to optimise their performance by simply choosing the suitable storage model (column or row-oriented, append-optimised tables), distribution, partitioning and data compression strategy.</p><p>It&#39;s now time to build a <strong><em>dbt-greenplum</em></strong> model with advanced configurations!</p><ol><li>Open your project in your favourite code editor and create our first dbt models.</li><li>Create two SQL files, <em>classic_dbt_model.sql</em> and <em>greenplum_dbt_model.sql,</em> in the models&#39; directory to see the benefits of having a <em>dbt-greenplum</em> adapter.</li></ol><p>For this blog, we use Greenplum <em>generate_series</em> and <em>random</em> functions to create a large six months CPU Usage table for 1000 devices with 1-minute intervals, ending now, which generates <strong><em>265 million rows!</em></strong></p><pre>SELECT time, device_id, random()*100 as cpu_usage<br>   FROM generate_series(<br>     now() - INTERVAL &#39;6 months&#39;,<br>      now(),<br>      INTERVAL &#39;1 minute&#39;<br>     ) as time,<br>   generate_series(1,1000) device_id;</pre><ul><li>Create the first file named <em>models/classic_dbt_model.sql</em>, and paste the following:</li></ul><pre>{{ config(materialized=&#39;table&#39;) }}<br><br>with source_data as (<br><br>  SELECT time, device_id, random()*100 as cpu_usage<br>  FROM generate_series(<br>    now() - INTERVAL &#39;6 months&#39;,<br>     now(),<br>     INTERVAL &#39;1 minute&#39;<br>    ) as time,<br>  generate_series(1,1000) device_id<br><br>)<br>select *<br>from source_data</pre><p>This model will create a randomly distributed Greenplum table without advanced or powerful features.</p><ul><li>On the other hand, create the second file named <em>models/greenplum_dbt_model.sql,</em> and paste the following code:</li></ul><pre>{% set fields_string %}<br>    time timestamp NULL,<br>    device_id int null,<br>    cpu_usage double precision<br>{% endset %}<br><br>{% set raw_partition %}<br>   PARTITION BY RANGE (time)<br>   (<br>       START (&#39;2022-06-01&#39;::timestamp) INCLUSIVE<br>       END (&#39;2024-01-01&#39;::timestamp) EXCLUSIVE<br>       EVERY (INTERVAL &#39;1 day&#39;),<br>       DEFAULT PARTITION extra<br>   );<br>{% endset %}<br><br>{{<br>   config(<br>       materialized=&#39;table&#39;,<br>       distributed_by=&#39;device_id&#39;,<br>       appendonly=&#39;true&#39;,<br>       orientation=&#39;column&#39;,<br>       compresstype=&#39;ZLIB&#39;,<br>       compresslevel=3,<br>       fields_string=fields_string,<br>       raw_partition=raw_partition,<br>       default_partition_name=&#39;other_data&#39;<br>   )<br>}}<br><br>with source_data as (<br><br>   SELECT time, device_id, random()*100 as cpu_usage<br>   FROM generate_series(<br>     now() - INTERVAL &#39;6 months&#39;,<br>      now(),<br>      INTERVAL &#39;1 minute&#39;<br>     ) as time,<br>   generate_series(1,1000) device_id<br><br>)<br>select *<br>from source_data</pre><p>This model will create a Greenplum column-oriented, append-optimised table distributed across segments by the device_id column key. It is partitioned on the <em>time</em> column with a daily interval, making it easier to manage and query data. Also, it uses the ZLIB algorithm with a compressed level = 3.</p><p>3. Let&#39;s now run dbt models using:</p><pre>$ dbt run</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7Z1lh36bcy_u8iWj" /></figure><p>4. To see the generated SQL by dbt, which ran on Greenplum, go to <em>/target/run </em>directory:</p><ul><li><strong><em>classic_dbt_model.sql:</em></strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pQ_KHmSa6-N73qEB" /></figure><p>This model created a 265 million rows table randomly distributed with default Greenplum options.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Q8YwBfhRhBQmcbNz" /></figure><ul><li><strong><em>greenplum_dbt_model.sql:</em></strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7rhjBLIHbMkM3BbB" /></figure><p>While for the second table, our data is distributed based on the device_id column. The table is column-oriented, partitioned daily with a ZLIB compression.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UuTmKh2E0Mfb6tGR" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NmE0GqeCagfJ1oaU" /></figure><p>5. When we return to the Greenplum console, we can select from these models:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*s2tJTeeuHrRdeTx-" /></figure><h3><strong>Query Performance &amp; Results Analysis:</strong></h3><p>As you can see, tables in Greenplum have powerful optimisation configurations that should improve query performance. To compare query performance between our newly created dbt tables, we will run analytical queries against these two large tables of 265 million records.</p><ul><li><strong>SELECT MAX(cpu_usage) FROM dbt. ***_dbt_model where time &gt;= ‘2023–01–01’::timestamp:</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9Gyo2FXuJNWnOHnl2g7o2A.png" /></figure><ul><li><strong>SELECT COUNT(*) FROM dbt.****_dbt_model WHERE cpu_usage &gt;= 99 AND (time between ‘2023–02–18’::timestamp and ‘2023–02–20’::timestamp):</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YJXC0tXEnV0iSvEwtnKQOA.png" /></figure><p>As expected, analytical queries are much faster on the <strong><em>greenplum_dbt_model</em></strong> table; our query took only 0.163 seconds to query a 265 million rows table thanks to the advanced Greenplum capabilities from distribution, partitioning and column orientation features, which is ten times faster than the <strong><em>classic_dbt_model </em></strong>table that took more than a second.</p><h3>Conclusion:</h3><p>The winning combination of <strong>Greenplum</strong> and <strong>dbt</strong> dramatically simplifies your overall data architecture by providing a centralised and familiar SQL-based environment for collaborative data transformation.</p><p>Built for performance on top of open source technologies with widespread community support — dbt and Greenplum — ensures ongoing innovation and eliminates the risk of any vendor lock-in.</p><blockquote>Thanks for reading! Any comments or suggestions are welcome! Check out other Greenplum articles <a href="https://medium.com/greenplum-data-clinics">here</a>.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=629da21160ae" width="1" height="1" alt=""><hr><p><a href="https://medium.com/greenplum-data-clinics/accelerate-analytics-with-greenplum-data-warehouse-dbt-629da21160ae">Accelerate Analytics with Greenplum Data-Warehouse &amp; dbt</a> was originally published in <a href="https://medium.com/greenplum-data-clinics">Greenplum Data Clinics</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>