<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ graph database - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ graph database - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 27 Jul 2026 04:21:41 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/graph-database/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Enterprise Knowledge Graphs for Scalable Digital Product Platforms ]]>
                </title>
                <description>
                    <![CDATA[ Enterprises are building more and more digital products that depend on real time intelligence. This means that being able to connect, contextualize, and reason over data has become a core capability.  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-optimize-enterprise-knowledge-graphs-for-scalable-digital-product-platforms/</link>
                <guid isPermaLink="false">6a26427ed198e572e0517866</guid>
                
                    <category>
                        <![CDATA[ data-engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ System Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ knowledge graph ]]>
                    </category>
                
                    <category>
                        <![CDATA[ scalability ]]>
                    </category>
                
                    <category>
                        <![CDATA[ graph database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kamal Kishore ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jun 2026 04:18:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/95434417-9316-481d-b6db-5e9d01f0c971.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Enterprises are building more and more digital products that depend on real time intelligence. This means that being able to connect, contextualize, and reason over data has become a core capability.</p>
<p>Recommendation systems, fraud detection engines, personalization platforms, and enterprise search solutions all rely on integrating data from multiple systems while preserving context and relationships.</p>
<p>Enterprise Knowledge Graphs (EKGs) have emerged as a foundational architecture for addressing this challenge. By modeling enterprise data as entities and relationships, EKGs enable richer semantics, improved data discoverability, and more intelligent downstream decision making.</p>
<p>While the conceptual benefits of knowledge graphs are well understood, scaling them to production grade digital platforms remains complex. Graph systems that perform well at small or medium scale often struggle under high ingestion rates, complex traversal queries, and strict latency requirements.</p>
<p>This article outlines some practical, field tested strategies for optimizing enterprise knowledge graphs for real world scalability. Rather than presenting purely theoretical models, we'll focus on architectural patterns, operational lessons, and performance insights from large scale enterprise deployments.</p>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-why-scalability-becomes-the-core-challenge">Why Scalability Becomes the Core Challenge</a></p>
</li>
<li><p><a href="#heading-moving-beyond-a-single-graph-store-hybrid-architectures">Moving Beyond a Single Graph Store: Hybrid Architectures</a></p>
</li>
<li><p><a href="#heading-partitioning-for-scale-reducing-distributed-traversal-costs">Partitioning for Scale: Reducing Distributed Traversal Costs</a></p>
</li>
<li><p><a href="#heading-managing-semantic-inference-without-sacrificing-performance">Managing Semantic Inference Without Sacrificing Performance</a></p>
</li>
<li><p><a href="#heading-improving-query-performance-with-smarter-planning">Improving Query Performance with Smarter Planning</a></p>
</li>
<li><p><a href="#heading-observability-as-a-first-class-requirement">Observability as a First Class Requirement</a></p>
</li>
<li><p><a href="#heading-impact-on-digital-product-platforms">Impact on Digital Product Platforms</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>This is an architectural guide intended for data engineers, platform architects, and developers managing production-grade graph systems. To get the most out of this article, you should have the following:</p>
<h3 id="heading-conceptual-knowledge"><strong>Conceptual Knowledge</strong></h3>
<ul>
<li><p>A solid understanding of Enterprise Knowledge Graphs (EKGs) and the fundamental differences between RDF triple stores and Labeled Property Graphs (LPGs).</p>
</li>
<li><p>Familiarity with distributed systems concepts, including data partitioning, semantic inference, and event-driven architectures.</p>
</li>
</ul>
<h3 id="heading-technical-background"><strong>Technical Background</strong></h3>
<ul>
<li><p>Experience working with real-time data integration pipelines (such as CDC, Kafka, or Pulsar).</p>
</li>
<li><p>Familiarity with database observability, query execution planning, and general performance optimization techniques at scale.</p>
</li>
</ul>
<h2 id="heading-understanding-the-enterprise-knowledge-graph-ekg">Understanding the Enterprise Knowledge Graph (EKG)</h2>
<p>Before exploring how to scale these systems, it's helpful to understand exactly what a knowledge graph is and how it organizes information.</p>
<p>At its core, a knowledge graph is a data model that represents real-world entities and the complex relationships between them. Unlike traditional relational databases that lock data into rigid, disconnected tables, knowledge graphs store data as a flexible, interconnected network.</p>
<p>A knowledge graph is built on three fundamental components:</p>
<ul>
<li><p><strong>Nodes (Entities):</strong> The distinct objects, concepts, or people in your data ecosystem (for example a Customer, a Product, a Location).</p>
</li>
<li><p><strong>Edges (Relationships):</strong> The lines connecting the nodes that define how they interact (for example "PURCHASED," "LOCATED_IN," "MANUFACTURED_BY").</p>
</li>
</ul>
<p><strong>Properties:</strong> The descriptive metadata attached to nodes or edges (for example, a customer's signup date, or the price of a product).</p>
<h2 id="heading-our-running-example-the-global-electronics-supply-chain-graph">Our Running Example: The Global Electronics Supply Chain Graph</h2>
<p>To ground these concepts, we'll use a unified example throughout this article: an enterprise graph for a global electronics manufacturer managing product data, suppliers, and manufacturing compliance.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6902fd055c9ea201c1fdc217/816a8985-93c2-4e0e-a085-87d3dd4e6fc7.png" alt="816a8985-93c2-4e0e-a085-87d3dd4e6fc7" style="display:block;margin:0 auto" width="1466" height="514" loading="lazy">

<ul>
<li><p>Nodes (Entities): Customer (Alice), Product (NeoPhone 15), Component (MX-200 Chip), Supplier (MaxSemi), and Region (EU).</p>
</li>
<li><p>Edges (Relationships): PURCHASED, PART_OF, SUPPLIES, and LOCATED_IN.</p>
</li>
<li><p>Properties: The NeoPhone 15 node has properties like price: 999 and sku: "NP15-01". The PURCHASED edge has a property of timestamp: 2026-06-03.</p>
</li>
</ul>
<p>Imagine you're building the data foundation for a retail recommendation engine. To build the graph, you move through a few distinct phases:</p>
<ol>
<li><p><strong>Establish ontology:</strong> First, you define the blueprint – the rules dictating what kinds of entities exist and how they are allowed to interact.</p>
</li>
<li><p><strong>Define the nodes:</strong> You integrate data to generate specific entity nodes, such as a Customer node for "Alice," a Product node for "Noise-Canceling Headphones," and a Brand node for "TechAudio."</p>
</li>
<li><p><strong>Map the edges:</strong> You connect these nodes based on user actions and inventory data. Alice VIEWED the Headphones. The Headphones are MANUFACTURED_BY TechAudio.</p>
</li>
</ol>
<p>Why does this matter? Because the data is natively structured as a relationship network, the system can rapidly execute context-rich queries.</p>
<p>If you want to know what else Alice might buy, you don't need to write a heavy, expensive SQL query that joins millions of rows across five different tables. Instead, the graph simply "walks" the pathways you've already built. It traverses from Alice, across the VIEWED edge to the Headphones, across the MANUFACTURED_BY edge to TechAudio, and can instantly return other products connected to that same brand.</p>
<p>By prioritizing the <em>relationships</em> between data points as much as the data points themselves, EKGs provide the contextual intelligence required for modern digital products.</p>
<h2 id="heading-why-scalability-becomes-the-core-challenge"><strong>Why Scalability Becomes the Core Challenge</strong></h2>
<p>Most enterprise knowledge graph initiatives begin with a limited scope, integrating a small number of datasets, enabling semantic search, or improving reporting accuracy. Early-stage deployments often succeed using a single graph database or RDF store.</p>
<p>Scalability challenges emerge when EKGs become production critical infrastructure, particularly when supporting customer facing or latency-sensitive applications. At this stage, multiple pressures converge:</p>
<ol>
<li><p>Rapid data growth as more systems and entities are integrated</p>
</li>
<li><p>Continuous ingestion from streaming pipelines and transactional systems</p>
</li>
<li><p>Increasing query complexity, including multi hop traversals</p>
</li>
<li><p>Strict response time requirements, often under tens of milliseconds</p>
</li>
<li><p>Inference overhead introduced by ontologies and reasoning engines</p>
</li>
</ol>
<p>Simply adding hardware or scaling nodes horizontally rarely resolves these issues. Performance degradation often results from architectural mismatches between graph workloads and system design.</p>
<h2 id="heading-moving-beyond-a-single-graph-store-hybrid-architectures">Moving Beyond a Single Graph Store: Hybrid Architectures</h2>
<h3 id="heading-the-limits-of-monolithic-graph-deployments">The Limits of Monolithic Graph Deployments</h3>
<p>RDF triple stores offer strong semantic expressiveness and standards compliance but may struggle with high volume transactional updates or deep real time traversals. Conversely, labeled property graph (LPG) databases often provide efficient traversal performance but lack native semantic reasoning capabilities.</p>
<p>Attempting to consolidate semantic modeling, inference, operational queries, and analytics into a single system frequently results in trade offs that affect performance, cost, or maintainability.</p>
<h3 id="heading-a-pragmatic-hybrid-model">A Pragmatic Hybrid Model</h3>
<p>A hybrid or polyglot architecture distributes responsibilities across systems optimized for specific workloads:</p>
<ol>
<li><p>Semantic layer (RDF / OWL): Ontology management, schema governance, reasoning workflows.</p>
</li>
<li><p>Operational graph layer (LPG): Real time traversals, recommendation engines, application queries.</p>
</li>
<li><p>Analytical stores: Aggregations, reporting, and historical analysis.</p>
</li>
</ol>
<p>To maintain consistency between the semantic layer (RDF/OWL) and the operational graph layer (LPG), many teams implement synchronization strategies like Change Data Capture (CDC) and event driven pipelines.</p>
<p>In this approach, updates in one layer are captured as events and propagated to the other layer in near real time using streaming platforms such as Kafka or Pulsar. For example, updates in the operational graph can trigger semantic updates, ensuring that ontologies and relationships remain aligned.</p>
<p>Some systems also use dual write patterns or scheduled reconciliation jobs to detect and resolve inconsistencies. In practice, event-driven synchronization combined with periodic validation provides a balance between real time accuracy and system reliability.</p>
<p>This separation isolates performance critical paths while preserving semantic richness where it adds value.</p>
<p>In production environments, hybrid architectures consistently demonstrate improved query latency and operational flexibility compared to monolithic graph deployments, particularly for traversal-heavy workloads. Some teams have also reported latency reductions of 30–60% when separating traversal-heavy workloads into LPG layers, compared to monolithic graph deployments.</p>
<p>This improvement is primarily due to reduced query complexity and optimized storage for specific access patterns.</p>
<h3 id="heading-in-practice-splitting-the-supply-chain-graph">In Practice: Splitting the Supply Chain Graph</h3>
<p>In a production-grade digital platform, a single database engine struggles to handle both semantic governance and high-speed operational queries on this data simultaneously.</p>
<p>Here is how the hybrid model divides the labor:</p>
<ul>
<li><p><strong>The Semantic layer (RDF/OWL):</strong> Manages strict ontological classification and compliance rules. For example, it defines the rule: <em>“If a Component is supplied by an entity in a country under a trade embargo, the final Product inherits a 'High Risk' compliance flag.”</em></p>
</li>
<li><p><strong>The Operational Layer (LPG):</strong> Optimized for fast, multi-hop traversals required by customer-facing apps. When Alice views the NeoPhone 15 on a mobile app, the system queries a Labeled Property Graph (like Neo4j) using a language like Cypher to instantly traverse from the product to its components for a real-time availability check:</p>
</li>
</ul>
<pre><code class="language-plaintext">MATCH (p:Product {id: 'NeoPhone15'})-[:HAS_COMPONENT]-&gt;(c:Component)
RETURN c.name, c.stock_level
</code></pre>
<h2 id="heading-partitioning-for-scale-reducing-distributed-traversal-costs">Partitioning for Scale: Reducing Distributed Traversal Costs</h2>
<p>As enterprise knowledge graphs outgrow single node capacity, distributed execution becomes necessary. Partitioning strategy then becomes a critical performance factor.</p>
<h3 id="heading-why-default-partitioning-often-fails">Why Default Partitioning Often Fails</h3>
<p>Many graph systems use hash-based or random partitioning to distribute data evenly across nodes. While this approach balances storage, it often fragments highly connected subgraphs. Even moderately complex traversals may then require excessive cross-node communication, increasing latency and reducing throughput.</p>
<h3 id="heading-topology-aware-partitioning">Topology-Aware Partitioning</h3>
<p>Topology-aware partitioning colocates frequently connected entities to minimize network hops during traversal. Common approaches include:</p>
<ol>
<li><p>Partitioning by business domain (for example, customers, products, organizations).</p>
</li>
<li><p>Community detection based clustering.</p>
</li>
<li><p>Partitioning informed by observed query patterns.</p>
</li>
</ol>
<p>In practice, teams can achieve topology-aware partitioning by first analyzing query patterns and identifying frequently traversed relationships. Based on this analysis, related entities are co-located within the same partition to minimize cross-partition queries.</p>
<p>Graph processing frameworks and database tools often provide built-in algorithms for community detection, which help group highly connected nodes. Teams can also monitor query performance over time and iteratively refine partitioning strategies to align with evolving workloads.</p>
<p>By combining domain driven design with continuous performance monitoring, teams can incrementally optimize graph layouts without requiring major architectural changes.</p>
<p>In production-inspired environments, topology-aware strategies significantly reduce traversal fan out and improve both median and tail latency under concurrent load.</p>
<p>Though repartitioning introduces operational complexity, the performance gains justify the effort once the knowledge graph becomes central to digital product delivery.</p>
<h3 id="heading-in-practice-partitioning-by-product-domain">In Practice: Partitioning by Product Domain</h3>
<p>Let’s look at what happens when our supply chain graph scales across multiple database nodes.</p>
<p>If we use <strong>Default Hash Partitioning</strong>, the graph is split randomly by node IDs. Alice might end up on Machine 1, the NeoPhone 15 on Machine 2, and the MX-200 Chip on Machine 3. A query tracking whether a component shortage affects Alice's order requires a slow, expensive network hop across three separate physical servers.</p>
<p>Using <strong>Topology-Aware Partitioning</strong>, we can configure the cluster to use the Region or Product_Line as a partitioning key.</p>
<ul>
<li><strong>Partition A (Europe Hub):</strong> Co-locates Region: EU, Product: NeoPhone 15, its internal MX-200 Chip, and local customer orders.</li>
</ul>
<p><strong>Result:</strong> A multi-hop traversal checking component supply chains for European customers happens entirely within local memory on a single machine, reducing query latency.</p>
<h2 id="heading-managing-semantic-inference-without-sacrificing-performance">Managing Semantic Inference Without Sacrificing Performance</h2>
<p>Semantic inference is a defining strength of EKGs but also a frequent source of scalability challenges.</p>
<h3 id="heading-the-inference-cost-problem">The Inference Cost Problem</h3>
<p>Applying full ontology reasoning at query time can dramatically increase computational overhead. In some systems, inference effectively multiplies graph size, increasing memory and CPU consumption. Not all inferred relationships are equally valuable for every workload.</p>
<h3 id="heading-strategies-for-selective-inference-and-materialization">Strategies for Selective Inference and Materialization</h3>
<p>Scalable EKG platforms typically adopt a selective strategy:</p>
<ol>
<li><p>Precompute and materialize frequently accessed inferences</p>
</li>
<li><p>Offload complex reasoning to batch or asynchronous pipelines</p>
</li>
<li><p>Disable low value inference paths in latency-sensitive workloads</p>
</li>
</ol>
<p>Hierarchical classifications and role-based relationships are often materialized ahead of time, while complex rule based reasoning is reserved for offline processing. This approach stabilizes query latency and reduces peak CPU utilization in enterprise deployments.</p>
<h3 id="heading-in-practice-materializing-the-compliance-path">In Practice: Materializing the Compliance Path</h3>
<p>Recall our semantic rule: <em>If a component has a supply risk, the final product inherits that risk.</em></p>
<ul>
<li><p><strong>The Scalability Bottleneck (Query-Time Inference):</strong> Every time an enterprise dashboard loads a product catalog of 10,000 items, the engine must recursively calculate: Product -&gt; Has Component -&gt; Supplied By -&gt; Supplier Country -&gt; Embargo List. Under high concurrent load, this calculation crashes performance.</p>
</li>
<li><p><strong>The Optimization (Materialization):</strong> We run an asynchronous batch job or Kafka consumer that listens for supplier updates. When a supplier's status changes, it computes the inference <em>once</em> and writes a direct property <code>is_high_risk: true</code> directly onto the Product node in the operational LPG.</p>
</li>
</ul>
<p>Now, the customer-facing application reads a simple, static property without running an expensive multi-hop recursive inference query during runtime.</p>
<h2 id="heading-improving-query-performance-with-smarter-planning">Improving Query Performance with Smarter Planning</h2>
<p>As query complexity increases, query planning becomes a decisive performance lever.</p>
<h3 id="heading-limitations-of-static-planning">Limitations of Static Planning</h3>
<p>Traditional graph engines often rely on static heuristics or limited statistics for execution planning. In dynamic enterprise environments where data distributions evolve, these heuristics frequently produce suboptimal execution plans, leading to unpredictable performance.</p>
<h3 id="heading-ml-assisted-query-optimization">ML-Assisted Query Optimization</h3>
<p>Machine learning techniques are increasingly being applied to query optimization, particularly for cardinality estimation. By learning from historical query execution data, ML models can predict plan costs more accurately than rule-based systems.</p>
<p>In controlled experiments and production pilots, ML-assisted planning has demonstrated substantial reductions in execution time for complex traversals, as well as improved consistency in response times.</p>
<p>While implementation requires operational maturity, this represents a promising direction for large scale graph optimization.</p>
<h3 id="heading-in-practice-optimizing-traversal-direction">In Practice: Optimizing Traversal Direction</h3>
<p>Consider this query on our data: <em>"Find all customers who purchased a product containing the MX-200 Chip."</em></p>
<p>There are two ways the graph execution planner can execute this:</p>
<ol>
<li><p><strong>Plan A:</strong> Start at Component: MX-200, find the products it belongs to, and then find the customers who bought those products.</p>
</li>
<li><p><strong>Plan B:</strong> Scan <em>all</em> Customer nodes in the database, look at their purchases, and filter for the ones containing the chip.</p>
</li>
</ol>
<p>If the MX-200 is a rare chip used in only one niche product, <strong>Plan A</strong> is incredibly fast. If it is a generic resistor used in millions of products, <strong>Plan B</strong> or a modified hybrid plan might be more efficient.</p>
<p>An ML-assisted query planner analyzes the real-time cardinality (the actual count) of the PART_OF and PURCHASED relationships in your specific database instance. It prevents the graph engine from choosing a disastrously slow traversal path when data distributions shift unexpectedly.</p>
<h2 id="heading-observability-as-a-first-class-requirement">Observability as a First Class Requirement</h2>
<p>Scalability can't be managed without deep observability.</p>
<h3 id="heading-beyond-infrastructure-metrics">Beyond Infrastructure Metrics</h3>
<p>Monitoring CPU and memory alone provides limited insight into graph-specific performance issues. Effective EKG observability includes:</p>
<ol>
<li><p>Query level latency metrics</p>
</li>
<li><p>Traversal depth and fan-out tracking</p>
</li>
<li><p>Inference cost monitoring</p>
</li>
<li><p>Partition imbalance detection</p>
</li>
</ol>
<h3 id="heading-closing-the-optimization-loop">Closing the Optimization Loop</h3>
<p>By continuously analyzing these signals, teams can iteratively refine partitioning strategies, caching policies, and materialization decisions. This feedback loop improves predictability and reduces production incidents.</p>
<p>In practice, strong observability often distinguishes proactive optimization from reactive firefighting.</p>
<h2 id="heading-impact-on-digital-product-platforms">Impact on Digital Product Platforms</h2>
<p>When applied collectively, these optimization strategies materially enhance scalability and reliability. Across enterprise deployments, teams commonly observe:</p>
<ol>
<li><p>Reduced latency in real time workloads</p>
</li>
<li><p>Improved ingestion throughput under sustained load</p>
</li>
<li><p>Linear or near linear scaling as datasets grow</p>
</li>
<li><p>Greater stability during traffic spikes</p>
</li>
</ol>
<p>These technical improvements translate directly into business outcomes: faster recommendations, more relevant search results, and increased confidence in deploying EKGs as mission critical infrastructure.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Enterprise knowledge graphs are no longer experimental. They're becoming the backbone of intelligent, data driven systems. As teams move toward AI-powered decision making, the role of knowledge graphs is expanding beyond storage into enabling context-aware reasoning and automation.</p>
<p>An optimized EKG isn't just a database – it acts as the connective tissue between data, models, and real world applications. It provides the structured context that modern AI systems, including agentic workflows and autonomous decision engines, rely on to operate effectively.</p>
<p>By adopting hybrid architectures, topology-aware partitioning, and intelligent query strategies, teams can build scalable and resilient graph systems that support both operational and analytical workloads.</p>
<p>Ultimately, organizations that invest in well-designed knowledge graph infrastructure will be better positioned to power the next generation of AI systems where retrieval, reasoning, and action are seamlessly integrated.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Graph Databases VS Relational Databases – Learn How a Graph Database Works ]]>
                </title>
                <description>
                    <![CDATA[ By Ljubica Lazarevic If you're curious about graph databases and how they compare with relational database management systems, then this beginner-friendly guide is for you.  In this article, you'll discover of the power of graphs by working with a sm... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/graph-database-vs-relational-database/</link>
                <guid isPermaLink="false">66d46012d14641365a05090f</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ graph database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 09 Sep 2021 17:16:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/f2fb45ed-48ce-4469-927f-d295b82d9f98.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ljubica Lazarevic</p>
<p>If you're curious about graph databases and how they compare with relational database management systems, then this beginner-friendly guide is for you. </p>
<p>In this article, you'll discover of the power of graphs by working with a small movie data set. It is based on the <a target="_blank" href="https://neo4j.com/developer/example-data/">built in dataset and guide</a> available on the <a target="_blank" href="https://dev.neo4j.com/try">Neo4j Sandbox</a>.</p>
<p>Want to drive right in and have a go yourself? Please do! You’ll find instructions on how to <a target="_blank" href="https://lju.medium.com/getting-started-with-play-movies-251228c12f2c">get up and running here</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/movie-image.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-well-cover-in-this-article">What We'll Cover in This Article</h2>
<p>Graph databases are growing in popularity and adoption. With ever-larger amounts of data from many different sources, it's critical to be able to understand the data and see how it's all connected. </p>
<p>If you want to find out more about the kinds of problems graph databases help solve, and how you might spot a good application for one, here's an <a target="_blank" href="https://medium.com/geekculture/spotting-a-graph-shaped-problem-b1f126bf8c03">introductory blog post</a>. </p>
<p>Some of you reading on may have heard of graph databases (GDB), some you perhaps haven’t. In this article we’re going to cover exactly what they are, and how they compare to the more traditional, Relational Database Management Systems (RDBMS) which have been the stalwart software application of the past 40+ years. </p>
<p>Inspired by a small movie data set used by Neo4j as a guided introduction to graph querying, we are going to look at side-by-side examples and equivalents of what a data model or query would look like in both a graph database, and a relational database.</p>
<p>In this article, we will:</p>
<ul>
<li>Introduce graph databases, briefly covering the two models that exist</li>
<li>Take a conceptual look at the differences between relational and graph paradigms</li>
<li>Look at the movie data set, and compare and contrast data models from a GDB and a RDBMS perspective</li>
<li>Compare and contrast some queries, based on either Cypher (for GDB) or SQL</li>
<li>Talk through the more interesting queries that appear in the movie example, and break out exactly what is happening</li>
</ul>
<p>If you’d like to have a play with the example walkthrough movie data set before reading the article (or during!), you are more than welcome to do so. You can find out more <a target="_blank" href="https://medium.com/neo4j/getting-started-with-play-movies-251228c12f2c">here</a>.</p>
<h2 id="heading-what-is-a-graph-database">What is a Graph Database?</h2>
<p>First of all, before we dive into what a graph database is, let’s define the term. Graph databases are a type of “Not only SQL” (NoSQL) data store. They are designed to store and retrieve data in a graph structure. </p>
<p>The storage mechanism used can vary from database to database. Some GDBs may use more traditional database constructs, such as table-based, and then have a graph API layer on top. </p>
<p>Others will be ‘native’ GDBs – where the whole construct of the database from storage, management and query maintains the graph structure of the data. Many of the graph databases currently available do this by treating relationships between entities as first class citizens.</p>
<h3 id="heading-different-types-of-graph-databases">Different Types of Graph Databases</h3>
<p>There are broadly two types of GDB, Resource Descriptive Framework (RDF)/triple stores/semantic graph databases, and property graph databases. </p>
<p>An RDF GDB uses the concept of a triple, which is a statement composed of three elements: subject-predicate-object. </p>
<p>Subject will be a resource or nodes in the graph, object will be another node or literal value, and predicate represents the relationship between subject and object. There are no internal structures on the nodes or relationships, and everything is identified by a unique identifier, in the form of a URI. </p>
<p>The motivation behind this structure is exchanging and publishing data. To find out more about this structure, I would refer you to <a target="_blank" href="https://jbarrasa.com/2016/11/17/neo4j-is-your-rdf-store-part-1/">Jesus Barrasa’s</a> work in this space. </p>
<p>A Property GDB is focussed on the concept of storing data that is close to the logical model. This in turn will be based on the questions sought of the data itself, and focuses on making that representation as efficient as possible for storage and querying. </p>
<p>Unlike an RDF-based graph, there are internal structures on the nodes and relationships, lending to a rich representation of data as well as associated metadata. </p>
<p>The following two diagrams provide a side by side comparison of sample data represented in a Property Graph Database, and as an RDF graph – both of which representing the person Tom Hanks, acting the role Jim Lovell, in the movie Apollo 13.</p>
<p><img src="https://lh3.googleusercontent.com/v4SPvkCESPh7JmNx1ibALZTHEb0ILjPjN2xR7Y_62TTaHkM8lMuErmqzRMcdAUIkL3nz1lqYlrlQl24J_B_-Oa9K-dk7yy1GsRRXPpW5tVCMzcQ6tgMwf0sgE-XGbCfnf8Wlaqs0=s0" alt="Image" width="600" height="400" loading="lazy">
<em>RDF example of Tom Hanks in Apollo 13</em></p>
<p><img src="https://lh5.googleusercontent.com/EW8G0eS4Luh9jykxFBvFA3CvFr9ivvbUDaspOwSL7gxuGx-N-eswCoZJjJiAdgo1x2k0eYTa55YeOaFXbfSYKywPW4mI_Di_NB-nTOwnHztaYVBBPVaecrG83es3DlT_PLskbf1b=s0" alt="Image" width="600" height="400" loading="lazy">
<em>Property Graph example of Tom Hanks in Apollo 13</em></p>
<h2 id="heading-ia"> </h2>
<p>Anatomy of a Property Graph Database</p>
<p>For the rest of this article, we will be focussing on native property graph databases, specifically Neo4j. Let's check out the main components. </p>
<p>The main components of a property graph database are as follows:</p>
<ul>
<li>Node: also known as a vertex in graph theory – the main data element from which graphs are constructed</li>
<li>Relationship: also known as an edge in graph theory – a link between two nodes. It will have <strong>direction</strong> and a <strong>type</strong>. A node without relationships is permitted, a relationship without two nodes is not permitted</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-40.png" alt="Image" width="600" height="400" loading="lazy">
<em>Node and Relationship</em></p>
<ul>
<li>Label: Defines a node category, a node can have more than one</li>
<li>Property: Enriches a node or relationship, no need for nulls!</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-39.png" alt="Image" width="600" height="400" loading="lazy">
<em>Label, Type, and Property</em></p>
<h2 id="heading-graph-databases-vs-relational-databases">Graph Databases vs Relational Databases</h2>
<h3 id="heading-relational-databases-recap">Relational Databases Recap</h3>
<p>A lot of developers are familiar with the traditional relational database, where data is stored in tables within a well-defined schema. </p>
<p>Each row in the table is a discrete entity of data. One of these elements in the row is typically used to define its uniqueness: the primary key. It could be a unique ID or maybe something like a social security number for a person.</p>
<p>We then go through a process called normalization to reduce data repetition. In normalization, we’re moving references, something like an address for a person, into another table. So we get a reference from the row representing the entity to the row representing the address for that person.</p>
<p>If, for example, somebody changes their address, you wouldn’t want multiple versions of that person’s addresses everywhere and have to try and remember all the different instances of where that person’s addresses exist. Normalization makes sure you have one version of the data, so you can make the updates in one place.</p>
<p>Then when we query, we want to reconstitute this normalized data. We do what’s called a JOIN operation. </p>
<p>In our main entity row, we have the primary key that identifies the ID for the entity, let’s say the person. We also have what’s called a foreign key that represents a row in our address table. We join the two tables through their primary and foreign keys, and use that to look up the address in the address table. This is called a JOIN and these JOINs are done at query time and at read time.</p>
<p>When we’re doing a JOIN in a relational database, it’s a set comparison operation where we’re looking to see where our two sets of data overlap (in this case, the sets are the person table and the address table). At a high level, that’s how traditional relational databases work.</p>
<p><img src="https://lh5.googleusercontent.com/VTc6WHaERtCGkdAxZOgAuN74-isXFuHQjAQL7cxXFZCntCHD3q86FBCkuUCOoRhfq_wwxRR4yd0y2XYrM3dG7CPyG0s7HukFfme1k-gU2il3HiQVlkTz9w3hzYJZhaD9Lzeow3M4=s0" alt="Image" width="600" height="400" loading="lazy">
<em>An example of the tables found and how they map to each other in a relational database for an insurance database</em></p>
<p><img src="https://lh4.googleusercontent.com/fRaKUVtGKp9TABKWcNfyy1CkZohxeC-5mf5FxbHF00xxh-_SsRdDqyVJ31ViXib8WdVvtWS7W2sZi4XS3SzcavlFvTW3-c8SEovdSWP3s4n6--pCRJ-w6FoQ53lgxAT455HWY29R=s0" alt="Image" width="600" height="400" loading="lazy">
<em>The equivalent example of the insurance database in a property graph database</em></p>
<h3 id="heading-how-native-graph-databases-work-connections-and-index-free-adjacency">How Native Graph Databases Work: Connections and Index-Free Adjacency</h3>
<p>Let’s have a quick peek at a native graph database and how it works. </p>
<p>We spoke about the discrete entity in a relational database being a row within a table. In a native graph database, that row would be the equivalent of a node. It’s still a discrete entity, so we still have this element of normalization.</p>
<p>A node would be an entity. If we were having person nodes, we would have one node for one person. And we would have some degree of uniqueness in it, let’s say the social security number. </p>
<p>The key difference, however, is when we are connecting this person node to another discrete entity – for example, an address – we create a physical connection (aka relationship) between those two points.</p>
<p>The address would have a pointer that says, what is the outbound part of the relationship that connects to the node? We then have another pointer for the inbound part of the relationship pointing to the other node. </p>
<p>So, effectively, we’re collecting a set of pointers, and this is a manifestation of the physical connection between those two entities. That is the big difference.</p>
<p>In a relational database, you would reconstitute the data with joins on read, which means at query time, it would go off to try and figure out how things map together.</p>
<p>In a graph database, since we already know these two elements are connected, we don’t need to look up the mapping at query time. All we’re doing is following the stored relationships to the other nodes. </p>
<p>This is something we call index-free adjacency. This concept of index-free adjacency is key to understanding the performance optimizations of a native graph database compared to other database systems.</p>
<p>Index-free adjacency means that during a local graph traversal, following these pointers (relationships) that connect the nodes in my graph, the performance of the operation is not dependent on the overall size of the graph. It depends on the number of relationships connected to the nodes that you’re traversing.</p>
<p>When we talk of a JOIN being a set operation (intersection), we’re using an index in a relational database to see where those two sets overlap. This means that the performance of the JOIN operation starts to slow down as the tables get bigger. </p>
<p>In big O notation terms, this is something like logarithmic growth using an index — something like O(log n) and also grows exponentially with the number of JOINs in your query.</p>
<p>On the other hand, traversing relationships in the graph is more of linear growth based on the number of relationships in the nodes that we’re actually traversing, not the overall size of the graph.</p>
<p>This is the fundamental query time optimization that graph databases make that give us index-free adjacency. From a performance perspective, that is really the most important thing to think about when we think of a native graph database.</p>
<h2 id="heading-a-brief-introduction-to-the-movie-graph">A Brief Introduction to the Movie Graph</h2>
<p>We've spoken a fair bit about the theoretical differences between a graph and relational database. Now let's start to look at some side-by-side comparisons.</p>
<p>The movie graph consists of a data set consisting of actors, directors, producers, writers, reviewers and movies, along with information on how they all connect to each other.  </p>
<p>This data set is available within Neo4j Browser, and can be easily triggered by using the <code>:PLAY movies</code> command. As a reminder, here's a blog to show you <a target="_blank" href="https://medium.com/neo4j/getting-started-with-play-movies-251228c12f2c">how to get started</a>. </p>
<p>The Movies data set consists of:</p>
<ul>
<li>133 Person nodes/entities</li>
<li>38 Movie nodes/entities</li>
<li>253 relationships/connections between the above entities, describing connections such as:</li>
<li>Person(s) who directed a Movie</li>
<li>Person(s) who acted in a Movie and role(s) played</li>
<li>Person(s) who wrote a Movie</li>
<li>Person(s) who produced a Movie</li>
<li>Person(s) who have reviewed a Movie and score and summary given</li>
<li>Person(s) who follow another Person</li>
</ul>
<p>While it is a relatively small data set, it comprehensively describes the power of graphs.</p>
<h3 id="heading-comparing-data-models">Comparing data models</h3>
<p>First of all, let's take a look at the data models of our respective databases. As with all data models, what they look like will ultimately depend on the types of questions you are asking. So let's assume we're going to ask the following types of questions:</p>
<ul>
<li>What movies did a person act in?</li>
<li>What movies does a person have a connection with?</li>
<li>Who are all the co-actors a person has ever worked with?</li>
</ul>
<p>Based on these, here are the associated potential data models:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-37.png" alt="Image" width="600" height="400" loading="lazy">
<em>Entity Relationship data model for movie graph</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-41.png" alt="Image" width="600" height="400" loading="lazy">
<em>Property Graph data model for movie graph</em></p>
<p>Immediately you will spot something – those IDs have gone! As we are connecting data together as soon as we know there's a connection there, we no longer need them, or those mapping tables to let us know how different rows of data connect together.</p>
<h3 id="heading-comparing-queries">Comparing queries</h3>
<p>Let's now move on to comparing some queries. Taking a few of the first queries from the <code>:PLAY movies</code> example, let's look at some side-by-side comparisons of the Cypher query, and what would the equivalent SQL query look like.</p>
<p>What is Cypher, I hear you ask? <a target="_blank" href="https://neo4j.com/developer/cypher/">Cypher is a graph query language</a> which is used to query the Neo4j graph database. There is an <a target="_blank" href="https://opencypher.org/">OpenCypher</a> version too, which is used by a number of other vendors.</p>
<p>As we move through the queries, it should start to become clearer how a graph database, accompanied with a query language to help explore relationships really starts to come into its own. Let's start looking for Tom Hanks!</p>
<h4 id="heading-how-to-find-tom-hanks">How to find Tom Hanks</h4>
<pre><code class="lang-cypher">MATCH (p:Person {name: "Tom Hanks"})
RETURN p
</code></pre>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> person 
<span class="hljs-keyword">WHERE</span> person.name = <span class="hljs-string">"Tom Hanks"</span>
</code></pre>
<h4 id="heading-how-to-find-tom-hanks-movies">How to find Tom Hanks movies</h4>
<pre><code class="lang-cypher">MATCH (:Person {name: “Tom Hanks”})--&gt;(m:Movie)
RETURN m.title
</code></pre>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> movie.title <span class="hljs-keyword">FROM</span> movie
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> movie_person <span class="hljs-keyword">ON</span> movie.movie_id = person_movie.movie_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person <span class="hljs-keyword">ON</span> person_movie.person_id = person.person_id
<span class="hljs-keyword">WHERE</span> person.name = <span class="hljs-string">"Tom Hanks"</span>
</code></pre>
<h4 id="heading-how-to-find-movies-tom-hanks-has-directed">How to find movies Tom Hanks has directed</h4>
<pre><code class="lang-cypher">MATCH (:Person {name: "Tom Hanks"})-[:DIRECTED]-&gt;(m:Movie)
RETURN m.title
</code></pre>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> movie.title <span class="hljs-keyword">FROM</span> movie
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person_movie <span class="hljs-keyword">ON</span> movie.movie_id = person_movie.movie_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person <span class="hljs-keyword">ON</span> person_movie.person_id = person.person_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> involvement <span class="hljs-keyword">ON</span> person_movie.involve_id = involvement.involve_id
<span class="hljs-keyword">WHERE</span> person.name = <span class="hljs-string">"Tom Hanks"</span> <span class="hljs-keyword">AND</span> involvement.title = <span class="hljs-string">"Director"</span>
</code></pre>
<h4 id="heading-how-to-find-co-actors-of-tom-hanks">How to find co-actors of Tom Hanks</h4>
<pre><code class="lang-cypher">MATCH (:Person {name: "Tom Hanks"})--&gt;(:Movie)&lt;-[:ACTED_IN]-(coActor:Person)
RETURN coActor.name
</code></pre>
<pre><code class="lang-sql"><span class="hljs-keyword">WITH</span> tom_movies <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span> movie.movie_id <span class="hljs-keyword">FROM</span> movie
    <span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person_movie <span class="hljs-keyword">ON</span> movie.movie_id = person_movie.movie_id
    <span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person <span class="hljs-keyword">ON</span> person_movie.person_id = person.person_id
    <span class="hljs-keyword">WHERE</span> person.name = <span class="hljs-string">"Tom Hanks"</span>)
<span class="hljs-keyword">SELECT</span> person.name <span class="hljs-keyword">FROM</span> person
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person_movie <span class="hljs-keyword">ON</span> tom_movies = person_movie.movie_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> person <span class="hljs-keyword">ON</span> person_movie.person_id = person.person_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> involvement <span class="hljs-keyword">ON</span> person_movie.involve_id = involvement.involve_id
<span class="hljs-keyword">WHERE</span> involvement.title = <span class="hljs-string">"Actor"</span>
</code></pre>
<h2 id="heading-more-queries-with-cypher">More Queries with Cypher</h2>
<p>Hopefully you’ll get the idea of the differences between Cypher and SQL queries. Perhaps you’re excited to learn more about them too! We’ll have some references further on in the blog post. </p>
<p>For now, let’s have a look at some of the other Cypher queries you can find in the <code>:PLAY movies</code> graph example, and explain what’s going on.</p>
<p>No movie graph would be complete without the quintessential <a target="_blank" href="https://en.wikipedia.org/wiki/Six_Degrees_of_Kevin_Bacon">Bacon number question</a>, and our movie graph is no different! </p>
<p>Up until now, the examples we have looked at have always traversed one relationship each time. We can easily take advantage of those ‘joins on write’ to traverse many relationships to answer interesting questions. </p>
<p>So, back to the Kevin Bacon number. The following query will start at the Kevin Bacon person node, and then go up to 4 hops out from that start point, to bring back all connected movies and people.</p>
<pre><code class="lang-cypher">MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)
RETURN DISTINCT hollywood
</code></pre>
<p>We can do this by using the syntax of <code>*1..4</code> in the relationship part of the query pattern:</p>
<ul>
<li><code>*</code> indicates everything</li>
<li><code>1..4</code> indicates the range - 1 says from 1 hop away, 4 says up to 4 hops away</li>
</ul>
<p>Another graphy thing we could do on this movie data set is the shortest path between two nodes. </p>
<p>In this example, let’s find out the <a target="_blank" href="https://neo4j.com/docs/cypher-manual/4.3/clauses/match/#query-shortest-path">shortest path</a> between Kevin Bacon and Meg Ryan. You will spot we’re using the <code>*</code> syntax again for the relationship pattern – indicating everything. </p>
<p>What may be new to you is the <code>p=</code>. You’ve seen how we use references for nodes (e.g. <code>bacon</code> or <code>meg</code> in our current query), and we can do the same for relationships. </p>
<p>We can also have references for the whole path (that is, all the nodes and relationships involved). The syntax we use for that is <code>refName =</code>, which in this example is <code>p=</code>. </p>
<p>We also use the Cypher function <code>shortestPath()</code> – this is a simple shortest path function that will return the first shortest path between two specified nodes. Be aware there may be another, equally short path, but this simple function will just bring back the first one encountered. </p>
<p>For those of you interested in other path-related functions, check out the ones available in APOC and GDS. </p>
<pre><code>MATCH p=shortestPath(
(bacon:Person {<span class="hljs-attr">name</span>:<span class="hljs-string">"Kevin Bacon"</span>})-[*]-(meg:Person {<span class="hljs-attr">name</span>:<span class="hljs-string">"Meg Ryan"</span>}))
RETURN p
</code></pre><p>A word of warning to you all: you may see that <code>[*]</code> and be tempted to run your graph without the constraint of the <code>shortestPath()</code> function or the <code>1..4</code> range. But this may well result in something unexpected. </p>
<p>In our example with Kevin Bacon and Meg Ryan, even though there are only 253 relationships in this very small data set, all of the possible combinations of paths between nodes and relationships could easily run into millions of different paths between Bacon and Ryan. </p>
<p>When using <code>*</code> in your relationships as part of a query, use with extreme caution! This problem does not come up with shortest path because as a potential path that is longer than the currently identified shortest one is encountered, it is immediately dropped. </p>
<h3 id="heading-a-simple-recommendations-query">A simple recommendations query</h3>
<p>Here are two queries that really show the power of graph databases and we can easily use the connections in our data to make some recommendations.</p>
<p>In our first query we’re looking for new co-actors for Tom Hanks to work with who he’s not already worked with. The query does this by:</p>
<ul>
<li>Firstly, finding all of the co-actors he has already worked with</li>
<li>Then, finding all of the co-actors' co-actors (referred to as co-co-actors)</li>
<li>Next, we want to exclude those co-co-actors who have already worked with Tom, as well as making sure the co-co-actor isn’t Tom himself</li>
<li>Finally, we return the suggested co-co-actors names, and we’re going to order them but the number of co-actors that have worked with them – the more co-actors that have worked with that co-co-actor, the better the recommendation.</li>
</ul>
<pre><code class="lang-cypher">MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]-&gt;(m)&lt;-[:ACTED_IN]-(coActors),
(coActors)-[:ACTED_IN]-&gt;(m2)&lt;-[:ACTED_IN]-(cocoActors)
WHERE NOT (tom)-[:ACTED_IN]-&gt;()&lt;-[:ACTED_IN]-(cocoActors) 
    AND tom &lt;&gt; cocoActors
RETURN cocoActors.name AS Recommended, count(*) AS Strength 
    ORDER BY Strength DESC
</code></pre>
<p>Excellent, so we’ve found some potential co-co-actors. In this next query, we want to suggest Tom Cruise as a potential new co-actor for Tom Hanks to work with. But, who’s going to introduce these Toms to each other? Back to the movie graph we go.</p>
<p>In this query, we:</p>
<ul>
<li>Find the co-actors of Tom Hanks, and then find which out of those co-actors have also acted with Tom Cruise</li>
<li>Then we’ll return the co-actor and the movies they were in with both Tom Hanks and Tom Cruise</li>
</ul>
<pre><code class="lang-cypher">MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]-&gt;(m)&lt;-[:ACTED_IN]-(coActors),
(coActors)-[:ACTED_IN]-&gt;(m2)&lt;-[:ACTED_IN]-(cruise:Person {name:"Tom Cruise"})
RETURN tom, m, coActors, m2, cruise
</code></pre>
<h2 id="heading-last-words">Last Words</h2>
<p>We've come to the end of our walk through of the movies database example. Hopefully those of you with a relational database background have a better idea of the similarities and differences between relational and graph databases, as well as a taste of the Cypher query language.</p>
<p>If you're keen to learn more about modeling and querying Neo4j, do check out the free <a target="_blank" href="https://dev.neo4j.com/learn">Graph Academy</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Have you had “The Talk” with your chatbot about graph data structures? ]]>
                </title>
                <description>
                    <![CDATA[ By Mark Watson A coming-of-age story for your database model _Image credit: [Charlotte Parent](http://www.charlotteparent.com/CLT/Health-Development/More-Than-the-Birds-and-the-Bees-Teaching-Your-Child-About-Healthy-Sexuality/" rel="noopener" target... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/have-you-had-the-talk-with-your-chatbot-about-graph-data-structures-3aaf5c3ae52c/</link>
                <guid isPermaLink="false">66c34c2ea1d481faeda49b6f</guid>
                
                    <category>
                        <![CDATA[ #chatbots ]]>
                    </category>
                
                    <category>
                        <![CDATA[ graph database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ IBM Watson ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Recommendation System ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 19 Feb 2017 00:28:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*AeUDHuLM_pyfNZ3ZP5znyQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mark Watson</p>
<h4 id="heading-a-coming-of-age-story-for-your-database-model">A coming-of-age story for your database model</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*AeUDHuLM_pyfNZ3ZP5znyQ.png" alt="Image" width="800" height="533" loading="lazy">
_Image credit: [Charlotte Parent](http://www.charlotteparent.com/CLT/Health-Development/More-Than-the-Birds-and-the-Bees-Teaching-Your-Child-About-Healthy-Sexuality/" rel="noopener" target="<em>blank" title=")</em></p>
<p>Graph databases are a great way to store conversational data. A simple <a target="_blank" href="https://hackernoon.com/chatbot-architecture-496f5bf820ed#320b">dialog</a> <a target="_blank" href="https://en.wikipedia.org/wiki/Dialog_tree">tree</a> can add depth to character interactions in a video game. A <a target="_blank" href="https://gigaom.com/2013/05/15/how-google-is-setting-the-new-search-standard-with-voice-and-knowledge-graph/">knowledge</a> <a target="_blank" href="http://www.aclweb.org/anthology/N15-1086">graph</a> can extract more meaning from dialog to better understand how user intent relates to an application’s data.</p>
<p>In this article, I’ll show you a basic graph model for capturing chatbot interactions and how to persist them using the <a target="_blank" href="https://tinkerpop.apache.org/">Apache TinkerPop</a> framework. I’ll also show you some <a target="_blank" href="http://tinkerpop.apache.org/gremlin.html">Gremlin</a> queries for adding a recommendation feature to the chatbot. The source code and setup instructions for my example “Recipe Bot” are <a target="_blank" href="https://github.com/ibm-cds-labs/watson-recipe-bot-nodejs-graph">on GitHub</a>.</p>
<h3 id="heading-review-recipe-bot">Review: Recipe Bot</h3>
<p>The Recipe Bot is a <a target="_blank" href="https://api.slack.com/bot-users">Slack Bot User</a> that lets people request recipes based on specified ingredients or cuisines. Previously I showed you how to add support for users to request their favorite recipes, like so:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*SjILWmRnPN3sSdr133pHRg.png" alt="Image" width="540" height="274" loading="lazy"></p>
<p>The graph version of the bot has all of the same features I discussed in my <a target="_blank" href="https://medium.com/ibm-watson-data-lab/persisting-data-for-a-smarter-chatbot-be599480f7b2#.jvmry69xz">previous article on persisting metadata with JSON</a>, but with the graph version you’ll be adding recommendations.</p>
<h3 id="heading-how-it-works-with-tinkerpop">How it works with TinkerPop</h3>
<p>Here is an architecture diagram of how the bot works:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*uGXlWtFX65TWPtvpKUkWGg.png" alt="Image" width="800" height="333" loading="lazy">
_My Recipe Bot. Hey! The diagram is actually an [undirected graph](https://en.wikipedia.org/wiki/Graph_theory" rel="noopener" target="<em>blank" title="). Who knew?</em></p>
<p>You’ll see that I’m using the Watson Conversation service. Watson Conversation lets me describe the flow of the conversation through the use of dialogs, and it helps me extract information and user intent from chat messages. You can code your own dialog tree and perform your own message parsing, or you can use tools like Watson Conversation or Botkit to help. Here is how the dialog tree for the Recipe Bot is modeled:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*qaJL5vQGKkhUCShVpiusGg.png" alt="Image" width="800" height="466" loading="lazy">
<em>The Watson Conversation UI. Graphs are everywhere.</em></p>
<p>You can follow a conversation through the dialog tree similar to how you can follow vertices and edges in a graph (after all, <a target="_blank" href="https://en.wikipedia.org/wiki/Tree_(graph_theory)">trees are graphs</a> too):</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*fzxYyM3iP9Qc08yu4spt_g.png" alt="Image" width="362" height="200" loading="lazy">
<em>It’s not much of a tree, but I’m keeping it simple, y’all.</em></p>
<p>In the simplified graph above, the Recipe Bot cares only about the progression between the major entities of the bot:</p>
<ol>
<li>People</li>
<li>Ingredients</li>
<li>Cuisines</li>
<li>Recipes</li>
</ol>
<h3 id="heading-data-model-amp-access-pattern">Data model &amp; access pattern</h3>
<p>As the conversation progresses, you store the following vertices and edges using the TinkerPop API:</p>
<ol>
<li><strong>Person vertex:</strong> For each person that interacts with the bot, store that person as a vertex in the graph.</li>
</ol>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"person"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"vertex"</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"name"</span>: <span class="hljs-string">"U2JBLUPL2"</span>  }}
</code></pre><p><strong>2. Ingredient or cuisine vertex:</strong> When a person requests a specific ingredient or cuisine, you store that ingredient or cuisine — along with the list of recipes retrieved from <a target="_blank" href="https://spoonacular.com/food-api">Spoonacular</a> — as a vertex.</p>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"cuisine"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"vertex"</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"name"</span>: <span class="hljs-string">"chinese"</span>,    <span class="hljs-string">"detail"</span>: <span class="hljs-string">"[{\"id\": 573147, \"title\": \"Kale Fried Rice\"..."</span>  }}
</code></pre><p><strong>3. Selects edge, person → (ingredient | cuisine):</strong> You create an edge, labelled <code>"selects"</code>, between the person and the ingredient or cuisine (that is, “person selects cuisine”). In addition, store a <code>"count"</code> property on the edge and increment its value each time the user requests the same ingredient or cuisine.</p>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"selects"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"edge"</span>,  <span class="hljs-string">"inV"</span>: <span class="hljs-number">4152</span>,  <span class="hljs-string">"outV"</span>: <span class="hljs-number">4224</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"count"</span>: <span class="hljs-number">3</span>  }}
</code></pre><ol start="4">
<li><strong>Recipe vertex:</strong> When a user requests a recipe, store the recipe as a vertex.</li>
</ol>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"recipe"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"vertex"</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"name"</span>: <span class="hljs-string">"573147"</span>,    <span class="hljs-string">"detail"</span>: <span class="hljs-string">"Ok, it takes *45* minutes to make...*"</span>,    <span class="hljs-string">"title"</span>: <span class="hljs-string">"Kale Fried Rice"</span>  }}
</code></pre><ol start="5">
<li><strong>Selects edge, (ingredient | cuisine) → recipe:</strong> You create another <code>"selects"</code> edge between the ingredient or cuisine and the recipe (that is, “cuisine selects recipe”). In addition, store a <code>"count"</code> property on the edge and increment it each time the ingredient or cuisine selects the same recipe.</li>
</ol>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"selects"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"edge"</span>,  <span class="hljs-string">"inV"</span>: <span class="hljs-number">4320</span>,  <span class="hljs-string">"outV"</span>: <span class="hljs-number">4152</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"count"</span>: <span class="hljs-number">22</span>  }}
</code></pre><p><strong>6. Selects edge, person → recipe:</strong> You create yet another <code>"selects"</code> edge directly between the person and the recipe (that is, “person selects recipe”). Store a <code>"count"</code> property on the edge and increment it each time a person requests the same recipe.</p>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"selects"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"edge"</span>,  <span class="hljs-string">"inV"</span>: <span class="hljs-number">4320</span>,  <span class="hljs-string">"outV"</span>: <span class="hljs-number">4224</span>,  <span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"count"</span>: <span class="hljs-number">4</span>  }}
</code></pre><p><strong>7. Has edge, recipe → (ingredient | cuisine):</strong> Finally, create an edge, labelled <code>"has"</code>, between the recipe and the ingredient or cuisine (that is, “recipe has cuisine”). This relationship allows you to find all the ingredients and cuisines that a recipe uses. There is no count field on this edge.</p>
<pre><code>{  <span class="hljs-string">"label"</span>: <span class="hljs-string">"has"</span>,  <span class="hljs-string">"type"</span>: <span class="hljs-string">"edge"</span>,  <span class="hljs-string">"inV"</span>: <span class="hljs-number">4152</span>,  <span class="hljs-string">"outV"</span>: <span class="hljs-number">4320</span>}
</code></pre><p>The graph for a single user looks something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*h6fvJxvuKB_6EVn-w1itTg.png" alt="Image" width="623" height="585" loading="lazy">
<em>This graph has it going on. It’s a [(weakly) connected graph](https://en.wikipedia.org/wiki/Connectivity</em>%28graph_theory%29#Definitions_of_components.2C_cuts_and_connectivity" rel="noopener" target="<em>blank" title="). There are all kinds of graphs.</em></p>
<p>So far, by using a graph database, you get the following benefits:</p>
<ol>
<li>Reduce third-party API calls by caching entities.</li>
<li>Provide a more personal experience for users by harnessing metadata on their interactions.</li>
</ol>
<p>A “more personal experience” for Recipe Bot means allowing users to request their favorite recipes. To find a user’s favorite recipes, you use the Gremlin <a target="_blank" href="http://tinkerpop.apache.org/docs/current/reference/#traversal">graph traversal</a> language. The following Gremlin query will give you a user’s top-five favorite recipes, sorted by count:</p>
<h3 id="heading-adding-recommendations">Adding recommendations</h3>
<p>Since you track every user interaction with the bot as a graph, you can find popular ingredients, cuisines, or recipes requested by all users. You can use Gremlin to find popular recipes based on an ingredient or cuisine. Here’s how it works:</p>
<p>Let’s say, a user is looking for recipes that use onions:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*Yf49Io2lbpZeHrsvfyMxLA.png" alt="Image" width="800" height="374" loading="lazy"></p>
<p>You can find popular recipes that use onions by issuing the following query. (I’ll unpack it further below—don’t worry!):</p>
<p>This query says, “Give me anyone, excluding the calling user, who has requested recipes more than once that have onions.” It breaks down like so:</p>
<ol>
<li>Start with <code>"onions"</code>:</li>
</ol>
<pre><code>g.V().hasLabel(<span class="hljs-string">"ingredient"</span>).has(<span class="hljs-string">"name"</span>,<span class="hljs-string">"onions"</span>)
</code></pre><ol start="2">
<li>Get the recipes that have <code>"onions"</code>. This API call uses the <code>"has"</code> edge coming from the recipe vertex into the ingredient vertex. Using <code>.in()</code> skips the edge and only returns the recipe vertex. (You don’t need any properties from the edge object, so there’s no reason to return it here.)</li>
</ol>
<pre><code>.in(<span class="hljs-string">"has"</span>)
</code></pre><ol start="3">
<li>Get the users that have requested these recipes more than once. This call uses the <code>"selects"</code> edge coming from the person to the recipe:</li>
</ol>
<pre><code>.inE().has(<span class="hljs-string">"count"</span>,gt(<span class="hljs-number">1</span>)).order().by(<span class="hljs-string">"count"</span>, decr)
</code></pre><ol start="4">
<li>Get the users, excluding the current user:</li>
</ol>
<pre><code>.outV().hasLabel(<span class="hljs-string">"person"</span>).has(<span class="hljs-string">"name"</span>,neq(<span class="hljs-string">"CURRENT_USER"</span>))
</code></pre><ol start="5">
<li>Get the full path:</li>
</ol>
<pre><code>.path()
</code></pre><p>This call returns an array of matching paths that looks like this:</p>
<blockquote>
<p>ingredient ← recipe ← edge ← person</p>
</blockquote>
<p>You can access these recommended recipes at index 1.</p>
<p>When you return this recipe list to the user, the app puts the recommended recipes at the top and highlights the number of users who have previously used which recipe:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*HS0ft98ZPG4AezihLIHnFA.png" alt="Image" width="800" height="218" loading="lazy"></p>
<h3 id="heading-whats-next">What’s Next?</h3>
<p>Try a deployment for yourself. The <a target="_blank" href="https://github.com/ibm-cds-labs/watson-recipe-bot-nodejs-graph#watson-recipe-bot--ibm-graph">project’s README</a> has step-by-step instructions for completing your first deployment on IBM Bluemix. There’s also a <a target="_blank" href="https://github.com/ibm-cds-labs/watson-recipe-bot-java-graph">Java port</a> of the example app.</p>
<p>If you’re already using a dialog tree in your applications and want to use a graph database to persist metadata on interactions, I hope the source code in the repo above gives you some ideas on delivering more personalized experiences to your users.</p>
<p>And if you’ve enjoyed this article, please hit the ol’ ♥ so other Medium users might find it and dig it too. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
