<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Memgraph</title>
    <description>The latest articles on DEV Community by Memgraph (@memgraph).</description>
    <link>https://dev.to/memgraph</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4973%2F37388b33-7d30-458b-a939-9a6e26f8f21b.gif</url>
      <title>DEV Community: Memgraph</title>
      <link>https://dev.to/memgraph</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/memgraph"/>
    <language>en</language>
    <item>
      <title>MCP for Agents: The Security Gap Most Teams Miss</title>
      <dc:creator>Sabika Tasneem</dc:creator>
      <pubDate>Mon, 16 Feb 2026 12:31:41 +0000</pubDate>
      <link>https://dev.to/memgraph/mcp-for-agents-the-security-gap-most-teams-miss-3bnl</link>
      <guid>https://dev.to/memgraph/mcp-for-agents-the-security-gap-most-teams-miss-3bnl</guid>
      <description>&lt;p&gt;MCP is exciting because it turns an LLM into something that can execute actions through tool calls. One protocol, many tools. Your agent can pull data, update tickets, call APIs, and trigger workflows. That is exactly why teams are rushing to ship MCP based agents.&lt;/p&gt;

&lt;p&gt;That speed comes with a tradeoff. Once an LLM can touch live systems, mistakes stop being “bad answers” and start becoming real actions. The point of this post is not to criticize MCP. It is to help you ship agents that stay useful without unintentionally expanding your blast radius.&lt;/p&gt;

&lt;p&gt;Let’s dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP Gives You (And What it Does Not)
&lt;/h2&gt;

&lt;p&gt;MCP standardizes how tools and context are exposed to a model, which is great for developer velocity. What it does not do is decide what is safe or appropriate in your environment. You still own boundaries and behavior.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/nmAVOTVi7yE"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;In production, the gaps show up fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tool should be used for this request&lt;/li&gt;
&lt;li&gt;What data is allowed for this user or team&lt;/li&gt;
&lt;li&gt;Which actions should be blocked or require approval&lt;/li&gt;
&lt;li&gt;How you can audit tool use after something goes wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want the spec level overview, start with &lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;Anthropic’s MCP introduction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Agents with MCP: 3 Problems You Will Hit First
&lt;/h2&gt;

&lt;p&gt;The first failure is rarely a headline breach. It usually looks like a normal product bug, except now the bug can trigger emails, update records, or touch production data. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Agent Does the “Helpful” Thing You Did Not Ask For&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A user asks, “Can you check which customers are impacted?” The agent decides that notifying customers is helpful and drafts a mass email. Nothing was hacked. The model was just optimizing for task completion, and you gave it a tool that made the wrong idea easy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Demo Tool Becomes a Production Hazard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most teams start with a broad tool set because it makes the demo work. Later, the agent gets a slightly different question and reaches for the most powerful tool available. If that tool can write, delete, or trigger workflows, you now have an outsized failure scope. That is the blast radius.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Agent Guesses and Guesses Wrong&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your agent can query a database, it will try. If it does not have the right context about what is allowed and what the data means, it will guess. Sometimes the guess is harmless. Sometimes it pulls data it should not have pulled, or it produces results that look right but are based on the wrong assumptions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Prompt Rules Are Not Enforcement
&lt;/h2&gt;

&lt;p&gt;The common response is to add more instructions: “Read-only,” “confirm before sending,” “never delete.” Those rules help, but they do not enforce anything.&lt;/p&gt;

&lt;p&gt;There is a simple reason. Prompts influence the model’s behavior. They do not change the system’s capabilities. If a write tool is exposed, the model can still call it, even if you told it not to. If a broad SQL tool is exposed, the model can still retrieve more data than you intended, even if you asked it to be careful.&lt;/p&gt;

&lt;p&gt;This is why prompt-only safety tends to decay over time. As you add tools, edge cases, and new workflows, the instruction layer becomes a long list of exceptions. The agent still has the same tool surface, but now it is operating under a growing set of text rules that are easy to miss, conflict, or misapply.&lt;/p&gt;

&lt;p&gt;The fix is capability control. Reduce what the agent can do, scope what it can see, and require explicit approvals for actions that have a real blast radius.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Practical Fix: Shrink the Tool Surface at Runtime
&lt;/h2&gt;

&lt;p&gt;Do not rely on the model to always choose correctly. Make wrong choices harder. The simplest way to do that is to reduce what the agent can do by default, then expand capabilities only when you have a clear reason.&lt;/p&gt;

&lt;p&gt;Start with these guardrails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expose fewer tools by default&lt;/li&gt;
&lt;li&gt;Only expose tools that match the current task&lt;/li&gt;
&lt;li&gt;Separate read tools from write tools&lt;/li&gt;
&lt;li&gt;Require approvals for irreversible actions&lt;/li&gt;
&lt;li&gt;Log tool calls so you can trace what happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is least-privilege design applied to agent tool access, enforced at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where GraphRAG Fits in an MCP Tooling Stack
&lt;/h2&gt;

&lt;p&gt;Most RAG stacks start with vectors. Vectors are great at finding semantically similar text, but they are not built to represent relationships like who owns which data, which rule is current, or which tool is allowed for this workflow.&lt;/p&gt;

&lt;p&gt;Graphs are good at that because they model relationships directly. When you add a graph-based context layer, you can give the model a smaller, cleaner slice of context tied to the user and the task.&lt;/p&gt;

&lt;p&gt;For example, you can make use of &lt;a href="https://memgraph.com/docs/database-management/authentication-and-authorization/role-based-access-control#label-based-access-control" rel="noopener noreferrer"&gt;label-based access controls&lt;/a&gt; that determine which node labels and relationship edge types a given user or workflow can touch. That reduces overload and lowers the chance your agent reaches for the wrong tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Checklist You Can Actually Use
&lt;/h2&gt;

&lt;p&gt;If you are shipping MCP-powered agents, do not treat guardrails as a final polish step. Treat them as part of the build. The fastest way to end up in trouble is to bolt safety on after you have already exposed a wide tool surface to an LLM.&lt;/p&gt;

&lt;p&gt;Start with a simple baseline and improve it as you learn. The point is not to predict every edge case up front. The point is to make tool behavior observable, reversible where possible, and scoped to what the agent should be doing right now.&lt;/p&gt;

&lt;p&gt;If you are shipping MCP-powered agents, start here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List your tools and label them read or write&lt;/li&gt;
&lt;li&gt;Turn off anything irreversible by default&lt;/li&gt;
&lt;li&gt;Add a human approval step for high impact actions&lt;/li&gt;
&lt;li&gt;Keep tool descriptions short and specific&lt;/li&gt;
&lt;li&gt;Log every tool call with who requested it and what tool ran&lt;/li&gt;
&lt;li&gt;Review misfires weekly and treat them as product bugs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This checklist is not about paranoia. It is about making MCP workflows predictable enough to ship. If your plan is “we will fix it in the prompt,” you are in for some trouble.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Memgraph adds to an MCP agent stack
&lt;/h2&gt;

&lt;p&gt;At some point in production, most enterprise teams realize they need a real context layer. Memgraph is an in-memory graph database used as a real-time context engine, which makes it a good fit when your agent needs fast traversal, connected context, and governance that changes as your systems change.&lt;/p&gt;

&lt;p&gt;In practice, you can use Memgraph to store and query the relationships your agent depends on, then apply GraphRAG patterns to retrieve a connected context slice instead of stuffing everything into a prompt.&lt;/p&gt;

&lt;p&gt;This is also where Memgraph’s &lt;strong&gt;&lt;a href="https://www.crowdcast.io/c/meet-atomic-graphrag-a-single-unified-execution-layer" rel="noopener noreferrer"&gt;Atomic GraphRAG&lt;/a&gt;&lt;/strong&gt; comes in. Instead of stitching together multiple retrieval steps in your application code, Atomic GraphRAG aims to generate context in a single query so it is simpler, faster, and easier to review and tweak. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv528cggc13phtxnqq4qm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv528cggc13phtxnqq4qm.png" alt="memgraph-atomic-graphrag-single-query-execution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For you, that means fewer moving parts, clearer failure modes, and a smaller surface area for accidental tool misuse.&lt;/p&gt;

&lt;p&gt;If you are exploring MCP specifically, Memgraph provides an &lt;a href="https://memgraph.com/blog/pushing-mcp-forward" rel="noopener noreferrer"&gt;MCP Server&lt;/a&gt; to expose graph context to agents, and an &lt;a href="https://modelcontextprotocol.io/clients#:~:text=and%20Agent%20API-,Memgraph%20Lab,-%23" rel="noopener noreferrer"&gt;MCP Client&lt;/a&gt; inside &lt;a href="https://memgraph.com/lab" rel="noopener noreferrer"&gt;Memgraph Lab&lt;/a&gt; to compose workflows across MCP servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;MCP is a doorway to useful agents. It also makes mistakes expensive. If you want to ship responsibly, focus on runtime guardrails: shrink the tool surface, keep context clean, and log everything.&lt;/p&gt;

&lt;p&gt;If you want to explore a graph-based context layer for MCP, &lt;a href="https://memgraph.com/blog/mcp-client-memgraph-lab-interoperability" rel="noopener noreferrer"&gt;start here&lt;/a&gt;. And remember, tool access is part of your attack surface, so review it alongside your production code.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>agents</category>
      <category>graphrag</category>
      <category>accesscontrols</category>
    </item>
    <item>
      <title>Innovation Graph Analytics Powered by Embeddings and LLM’s</title>
      <dc:creator>André Vermeij</dc:creator>
      <pubDate>Wed, 27 Nov 2024 10:52:44 +0000</pubDate>
      <link>https://dev.to/memgraph/innovation-graph-analytics-powered-by-embeddings-and-llms-4hb9</link>
      <guid>https://dev.to/memgraph/innovation-graph-analytics-powered-by-embeddings-and-llms-4hb9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Guest Author:&lt;/strong&gt; &lt;a href="https://dev.to/andrevermeij"&gt;André Vermeij&lt;/a&gt;, Founder of Kenedict Innovation Analytics &amp;amp; Developer of Kenelyze&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro &amp;amp; Recap: Innovation Graphs
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://dev.to/memgraph/innovation-as-a-graph-improved-insight-into-technology-clusters-collaboration-and-knowledge-networks-1746"&gt;first post in our series&lt;/a&gt; on &lt;strong&gt;Innovation Graphs&lt;/strong&gt; introduced the usage of graphs in the analysis of innovation and its output, such as patents, scientific publications and research grants. &lt;/p&gt;

&lt;p&gt;Innovation graphs focus on mapping the connections between technologies, organisations and people and can provide new insights into the actual underpinnings of innovative activity within topics or organisations of interest. They can be constructed based on all kinds of metadata and often focus on visually mapping three complementary perspectives: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Graphs of documents to gain deeper insight into technology/topic clusters.&lt;/li&gt;
&lt;li&gt;Graphs of organisations and institutions to focus on sector-wide collaboration patterns.&lt;/li&gt;
&lt;li&gt;Graphs of people/experts to get a better understanding of team-level collaboration and key players in a field of expertise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this second post on Innovation Graphs, we’ll focus on the creation and LLM-powered analysis of the first type of graph mentioned above—graphs detailing clusters of technologies and topics within a specific sector of interest. Specifically, we’ll dive into how we can use text embeddings to construct document similarity graphs, and how we can automatically analyse the content and label the graph’s clusters using locally running Large Language Models. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa90h0xixzkux147sza9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa90h0xixzkux147sza9r.png" alt="How to use text embeddings to construct document similarity graphs" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Text Embeddings &amp;amp; Graph Creation
&lt;/h1&gt;

&lt;p&gt;Mapping clusters of technology and the connections between them is a key part of most innovation analytics projects. A common way to create the related document similarity graphs is to collect the unstructured text related to documents in a dataset (for example, abstracts for scientific publications or summaries of R&amp;amp;D project reports), convert the text into vectors/embeddings, and then calculate pairwise similarities to get similarity scores for each pair of documents to construct the final graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Classical Way: TF-IDF
&lt;/h2&gt;

&lt;p&gt;Converting unstructured text into ready-to-analyse vectors can be done in various ways. A classical way to approach this is to use a variant of Term Frequency-Inverse Document Frequency (&lt;a href="https://en.wikipedia.org/wiki/Tf%E2%80%93idf" rel="noopener noreferrer"&gt;TF-IDF&lt;/a&gt;). Here, all unstructured text is initially pre-processed using common techniques in Natural Language Processing (tokenization, lemmatization, stop-word removal, etc.), after which each token in a document is assigned a TF-IDF score. This score is based on how often the token appears in the document itself (TF) and on the inverse of how often it appears across all documents in the dataset (IDF). For each document, a vector with a length equalling the total number of unique tokens across all documents is then created, holding the TF-IDF scores for all tokens in the document and zeroes for any tokens that do not occur in the document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcajie7ezbmsnmy6c33iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcajie7ezbmsnmy6c33iu.png" alt="Simplified version of TF-IDF vector construction" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although this is a pretty intuitive way of converting text into vectors, it comes with several challenges. The main drawback is that semantic similarity is mostly overlooked in this approach, since the scores are simply based on term counts within and across documents. Also, the vectors resulting from TF-IDF are generally very sparse and can easily consist of thousands of elements per vector, depending on the size of the overall text corpus.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Modern Way: Embedding Models
&lt;/h2&gt;

&lt;p&gt;The rise of Large Language Models and Generative Artificial Intelligence has also resulted in the availability of a wide variety of embedding models and APIs to convert unstructured text into fixed-length vectors. For example, &lt;a href="https://docs.nomic.ai/reference/api/embed-text-v-1-embedding-text-post" rel="noopener noreferrer"&gt;Nomic&lt;/a&gt;, &lt;a href="https://www.mixedbread.ai/docs/embeddings/overview" rel="noopener noreferrer"&gt;Mixedbread&lt;/a&gt;, &lt;a href="https://jina.ai/embeddings/" rel="noopener noreferrer"&gt;Jina&lt;/a&gt;, and &lt;a href="https://platform.openai.com/docs/guides/embeddings" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; all offer APIs to get embeddings based on input of unstructured text of your choice. Some key use cases for these embedding models are query and document embedding for Retrieval Augmented Generation, but they also serve as an excellent basis for the large-scale embedding of datasets to create document similarity graphs.&lt;/p&gt;

&lt;p&gt;The main benefits of these embedding models are that they also consider semantic similarity between concepts and are usually of a fixed, dense size (often 768 or 1024 elements, often called dimensionality). A challenge is that users need to carefully pick the parameters when using these models since these can significantly impact the overall outcome when converting the vectors into document similarity graphs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graph Creation Based on Embeddings
&lt;/h2&gt;

&lt;p&gt;We can construct a document similarity graph based on all pairwise similarities between the document vectors as soon as embeddings are generated for all documents in our dataset. The nodes in the graph are simply the original documents from our dataset, with weighted links drawn between nodes when they have a certain degree of similarity. A commonly used similarity metric is &lt;a href="https://en.wikipedia.org/wiki/Cosine_similarity" rel="noopener noreferrer"&gt;cosine similarity&lt;/a&gt;, with scores ranging from 0 to 1, where 1 denotes identical texts/vectors. Links between nodes can be determined by setting a threshold similarity value.&lt;/p&gt;

&lt;p&gt;The exact value used here can have a significant impact on the readability of the graph: setting the threshold too low will often lead to a hairball/spaghetti bowl visualization (too many links between nodes), while setting it too high will show many disparate clusters with no connections between them. When constructing a graph, it is therefore important to give this some thought and also relate it to the actual size of the text fragments you are dealing with – shorter strings (titles) usually go well with higher threshold values, while longer strings (abstracts, summaries) usually combine well with lower threshold values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Detection for Technology Cluster Identification
&lt;/h2&gt;

&lt;p&gt;As soon as the nodes and links in the graph have been constructed based on the embedding similarities and the threshold set, we can start analysing the graph of documents to uncover clusters of related content. In practice, this is a very important step to make the graph more readable and understandable.In innovation analytics, gaining insight into which technology clusters are present in a dataset and how they connect and evolve is often key to a project’s success.&lt;/p&gt;

&lt;p&gt;An excellent way to uncover these clusters is by using the Leiden community detection algorithm, now &lt;a href="https://memgraph.com/docs/advanced-algorithms/available-algorithms/leiden_community_detection" rel="noopener noreferrer"&gt;available in Memgraph&lt;/a&gt;. Based on the structure of the graph, this algorithm detects densely connected subsets of nodes and iteratively assigns them to the same communities. In the end, when colouring nodes based on the communities they are assigned, we have an excellent basis to start labelling and annotating the graph to make sense of its contents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdcxvzo5elrc7wk82pib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdcxvzo5elrc7wk82pib.png" alt="Uncoloured graph vs the same graph coloured based on communities" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  LLM-Powered Innovation Cluster Labelling
&lt;/h1&gt;

&lt;p&gt;In the analysis of technology and topic graphs, providing clear labelling and annotation of the resulting graph visualizations is key to gaining insights by stakeholders in an innovation analytics project. Annotated visuals are often used to provide initial high-level overviews of a graph’s contents in presentations, and often serve as a basis for further deep dives into specific clusters of interest.&lt;/p&gt;

&lt;p&gt;A classical approach to initial cluster labelling is to treat each cluster's contents as a separate corpus of documents and then run a version of TF-IDF to extract the top-5 highest-scoring tokens or phrases for each cluster. The resulting labels often provide a decent first indication of a cluster’s contents, but they do require subsequent manual analysis and improvement to improve their readability.&lt;/p&gt;

&lt;p&gt;An exciting alternative way to label clusters is to use a Large Language Model to summarize cluster contents. In our case, we utilize locally running models such as &lt;a href="https://www.llama.com/llama3_1/" rel="noopener noreferrer"&gt;Llama 3.1&lt;/a&gt; in &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; or &lt;a href="https://lmstudio.ai/" rel="noopener noreferrer"&gt;LM Studio&lt;/a&gt; based on the following high-level process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcj93k8phc0x10lf1ht87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcj93k8phc0x10lf1ht87.png" alt="Alternative way to label clusters is to use a Large Language Model to summarize cluster contents" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For each detected community, we first gather relevant unstructured text from the attributes of the nodes in the cluster. In most cases, we have found that sending over collections of document titles per cluster works very well for cluster labelling. This collection of texts is then added to a prompt that specifies exactly how the LLM should respond in its summarization: based on the texts provided, return a short summary/label consisting of a maximum of 5 words with an indication of the high-level topic. Many LLM’s are prone to adding a lot of introductory (“Absolutely! Here is a summary of…”) and concluding text to answers, so the prompt also specifies that it should never do this and purely focus on returning the labels.&lt;/p&gt;

&lt;p&gt;As soon as the LLM finishes providing the labels for all communities, we replace the nodes’ initial community attribute with the newly created label. Of course, these labels do require manual checks to see whether they make sense and sometimes require slight adjustments because they are too high-level. The quality of the labels is also dependent on the LLM itself: we’ve found that larger models such as Llama3.1 (8B parameters) generally provide better labels than smaller models such as Llama 3.2 (3B parameters).&lt;/p&gt;

&lt;h1&gt;
  
  
  Cluster Summarization Using LLM’s
&lt;/h1&gt;

&lt;p&gt;Another valuable way to use LLM’s in document similarity graph analysis is to further enhance users’ understanding of clusters by providing point-and-click larger summaries of what the documents in a cluster are about. The approach here is similar to the LLM-based labelling described above, with the prompt sent to the model focusing on providing an overall summary consisting of 3 to 5 phrases instead.&lt;/p&gt;

&lt;p&gt;Practically speaking, users of a graph visualization select nodes of their interest using a free-form selection tool and point out which unstructured text attribute should be used for the analysis, after which the LLM returns a summary based on the collection of texts sent to it. The summary is then printed in a window right on top of the visual, as in the example below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewarnjbuago4z34okjob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewarnjbuago4z34okjob.png" alt="AI Sumary of Node label" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Up Next: Step-By-Step Real-Life Examples and Visuals
&lt;/h1&gt;

&lt;p&gt;This post provided an overview of how text embeddings can be used to construct document similarity graphs for innovation analysis, and how Large Language Models can aid in the labeling and summarization of the resulting graphs. Our next post in this series will show examples of this in practice using &lt;a href="https://www.kenelyze.com/" rel="noopener noreferrer"&gt;Kenelyze&lt;/a&gt;, based on a real-life dataset of the innovation output of a major high-tech company. It will also discuss the importance of local LLM’s when working with sensitive data, and highlight some technical considerations when picking and configuring a local LLM.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>technologyclusters</category>
      <category>innovationnetworkanalysis</category>
      <category>graphdatabase</category>
    </item>
    <item>
      <title>Innovation as a Graph: Improved Insight into Technology Clusters, Collaboration and Knowledge Networks</title>
      <dc:creator>André Vermeij</dc:creator>
      <pubDate>Wed, 18 Sep 2024 12:42:47 +0000</pubDate>
      <link>https://dev.to/memgraph/innovation-as-a-graph-improved-insight-into-technology-clusters-collaboration-and-knowledge-networks-1746</link>
      <guid>https://dev.to/memgraph/innovation-as-a-graph-improved-insight-into-technology-clusters-collaboration-and-knowledge-networks-1746</guid>
      <description>&lt;p&gt;&lt;strong&gt;Guest Author:&lt;/strong&gt; André Vermeij, Founder of &lt;a href="https://www.kenedict.com" rel="noopener noreferrer"&gt;Kenedict Innovation Analytics&lt;/a&gt; &amp;amp; Developer of &lt;a href="https://www.kenelyze.com" rel="noopener noreferrer"&gt;Kenelyze&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Organisations focused on innovation come in many forms, including corporations with large Research &amp;amp; Development (R&amp;amp;D) departments, universities, research institutions active in advancing science, and startups working on the potentially next big thing. Innovation-related data has become increasingly important for each of these organisations to inform decision-making and stay ahead of market developments. For example, an R&amp;amp;D-intensive corporation could use data to benchmark its own technology portfolio with its direct competitors, while a startup might be analysing data to assess previous activity and potential market entry in a sector of interest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional Innovation Analysis
&lt;/h2&gt;

&lt;p&gt;The traditional way to look at innovation-related data is to report on output within a topic or organisation of interest based on counts and sums of variables of interest. When analysing its competition, a business may for example gather information on a competitor’s recent output and report on the number of documents in each technology domain, produce a list of the companies the competitor has worked with, or generate an overview of the most active inventors or researchers in a field of interest. Although all these analyses can be valuable in their own right, they’re missing out on a key aspect of an innovation ecosystem: the connections between technologies, organisations, and people.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Graph of Innovation
&lt;/h2&gt;

&lt;p&gt;Viewing innovation and its output as a graph of interconnected data points allows us to get a much deeper understanding of the technology and knowledge structures in a context of interest. Using the metadata in a wide array of innovation-related data sources, which will be discussed more in the following  section, it is possible to create graphs of connected documents, organisations and people and gain new insights into the actual underpinnings of innovative activity.&lt;/p&gt;

&lt;p&gt;For example, innovation graphs allow us to answer questions, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which clusters of activity can we distinguish within a topic or organisation of interest, and how has this evolved?&lt;/li&gt;
&lt;li&gt;What do the organisational collaboration networks in an area of interest look like, and who are the key players in network connectivity?&lt;/li&gt;
&lt;li&gt;How are teams of individual experts in a specific field composed, and who are the leading experts in a given topic?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open Data Sources for Innovation Analytics
&lt;/h2&gt;

&lt;p&gt;Until just a few years ago, quality innovation data was quite hard to come by without a subscription to an expensive database hosting patent information or scientific publications. Luckily, in recent years, there has been a move towards more openly available data, which can serve as an excellent basis for setting up a wide variety of innovation graphs.&lt;/p&gt;

&lt;p&gt;Here’s a quick overview of common data sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patents:&lt;/strong&gt; organisations apply for patents to protect their inventions against commercialisation by third parties. Patent applications and grants are published online by national patent offices around the world, with databases gathering data from all jurisdictions and providing a wide array of metadata. A great open data source is the European Patent Office's &lt;a href="https://www.epo.org/en/searching-for-patents/data/web-services/ops" rel="noopener noreferrer"&gt;Open Patent Services&lt;/a&gt; (OPS) API, or the EPO's search platform &lt;a href="https://worldwide.espacenet.com/" rel="noopener noreferrer"&gt;Espacenet&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scientific publications:&lt;/strong&gt; journal publications, conference proceedings, book chapters and various other types of scientific output are gathered in databases which bring together output from many sources. Paid databases such as Scopus are still used often by large organisations – great open alternatives include &lt;a href="https://openalex.org/" rel="noopener noreferrer"&gt;OpenAlex&lt;/a&gt; and &lt;a href="https://www.semanticscholar.org/" rel="noopener noreferrer"&gt;Semantic Scholar&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subsidies &amp;amp; funding programmes:&lt;/strong&gt; governmental subsidies to stimulate innovation and R&amp;amp;D in specific areas are often structured in openly available data sources. A good example is the European Union’s &lt;a href="https://data.europa.eu/data/datasets/cordis-eu-research-projects-under-horizon-europe-2021-2027?locale=en" rel="noopener noreferrer"&gt;CORDIS data&lt;/a&gt; for the Horizon Europe programme. Many national enterprise agencies also publish their granted subsidies and projects online.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal data:&lt;/strong&gt; the above data sources are often augmented with internal, unpublished data (e.g., internal project reports, unfiled patent applications, scientific output in the review stage) to get a view on very recent activity within an organisation. This is especially valuable when creating knowledge graphs within organisations or  carrying out an innovation portfolio analysis for a specific client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a typical Innovation Analytics project, combining data from multiple of the above data sources is often key to gaining the best insights. For example, organisations applying for patents often also have scientific output related to the same theme and may also apply for governmental funding. To get a picture of innovative activity that is as complete as possible, it is therefore important to look at activity from multiple data sources and graph perspectives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphs of Documents: Insight into Technology and Knowledge Clusters
&lt;/h2&gt;

&lt;p&gt;The analysis and visualisation of innovation graphs often starts with looking at the relationships between documents based on a shared characteristic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtvqe8014t8q1bsy0qbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtvqe8014t8q1bsy0qbl.png" alt="Graphs of Documents: Text Similarity" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on the goals of the analysis, there are various ways to link documents together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Text similarity:&lt;/strong&gt; unstructured text data in the form of document titles, abstracts and summaries can be used to connect documents when there is a high similarity between their contents. This relies on vectorisation of the text of interest and subsequent calculation of pairwise cosine similarities, where a link is then drawn between documents based on a minimum similarity score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge flows / shared authors:&lt;/strong&gt; another way to generate clusters of connected documents is to link them when the same people have worked on them. The authorship data on documents can be used to accomplish this. The key assumption here is that documents are part of the same “knowledge cluster” when persons with specific expertise have (co-) written them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Citations:&lt;/strong&gt; numerous citations to other documents can be found in both scientific publications and patent applications. We can use these citations to create various types of graphs:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared references:&lt;/strong&gt; connect documents when they cite the same sources, often with a minimum number of shared citations set as the weight for the links. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared citing documents:&lt;/strong&gt; connect documents when they have been cited by the same other documents, again often with a minimum weight set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct citations:&lt;/strong&gt; creation of citation graphs where links are drawn between documents when they cite each other.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Technology classifications:&lt;/strong&gt; patent documents are categorised using classification codes designating the technology areas which they fall into. These can be used to connect documents when they share one or multiple codes, essentially creating clusters of documents based on technological overlap.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The following graph is an example of a text similarity approach, where scientific publications in the area of autonomous vehicles are connected when they share significant textual content. Colors depict clusters of activity based on the outcomes of a community detection algorithm, and nodes are sized based on the number of times they were cited by other papers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sfmbvz220qcnd4hgd5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sfmbvz220qcnd4hgd5i.png" alt="A graph showing scientific publications on autonomous vehicles, where node size reflects citation count, edges show text similarity, and colors represent clusters from a community detection algorithm." width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: Graph of scientific publications linked based on text similarity approach&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphs of Organisations: Insight into Collaboration Ecosystems
&lt;/h2&gt;

&lt;p&gt;Another graph perspective, which is very common in innovation analysis, focuses on mapping the connections between organisations (businesses, universities, research institutions, public bodies, hospitals, etc.). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6940g5nx6nvjqimyuwvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6940g5nx6nvjqimyuwvq.png" alt="Graphs of Organisations: Mapping the connections between organisations" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many of the data sources above hold extensive metadata on the organisations responsible for the documents—scientific authors are affiliated with their employers, patents are applied for by the parties seeking protection of their invention and governmental subsidies are often received by consortia of collaborating organisations.&lt;/p&gt;

&lt;p&gt;It is common to attach weights to the links based on the number of collaborations between two organisations. Using these weights, it is then possible to filter the graph to focus only on the strongest / most frequently occurring collaborations.&lt;/p&gt;

&lt;p&gt;The graph below shows an example of collaboration in radiotherapy innovation, where colors are based on the type of organisation (e.g. blue = universities, green = hospital and medical centers) and node sizes based on their betweenness centrality scores:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fm8tokb4wtgd5asjo8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fm8tokb4wtgd5asjo8a.png" alt="Collaboration in radiotherapy" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2: Collaboration in radiotherapy&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphs of People: Insight into Expertise and Knowledge Networks
&lt;/h2&gt;

&lt;p&gt;This is a graph perspective that often follows after mapping organizational collaboration networks, focusing on the actual person-to-person collaborations taking place to produce the analysed output. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firwev36fljk3eoyb7hcn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firwev36fljk3eoyb7hcn.png" alt="Graphs of People: Focused on the actual person-to-person collaborations taking place to produce the analysed output. " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the author/inventor metadata on documents, we draw links between people when they have co-authored a document. Similar to the organisational networks, we can also attach weights to the links,  which correspond to the number of documents which have been worked on jointly by two authors. This perspective can provide a deep understanding of the actual team structures and knowledge networks within and outside of organisations.&lt;/p&gt;

&lt;p&gt;Here’s an example of the (relatively large!) network of inventors who have worked on Apple patents. Nodes are sized based on their betweenness centralities, and colors are based on clusters detected by a community detection algorithm:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n98a3uxox1ph32b33ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n98a3uxox1ph32b33ss.png" alt="Apple's inventor network" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 3: Apple's inventor network&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Graph Metrics &amp;amp; Innovation Insights
&lt;/h2&gt;

&lt;p&gt;The above examples show various ways to convert innovation data into actionable graph visualisations. In the actual analysis and interpretation of these graphs, it is important to make good use of the many metrics available in graph analytics. These metrics can help us understand which clusters are present in a network, and can aid in determining the importance of nodes based on centrality measures.&lt;/p&gt;

&lt;p&gt;The following metrics are valuable for analysing the overall graph structure in innovation analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Component analysis:&lt;/strong&gt; determining the components (interconnected subsets of nodes) in the graph to be able to see how far the graph is interconnected (how many nodes can reach each other directly or indirectly) and to determine the impact of the largest connected components versus smaller components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;K-Cores:&lt;/strong&gt; to determine highly connected subsets of nodes in graphs, k-Cores can be used to highlight subgraphs in which all nodes have at least a degree of k. This can be used to focus on so-called cliques of nodes quickly and is especially valuable when analysing collaboration and knowledge networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community detection:&lt;/strong&gt; using an algorithm such as the Leiden community detection algorithm to determine which clusters we can distinguish within the components. These clusters then serve as the basis for graph annotation, where clusters are labeled based on their actual contents (see the labels in the autonomous driving graph above).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the individual node level, degree and betweenness centrality measures can be used to determine the importance of nodes in innovation graphs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Degree Centrality:&lt;/strong&gt; determining simple connection counts per node to quickly see which actors are most important in terms of the number of other nodes they are connected to. Since most innovation graphs are weighted (links have weights associated with them), weighted degree centrality is also used regularly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Betweenness Centrality:&lt;/strong&gt; this is a frequently and often used metric to determine who holds key positions in a graph in terms of hub positions – which organizations/people are the “key connectors” between clusters/teams? It is calculated by determining how often each node appears on the shortest paths between all other nodes in the network.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Up Next: Use Cases
&lt;/h2&gt;

&lt;p&gt;Now that you have an initial idea of the main ideas behind innovation graphs, we will showcase practical use cases, real-world client examples and common challenges in innovation graph analysis in the next blog post. Stay tuned! &lt;/p&gt;

</description>
      <category>technologyclusters</category>
      <category>innovationnetworkanalysis</category>
      <category>knowledgegraph</category>
      <category>graphdatabase</category>
    </item>
    <item>
      <title>In-memory vs. disk-based databases: Why do you need a larger than memory architecture?</title>
      <dc:creator>Memgraph</dc:creator>
      <pubDate>Tue, 05 Sep 2023 14:41:54 +0000</pubDate>
      <link>https://dev.to/memgraph/in-memory-vs-disk-based-databases-why-do-you-need-a-larger-than-memory-architecture-37p</link>
      <guid>https://dev.to/memgraph/in-memory-vs-disk-based-databases-why-do-you-need-a-larger-than-memory-architecture-37p</guid>
      <description>&lt;p&gt;Memgraph is an in-memory graph database that recently added support for working with data that cannot fit into memory. This allows users with smaller budgets to still load large graphs to Memgraph without paying for (more) expensive RAM. However, expanding the main-memory graph database to support disk storage is, by all means, a complex engineering endeavor. Let’s break this process down into pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-disk databases
&lt;/h2&gt;

&lt;p&gt;Disk-based databases have been, for a long time, a de facto standard in the database development world. Their huge advantage lies in their ability to store a vast amount of data relatively cheaply on disk. However, the development can be very complex due to the interaction with low-level OS primitives. Fetching data from disk is something that everyone strives to avoid since it takes approximately 10x more time than using it from main memory. Neo4j is an example of a graph, an on-disk database that uses disk as its main storage media while trying to cache as much data as possible to main memory so it could be reused afterward. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fliwfmi74iomv74hf3bni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fliwfmi74iomv74hf3bni.png" alt="disk oriented dbms" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In-memory databases
&lt;/h2&gt;

&lt;p&gt;In-memory databases avoid the fundamental cost of accessing data from disk by simply storing all its data in the main memory. Such architecture also significantly simplifies the development of the storage part of the database since there is no need for a buffer pool. However, the biggest issue with in-memory databases is when the data cannot fit into the random access memory since the only possible way out is to transfer the data to a larger and, consequently, more expensive machine. &lt;/p&gt;

&lt;p&gt;In-memory database users rely on the fact that durability is still secured through durability mechanisms like transaction logging and snapshots so that data loss does not occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Larger-than-memory architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Main memory computation
&lt;/h3&gt;

&lt;p&gt;Larger-than-memory architecture describes a database architecture when the majority of computations are still within the main memory, but the database offers the ability to store a vast amount of data on disk, too, without having the computational complexity of interacting with buffer pools. &lt;/p&gt;

&lt;h3&gt;
  
  
  Identify hot &amp;amp; cold data
&lt;/h3&gt;

&lt;p&gt;The larger-than-memory architecture utilizes the fact that there are always hot and cold parts of the database in terms of accessing it. The goal is then to find cold data stored and move it to the disk so that transactions still have fast access to hot data. Cold data identification can be done either by directly tracking transactions’ access patterns (online) or by offline computation in which a background thread analyzes data.&lt;/p&gt;

&lt;p&gt;The second very important feature of the larger-than-memory architecture is the process of evicting cold data. This can be done in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DB tracks the memory usage and starts evicting data as soon as it reaches a predefined threshold.&lt;/li&gt;
&lt;li&gt;Eviction can be done only when new data is needed. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Transaction management
&lt;/h3&gt;

&lt;p&gt;Different systems also behave differently regarding transaction management. If the transaction needs data that is currently stored on the disk, it can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abort the transaction, fetch data stored on the disk, and restart the transaction.&lt;/li&gt;
&lt;li&gt;Stall the transaction by synchronously fetching data from the disk.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Transaction must fit into memory
&lt;/h3&gt;

&lt;p&gt;The question is, what happens when the transaction data cannot fit into random access memory? In Memgraph, we decided to start with an approach that all transaction data must fit into memory. This means that some analytical queries cannot be executed on a large dataset, but this is the tradeoff we were willing to accept in the first iteration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjms4r0m897xd4b1u0063.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjms4r0m897xd4b1u0063.png" alt="memory dbms" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of larger-than-memory databases
&lt;/h2&gt;

&lt;p&gt;Memgraph uses &lt;a href="https://rocksdb.org/" rel="noopener noreferrer"&gt;RocksDB&lt;/a&gt; as a &lt;a href="https://memgraph.com/blog/what-is-a-key-value-database" rel="noopener noreferrer"&gt;key-value store&lt;/a&gt; for extending the capabilities of the in-memory database. Not to go into too many details about RocksDB, but let’s just briefly mention that it is based on a data structure called &lt;a href="https://www.cs.umb.edu/~poneil/lsmtree.pdf" rel="noopener noreferrer"&gt;Log-Structured Merge-Tree&lt;/a&gt; (LSMT) (instead of B-Trees, typically the default option in databases), which are saved on disk and because of the design come with a much smaller &lt;a href="https://smalldatum.blogspot.com/2019/05/crum-conjecture-read-write-space-and.html" rel="noopener noreferrer"&gt;write amplification&lt;/a&gt; than B-Trees. &lt;/p&gt;

&lt;p&gt;The in-memory version of Memgraph uses Delta storage to support multi-version concurrency control (MVCC). However, for larger-than-memory storage, we decided to use the Optimistic Concurrency Control Protocol (OCC) since we assumed conflicts would rarely happen, and we could make use of &lt;a href="https://github.com/facebook/rocksdb/wiki/Transactions" rel="noopener noreferrer"&gt;RocksDB’s transactions&lt;/a&gt; without dealing with the custom layer of complexity like in the case of Delta storage. &lt;/p&gt;

&lt;p&gt;We’ve implemented OCC in a way that every transaction has its own private workspace, so potential conflicts are detected at the commit time. One of our primary requirements before starting to add disk-based data storage was not to ruin the performance of the main memory-based storage. Although we all knew there was no such thing as &lt;a href="https://www.youtube.com/watch?v=rHIkrotSwcc" rel="noopener noreferrer"&gt;zero-cost abstraction&lt;/a&gt;, we managed to stay within 10% of the original version. We decided to use &lt;a href="https://memgraph.com/blog/acid-transactions-meaning-of-isolation-levels" rel="noopener noreferrer"&gt;snapshot isolation&lt;/a&gt; as an appropriate concurrency isolation level since we believed it could be the default option for the large majority of Memgraph users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disadvantages of larger-than-memory databases
&lt;/h2&gt;

&lt;p&gt;As always, not everything is sunshine and flowers, especially when introducing such a significant feature to an existing database, so there are still improvements to be made. First, the requirement that a single transaction must fit into memory makes it impossible to use large analytical queries. &lt;/p&gt;

&lt;p&gt;It also makes our &lt;a href="https://memgraph.com/docs/memgraph/import-data/load-csv-clause/" rel="noopener noreferrer"&gt;LOAD CSV&lt;/a&gt; command for importing CSV files practically unusable since the command is executed as a single transaction. Although RocksDB is really good, fits really well into our codebase, and has proved to be very efficient in its caching mechanisms, maintaining an external library is always hard.&lt;/p&gt;

&lt;h2&gt;
  
  
  In retrospect
&lt;/h2&gt;

&lt;p&gt;Albeit the significant engineering endeavor, the larger-than-memory architecture is a super valuable asset to Memgraph users since it allows them to store large amounts of data cheaply on disk without sacrificing the performance of in-memory computation. We are actively working on resolving issues introduced with the new storage mode, so feel free to &lt;a href="https://discord.com/invite/memgraph" rel="noopener noreferrer"&gt;ask&lt;/a&gt;, &lt;a href="https://github.com/memgraph/memgraph/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;, or &lt;a href="https://github.com/memgraph/memgraph/pulls" rel="noopener noreferrer"&gt;pull a request&lt;/a&gt;. We will be more than happy to help. Until next time 🫡 &lt;/p&gt;

</description>
      <category>database</category>
      <category>memgraph</category>
      <category>development</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Exciting News: LangChain Now Supports Memgraph!</title>
      <dc:creator>Memgraph</dc:creator>
      <pubDate>Fri, 25 Aug 2023 07:06:32 +0000</pubDate>
      <link>https://dev.to/memgraph/exciting-news-langchain-now-supports-memgraph-4mc8</link>
      <guid>https://dev.to/memgraph/exciting-news-langchain-now-supports-memgraph-4mc8</guid>
      <description>&lt;p&gt;We're thrilled to announce a powerful integration between LangChain and Memgraph, bringing you an unparalleled natural language interface to your Memgraph database. Say goodbye to complex queries and welcome a seamless and intuitive way to interact with your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memgraph QA chain tutorial
&lt;/h2&gt;

&lt;p&gt;If you've ever wanted to effortlessly query your Memgraph database using natural language, this tutorial is for you. This step-by-step guide will walk you through the process, ensuring you have all the tools you need to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you dive in, make sure you have Docker and Python 3.x installed on your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Launch a Memgraph Instance&lt;/strong&gt;: With a few simple commands, you can have your Memgraph instance up and running using Docker. Just &lt;a href="https://python.langchain.com/docs/use_cases/more/graph/graph_memgraph_qa" rel="noopener noreferrer"&gt;follow our script&lt;/a&gt; to set it up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install dependencies&lt;/strong&gt;: We've got you covered with the required packages. Use pip to install &lt;code&gt;langchain&lt;/code&gt;, &lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;neo4j&lt;/code&gt;, and &lt;code&gt;gqlalchemy&lt;/code&gt;. Don't forget the &lt;code&gt;--user&lt;/code&gt; flag to ensure smooth permissions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code playtime&lt;/strong&gt;: Whether you prefer working within this notebook or want to use a separate Python file, the tutorial offers code snippets to guide you through the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's inside
&lt;/h2&gt;

&lt;p&gt;Explore the rich features and functionalities that LangChain and Memgraph offer together:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API reference&lt;/strong&gt;: We provide an overview of the key components you'll be working with, such as ChatOpenAI, GraphCypherQAChain, and MemgraphGraph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Populating the database&lt;/strong&gt;: Learn how to populate your Memgraph database effortlessly using the Cypher query language. We guide you through the process of seeding data that serves as the foundation for your work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refresh graph schema&lt;/strong&gt;: Familiarize yourself with refreshing the graph schema, a crucial step in setting up the Memgraph-LangChain graph for Cypher queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Querying the database&lt;/strong&gt;: Discover how to interact with the OpenAI API and configure your API key. We'll show you how to utilize the GraphCypherQAChain to ask questions and receive informative responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chain modifiers&lt;/strong&gt;: Customize your chain's behavior with modifiers like return_direct, return_intermediate_steps, and top_k. Tailor the experience to your preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced querying&lt;/strong&gt;: Delve into advanced querying techniques and uncover tips for refining your prompts to improve query accuracy.&lt;/p&gt;

&lt;p&gt;Ready to take your data interaction to the next level? Join us in exploring the seamless synergy between LangChain and Memgraph. No more wrangling with queries – just natural language and meaningful insights. Simplify complexity, elevate your insights, and share your projects in our &lt;a href="https://discord.com/invite/memgraph" rel="noopener noreferrer"&gt;community&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>langchain</category>
      <category>memgraph</category>
      <category>python</category>
    </item>
    <item>
      <title>What is a Graph Database?</title>
      <dc:creator>Ani Ghazaryan</dc:creator>
      <pubDate>Wed, 23 Aug 2023 15:22:01 +0000</pubDate>
      <link>https://dev.to/memgraph/what-is-a-graph-database-4kl4</link>
      <guid>https://dev.to/memgraph/what-is-a-graph-database-4kl4</guid>
      <description>&lt;p&gt;While relational databases have been the go-to choice for data storage, they fall short when it comes to handling complex relationships and traversing interconnected data, which puts graph databases in a special spotlight. A graph database is a specialized database system designed to store, manage, and query highly connected data using graph theory principles. As data volumes continue to explode, companies need efficient and scalable solutions to handle the complexities of their data.&lt;/p&gt;

&lt;p&gt;Specialized database systems like graph databases offer a more natural and efficient way to model, query, and store data, leading to improved performance and better data insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding graphs
&lt;/h2&gt;

&lt;p&gt;In simple terms, at the core of graph databases lies the concept of a graph. In mathematics and computer science, a graph is a collection of nodes (also known as vertices) connected by edges. Nodes represent entities or objects, while edges depict the relationships or connections between them. This straightforward yet effective structure forms the foundation of graph databases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components of graphs
&lt;/h3&gt;

&lt;p&gt;It's your time to shine! Let's reiterate on what we've learned so far. Graphs consist of two fundamental components: nodes and edges.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nodes represent entities or objects and can have various attributes associated with them.&lt;/li&gt;
&lt;li&gt;Edges, on the other hand, depict the relationships or connections between nodes and can also carry properties.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Together, nodes and edges create a rich network of connected data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fnodes-and-edges.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fnodes-and-edges.png" alt="nodes and edges"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Graph theory basics
&lt;/h3&gt;

&lt;p&gt;Another common term you may hear here and there, alluding to graphs or graph databases, is graph theory, which is a branch of mathematics, that provides the theoretical underpinning for understanding and analyzing graphs. It defines vertices as the fundamental building blocks of a graph and edges as the connections between vertices. Relationships in a graph can be represented by directed or undirected edges, capturing the nature and direction of the connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relational databases vs. graph databases
&lt;/h3&gt;

&lt;p&gt;Opinions split when it comes to &lt;a href="https://memgraph.com/blog/how-to-choose-a-database-for-your-needs" rel="noopener noreferrer"&gt;choosing a database&lt;/a&gt;, however, the debate around &lt;a href="https://memgraph.com/blog/graph-database-vs-relational-database" rel="noopener noreferrer"&gt;relational vs. graph databases&lt;/a&gt; is still hot. Relational databases have long been the dominant database model, organizing data into structured tables with predefined schemas. They excel in handling structured data and transactions but face challenges when dealing with complex relationships and traversing connected data. This is largely due to their rigid tabular structure.&lt;/p&gt;

&lt;p&gt;Joining multiple tables and navigating through numerous relationships can lead to performance bottlenecks and complex query formulations. This limits their effectiveness in scenarios where relationships play a crucial role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2FGraph%2520vs%2520Relational%2520DB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2FGraph%2520vs%2520Relational%2520DB.png" alt="relational vs graph databases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Graph databases excel in modeling and querying relationships. They store connections explicitly, allowing for efficient traversals between nodes and enabling complex relationship queries with ease. And of course, graph databases provide flexibility, scalability, and performance advantages over a relational database when it comes to handling interconnected data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Characteristics of graph databases
&lt;/h2&gt;

&lt;p&gt;So far, you've been introduced to a few qualities that are typical to graphs, so let's put the learnings into structure and build off of what you've grasped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema-less nature
&lt;/h3&gt;

&lt;p&gt;Unlike relational databases, graph databases are schema-less, meaning they do not require a predefined structure or schema for data. This flexibility allows for the dynamic addition of new node types, properties, and relationships, making graph databases highly adaptable to evolving data models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native graph processing
&lt;/h3&gt;

&lt;p&gt;Graph databases are purpose-built for processing graph data. They employ optimized algorithms and data structures to efficiently traverse and manipulate the graph structure, resulting in faster query response times and improved performance compared to non-native graph databases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graph traversal and pattern matching
&lt;/h3&gt;

&lt;p&gt;One of the key strengths of graph databases is their ability to traverse and explore relationships between nodes. Graph traversal algorithms can efficiently navigate the graph to discover patterns, uncover hidden connections, and retrieve data based on specific criteria. This capability is particularly valuable in applications such as recommendation engines, fraud detection, and knowledge graphs, which we will explore in the sections to come.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fgraph-traversal-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fgraph-traversal-.png" alt="graph traversal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases of graph databases
&lt;/h2&gt;

&lt;p&gt;Unlike a traditional relational database that relies on tabular data, a graph database utilizes a flexible and intuitive data model, allowing for the representation of intricate relationships between entities. With its ability to efficiently capture and traverse vast networks of data, a graph database has emerged as an advanced tool for diverse domains, including:&lt;/p&gt;

&lt;h3&gt;
  
  
  Social networks and recommendation engines
&lt;/h3&gt;

&lt;p&gt;Graph databases have revolutionized social networking platforms and &lt;a href="https://memgraph.com/blog/building-a-recommendation-system-using-memgraph" rel="noopener noreferrer"&gt;recommendation engines&lt;/a&gt;. They enable personalized recommendations, friend suggestions, and social network analysis by leveraging the rich network of connections between users, interests, and entities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2FSocial-recommendation-engine.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2FSocial-recommendation-engine.png" alt="social recommendation engine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fraud detection and network analysis
&lt;/h3&gt;

&lt;p&gt;Graphs also excel in &lt;a href="https://memgraph.com/blog/how-memgraph-helped-companyx-save-7-figures-fraud-detection" rel="noopener noreferrer"&gt;fraud detection&lt;/a&gt; and network analysis. By representing complex networks of relationships, they can identify suspicious patterns, detect fraudulent activities, and uncover hidden connections that might indicate illicit behavior, making them an invaluable tool for cybersecurity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Ffraud-detection-and-network-analysis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Ffraud-detection-and-network-analysis.png" alt="fraud detection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Knowledge graphs and semantic networks
&lt;/h3&gt;

&lt;p&gt;Last but not least, graph databases serve as a foundation for building knowledge graphs and semantic networks. By representing data as nodes and relationships, they capture the semantics and context of information, enabling sophisticated knowledge discovery, semantic search, and data integration across disparate sources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fknowledge-graphs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhat-is-a-graph-database%2Fknowledge-graphs.png" alt="knowledge graphs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sneak peek into graph algorithms
&lt;/h2&gt;

&lt;p&gt;Surely enough, &lt;a href="https://memgraph.com/white-paper/beginners-guide-to-graph-algorithms" rel="noopener noreferrer"&gt;graph algorithms&lt;/a&gt; play a crucial role in leveraging the power of graph databases and unlocking valuable insights from connected data. In this section, we provide a sneak peek into some fundamental graph algorithms that form the backbone of graph database operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Breadth-First Search (BFS)&lt;/strong&gt;: Breadth-First Search is a fundamental algorithm used to explore and traverse a graph in a breadth-first manner. Starting from a given source node, BFS systematically explores all the neighboring nodes before moving deeper into the graph. This algorithm is commonly used to find the shortest path between two nodes, identify connected components, and perform level-based analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Depth-First Search (DFS)&lt;/strong&gt;: Depth-First Search is another crucial graph algorithm that explores a graph with a depth-first principle. DFS starts from a given source node and traverses as far as possible along each branch before backtracking. The algorithm is useful for identifying cycles in a graph, performing topological sorting, and searching for specific nodes or patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PageRank algorithm&lt;/strong&gt;: Developed by Google's founders, &lt;a href="https://memgraph.com/blog/pagerank-algorithm-for-graph-databases" rel="noopener noreferrer"&gt;PageRank&lt;/a&gt; is a graph algorithm used to measure the importance or relevance of nodes in a graph, particularly in web graphs. PageRank assigns each node a numerical value based on the number and quality of incoming links, and plays a vital role in search engine ranking, recommendation systems, and social network analysis.&lt;/p&gt;

&lt;p&gt;These are just a few examples of the numerous graph algorithms available, however, graph databases employ a wide range of algorithms to perform tasks such as &lt;a href="https://memgraph.com/docs/mage/algorithms/traditional-graph-analytics/community-detection-algorithm" rel="noopener noreferrer"&gt;community detection&lt;/a&gt;, centrality analysis, graph clustering, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sum up
&lt;/h2&gt;

&lt;p&gt;In this article, we explored the world of graph databases and their significance in modern data management. We defined graph databases and highlighted their importance in handling complex relationships and interconnected data. If you're curious and want to learn more about the fascinating world of graphs, make sure to check out our &lt;a href="https://memgraph.com/blog" rel="noopener noreferrer"&gt;blog&lt;/a&gt; and give us a shout in our &lt;a href="https://memgraph.com/community" rel="noopener noreferrer"&gt;community&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Security Analysis with JupiterOne’s Starbase and Memgraph</title>
      <dc:creator>Matea Pesic</dc:creator>
      <pubDate>Tue, 22 Aug 2023 16:36:38 +0000</pubDate>
      <link>https://dev.to/memgraph/security-analysis-with-jupiterones-starbase-and-memgraph-138f</link>
      <guid>https://dev.to/memgraph/security-analysis-with-jupiterones-starbase-and-memgraph-138f</guid>
      <description>&lt;p&gt;Starbase is an open-source graph-based security analysis tool that unifies all of JupiterOne’s integrations into one. It collects assets and relationships from services and systems, including cloud infrastructure, SaaS applications, security controls, and more, into an intuitive graph visualization. With over 115 open-source graph integrations, Starbase collaborates with your existing toolkit enabling easy and insightful cyber security analysis.&lt;/p&gt;

&lt;p&gt;In this article, we’ll dig into Starbase, guiding you through the setup of two example integrations and enabling Starbase to work with Memgraph for easy ingestion and visualization of your graph data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p3ARwUhY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/starbase-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p3ARwUhY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/starbase-logo.png" alt="starbase logo" width="726" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Installed &lt;a href="https://yarnpkg.com/"&gt;Yarn&lt;/a&gt; package manager.&lt;/li&gt;
&lt;li&gt;Installed &lt;a href="https://nodejs.org/en"&gt;Node.js&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A running Memgraph instance—visit Memgraph’s docs for instructions on how to &lt;a href="https://memgraph.com/docs/memgraph/installation"&gt;install&lt;/a&gt; and &lt;a href="https://memgraph.com/docs/memgraph/connect-to-memgraph"&gt;connect&lt;/a&gt; to Memgraph.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up Starbase
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;To kick-start your Starbase setup, first, you need to clone the &lt;a href="https://github.com/JupiterOne/starbase"&gt;JupiterOne/Starbase&lt;/a&gt; repo into your local directory and ensure you have &lt;strong&gt;Yarn&lt;/strong&gt; and &lt;strong&gt;Node.js&lt;/strong&gt; installed.&lt;/li&gt;
&lt;li&gt;Once you’ve successfully cloned the repository and installed the prerequisites, place yourself in the terminal in the directory where you cloned the repo and run the &lt;code&gt;yarn&lt;/code&gt; command. The command installs all of the necessary project dependencies.&lt;/li&gt;
&lt;li&gt;The next step is setting up configurations for your integration of choice. You can find a list of all integrations on JupiterOne’s GitHub repo. Moving forward, we are going to explore two options for possible integration, &lt;a href="https://github.com/jupiterone/graph-zoom"&gt;Zoom&lt;/a&gt;, and &lt;a href="https://github.com/jupiterone/graph-github"&gt;GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up integrations
&lt;/h2&gt;

&lt;p&gt;In order to set up an integration, you need to register an account in the system the integration targets for ingestion and obtain the necessary API credentials. Starbase leverages credentials from external services to authenticate and collect data. When Starbase is started, it reads configuration data from a single configuration file named &lt;code&gt;config.yaml&lt;/code&gt; at the root of the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoom integration
&lt;/h3&gt;

&lt;p&gt;In order to configure the Zoom integration, we need to create a Zoom app to retrieve the needed credentials: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://marketplace.zoom.us/"&gt;Zoom App Marketplace&lt;/a&gt; and sign into your Zoom account.&lt;/li&gt;
&lt;li&gt;In the top right corner, go to the Develop dropdown menu and select Build App.&lt;/li&gt;
&lt;li&gt;Choose to create an &lt;strong&gt;OAuth&lt;/strong&gt; type of app.&lt;/li&gt;
&lt;li&gt;Take note of your &lt;strong&gt;Account ID&lt;/strong&gt;, &lt;strong&gt;Client ID&lt;/strong&gt;, and &lt;strong&gt;Client secret&lt;/strong&gt; which we’ll need for the configuration file later on.&lt;/li&gt;
&lt;li&gt;In the Scopes section, add &lt;code&gt;group:read:admin&lt;/code&gt;, &lt;code&gt;role:read:admin&lt;/code&gt;, &lt;code&gt;user:read:admin&lt;/code&gt;, and &lt;code&gt;account:read:admin&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After you’ve successfully created your Zoom App, open up the starbase repo in your editor of choice and create your &lt;code&gt;config.yaml&lt;/code&gt; file. This is an example of a &lt;code&gt;config.yaml&lt;/code&gt; file for Zoom integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;integrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;zoom&lt;/span&gt;
    &lt;span class="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;testInstanceId&lt;/span&gt;
    &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;integrations&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;zoom&lt;/span&gt;
    &lt;span class="nx"&gt;gitRemoteUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/JupiterOne/graph-zoom.git&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read:admin role:read:admin user:read:admin account:read:admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub integration
&lt;/h3&gt;

&lt;p&gt;In order to configure GitHub integration, we need to create a GitHub app to retrieve the needed credentials: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://github.com/settings/apps"&gt;GitHub Apps&lt;/a&gt; and select to create a new GitHub App&lt;/li&gt;
&lt;li&gt;Name your app, and enter a homepage URL (in this case, you can use the JupiterOne’s &lt;a href="https://github.com/JupiterOne/starbase"&gt;Starbase repo URL&lt;/a&gt;), uncheck the webhook and adjust the repository permissions. The following permissions need to be set to &lt;strong&gt;read-only&lt;/strong&gt;: 
-&lt;em&gt;Repository Permissions&lt;/em&gt;: Actions, Environments, Issues, Pull Requests and Secrets
-&lt;em&gt;Organization Permissions&lt;/em&gt;: Administration, Members, Secrets. The rest of the permissions are &lt;strong&gt;No access&lt;/strong&gt; by default. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read-only access for secrets repo doesn’t give read-only access to actual secret content, it only gives read-only info to the existence of the metadata about the secrets.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Any account&lt;/strong&gt; and create your GitHub App.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After you’ve successfully created your GitHub App, open up the cloned Starbase repository in your editor of choice and create your &lt;code&gt;config.yaml&lt;/code&gt; file. Generate your private key and retrieve other needed credentials from the GitHub App you previously created. Below is an example of a &lt;code&gt;config.yaml&lt;/code&gt; file for a GitHub integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;integrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;-&lt;/span&gt;
     &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;
     &lt;span class="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;testInstanceId&lt;/span&gt;
     &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;integrations&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;
     &lt;span class="nx"&gt;gitRemoteUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/JupiterOne/graph-github.git&amp;gt;&lt;/span&gt;
     &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;GITHUB_APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_APP_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;GITHUB_APP_LOCAL_PRIVATE_KEY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;YOURPATH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/{YOURFILENAME}.private-key.pe&lt;/span&gt;&lt;span class="err"&gt;m
&lt;/span&gt;        &lt;span class="nx"&gt;INSTALLATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;INSTALLATION_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;GITHUB_API_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//api.github.com     &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Starbase with Memgraph
&lt;/h2&gt;

&lt;p&gt;After you’ve successfully created your &lt;code&gt;config.yaml&lt;/code&gt; file, the last step is to adjust your queries to work with Memgraph. In order to do that, run the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, you need to place yourself in the terminal in the folder you cloned your Starbase repo and run yarn starbase setup command to clone or update all integrations listed in the config.yaml file, as well as install all dependencies for each integration.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run your Memgraph instance. Follow the instructions from Memgraph’s docs on how to connect to Memgraph, or if you are using Docker, simply run the following command:&lt;br&gt;
&lt;code&gt;docker run -it -p 3000:3000 -p 7444:7444 -p 7687:7687 memgraph/memgraph-platform&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By modifying just a single line of code, you are ready to use Starbase with Memgraph. Inside the neo4jGraphStore.js file, locate the addEntities() function. To enable compatibility with Memgraph, simply update the following line:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runCypherCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE INDEX index_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; IF NOT EXISTS FOR (n:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) ON (n._key, n._integrationInstanceID);`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runCypherCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE INDEX index_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; IF NOT EXISTS FOR (n:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) ON (n._key, n._integrationInstanceID);`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runCypherCommand&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You are all set to utilize Starbase with Memgraph. The instance is actively listening to port 7687, as defined in the code. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final step is to run the &lt;code&gt;yarn starbase run&lt;/code&gt; command. Afterward, launch your browser and go to &lt;code&gt;localhost:3000&lt;/code&gt; to access &lt;strong&gt;Memgraph Lab&lt;/strong&gt; or open your desktop version to explore and visualize your graph data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explore your dataset
&lt;/h3&gt;

&lt;p&gt;Below, we’ve provided a few query examples that demonstrate how you can dig into your dataset and extract valuable insights. The following examples assume the use of GitHub integration.&lt;/p&gt;

&lt;p&gt;With the following query, you are retrieving the information of all of the extracted GitHub users from a certain organization:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MATCH (n:github_user) RETURN n LIMIT 3;&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9sx93pZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/github-user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9sx93pZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/github-user.png" alt="github user" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you also want to determine which code owners of organization repositories grant access to outside contributors, execute the following query:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MATCH (account:github_account) - [e:OWNS] -&amp;gt; (repo:github_repo) -&amp;gt; [f:ALLOWS] -&amp;gt; (user:github_user {role: ‘OUTSIDE’})&lt;br&gt;
RETURN account, repo, user, e, f;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DM8YN9Pf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/github-user-awesome-code.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DM8YN9Pf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/security-analysis-with-starbase-and-memgraph/github-user-awesome-code.png" alt="github user awesome code" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Starbase is a powerful tool that simplifies security analysis by unifying integrations into a user-friendly graph view, enhancing cybersecurity insights. Incorporating Memgraph for data ingestion adds another dimension by enhancing its capabilities and visualizing your data. If you are curious about graphs and would like to learn more, make sure to check out our &lt;a href="https://memgraph.com/blog"&gt;blog&lt;/a&gt; and join our community on &lt;a href="https://discord.gg/memgraph"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Memgraph vs. TigerGraph</title>
      <dc:creator>Vlasta Pavicic</dc:creator>
      <pubDate>Fri, 18 Aug 2023 06:43:44 +0000</pubDate>
      <link>https://dev.to/memgraph/memgraph-vs-tigergraph-405o</link>
      <guid>https://dev.to/memgraph/memgraph-vs-tigergraph-405o</guid>
      <description>&lt;p&gt;In today's data-driven world, the necessity to process and interpret complex relationships within massive datasets is making organizations continually search for the go-to graph database, leaving the traditional relational database options behind. After the initial &lt;a href="https://db-engines.com/en/ranking/graph+dbms"&gt;DB-Engines&lt;/a&gt; consultations, two names commonly arise in conversations: TigerGraph and Memgraph. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5ldneKA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/db-rankings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5ldneKA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/db-rankings.png" alt="db-engines-ranks" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background on both solutions
&lt;/h2&gt;

&lt;p&gt;Founded in 2012 by Dr. Yu Xu, &lt;strong&gt;TigerGraph's&lt;/strong&gt; core objective is to provide a scalable and efficient graph database platform that enables organizations to leverage the power of interconnected data, supporting applications ranging from fraud detection to AI and machine learning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memgraph&lt;/strong&gt; is an in-memory, open-source graph database with roots in the UK and Croatia. Founded by Marko Budiselic and Dominik Tomicevic in 2016, and backed by American investors, Memgraph prioritizes high performance and developer accessibility. With a robust community edition, the platform offers a blend of ease of use and practical functionality, all presented through clear and uncomplicated &lt;a href="https://memgraph.com/blog/what-is-an-open-source-license"&gt;licensing&lt;/a&gt;, making it the backbone of many cybersecurity solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memgraph vs. TigerGraph differences
&lt;/h2&gt;

&lt;p&gt;Although both TigerGraph and Memgraph have been developed in C++ and aim to provide performant solutions for &lt;a href="https://memgraph.com/blog/real-time-graph-analytics"&gt;real-time data analytics&lt;/a&gt;, there exist some important differences between the two platforms that set them apart. Let’s check what those are.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query language
&lt;/h3&gt;

&lt;p&gt;The choice of query language plays a significant role in the overall user experience.&lt;/p&gt;

&lt;p&gt;GSQL, TigerGraph's proprietary query language, does offer an expressive, Turing-complete language tailored for graph pattern-matching and analytics functions but might present a steeper learning curve for those new to graphs. It has been specifically designed for TigerGraph, and the skillset may not be easily transferred from or to other graph database platforms. &lt;/p&gt;

&lt;p&gt;In contrast, Cypher query language is an open-source, declarative language known for its user-friendly syntax. Cypher's human-readable style has propelled it into a standard for querying graph databases. It has been developed by Neo4j but is utilized by various systems, including Memgraph. Due to its simplicity, and broad community support, it is a preferred choice for many developers who know their applications will need minimum changes if they require a switch to another database vendor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data storage
&lt;/h3&gt;

&lt;p&gt;TigerGraph and Memgraph offer distinctive approaches to handling data in their graph databases, each reflecting a unique strategy to balance performance, scalability, and flexibility. &lt;/p&gt;

&lt;p&gt;TigerGraph employs a hybrid memory-disk approach, leveraging RAM for storing frequently accessed data and disk storage for large graphs that may exceed available memory. This hybrid model allows TigerGraph to achieve real-time analytics, where active datasets are immediately available, while also scaling to handle massive datasets without being constrained by RAM.&lt;/p&gt;

&lt;p&gt;In contrast, Memgraph's architecture has been built natively for in-memory data analysis and storage, focusing on lightning-fast data processing. Being ACID compliant, it ensures consistency and reliability in its core design. However, Memgraph also offers flexibility. An analytical storage mode that bypasses ACID compliance is available, accelerating analytics and data import operations when absolute consistency is not required. Additionally, an on-disk storage option allows users to weigh performance against budget constraints, thus achieving a balance tailored to specific needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mTjPjUl_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/storage-modes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mTjPjUl_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/storage-modes.png" alt="storage-modes" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While TigerGraph's hybrid approach offers a comprehensive solution for both speed and scalability, Memgraph's focus on in-memory processing with adaptable options reflects a commitment to performance with versatility to suit various requirements. The distinction between these two models shows the innovation in graph database technology, catering to diverse needs in data management, analysis, and storage. &lt;/p&gt;

&lt;h3&gt;
  
  
  Data isolation level
&lt;/h3&gt;

&lt;p&gt;TigerGraph employs a &lt;a href="https://memgraph.com/blog/acid-transactions-meaning-of-isolation-levels"&gt;read-committed data isolation level&lt;/a&gt;, meaning that a transaction can access data which is committed before and during this transaction’s execution.&lt;br&gt;
For example, two same READ queries inside one transaction can return different results because between them another transaction was committed.&lt;/p&gt;

&lt;p&gt;On the other hand, Memgraph uses snapshot isolation by default, where each query operates on a consistent snapshot of the data at the query's start time, with the option to change the isolation level, but snapshot isolation offers an advantage as it provides a more consistent view of the data, reducing the chance of reading partial or uncommitted changes. This ensures more accurate query results and a smoother transaction experience, making snapshot isolation generally considered a more reliable approach in many scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pricing models and support
&lt;/h3&gt;

&lt;p&gt;TigerGraph has a free version that allows users to work with up to 50GB of data, making it suitable for small projects or initial exploration. Memgraph offers something different with its &lt;a href="https://memgraph.com/pricing"&gt;Community Edition&lt;/a&gt;, which is not only free but also open-source and packed with features.&lt;/p&gt;

&lt;p&gt;For example, both TigerGraph and Memgraph offer high availability features to ensure that data is consistently accessible and resistant to failures, but Memgraph's replication is available even in the Community Edition of the product. This means that the Community Edition is not "crippleware" but a fully functional version that allows users to "kick the tires" on the product and properly test it to ensure it meets requirements before deploying it in a production environment.&lt;/p&gt;

&lt;p&gt;By offering this, and a plethora of other features in the Community Edition, Memgraph not only shows a commitment to performance and reliability but also to accessibility, empowering users to explore and validate the capabilities of the software without barriers.&lt;/p&gt;

&lt;p&gt;Due to the lack of complicated layers of management that some larger companies might have, in Memgraph you can talk directly to engineers if you have questions or need help. It's a more hands-on, direct way of working that puts you closer to the people who built the product, and it can make working with Memgraph a more pleasant and efficient experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of features
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vm3EHAvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/memgraph-vs-tigergraph/overview-of-features.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vm3EHAvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/memgraph-vs-tigergraph/overview-of-features.png" alt="overvies-of-features" width="743" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways on both graph databases
&lt;/h2&gt;

&lt;p&gt;Memgraph and TigerGraph both offer graph database solutions, but Memgraph's native in-memory design sets it apart. Built for speed without losing stability or ACID compliances, Memgraph provides efficient real-time querying and analytics. Although TigerGraph claims to be "The World’s Fastest Graph Analytics Platform for the Enterprise", clients have reported increased performance after switching to Memgraph. If speed, reliability, direct interaction, and support from engineers are key priorities, Memgraph may be the more appealing choice. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ePlK0GrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/benchgraph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ePlK0GrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/tigergraph-vs-memgraph/benchgraph.png" alt="benchgraph" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the performance of Memgraph on your own dataset using &lt;a href="https://memgraph.com/blog/benchmark-memgraph-or-neo4j-with-benchgraph"&gt;Benchgraph&lt;/a&gt;, a graph database performance benchmark, and feel free to &lt;a href="https://memgraph.com/contact-us"&gt;contact us&lt;/a&gt; about making the switch.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is a Key-Value Database?</title>
      <dc:creator>Kruno Golubic</dc:creator>
      <pubDate>Thu, 03 Aug 2023 09:17:43 +0000</pubDate>
      <link>https://dev.to/memgraph/what-is-a-key-value-database-34jh</link>
      <guid>https://dev.to/memgraph/what-is-a-key-value-database-34jh</guid>
      <description>&lt;p&gt;In the landscape of data management solutions, key-value databases stand apart, offering a unique blend of simplicity and performance tailored to the big data era. By abstracting data into simple key-value pairs and values, this type of database offers an intuitive and flexible data model that can seamlessly scale to accommodate large datasets. Before delving into the complexities of key-value databases, their advantages, use cases, and potential drawbacks, let's first establish a foundational understanding of these databases and how they represent a distinctive paradigm in data storage and retrieval.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding a key-value store
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://memgraph.com/blog/how-to-choose-a-database-for-your-needs"&gt;ever-expanding world of databases&lt;/a&gt;, key-value databases have emerged as a vital element. They are designed for storing, retrieving, and managing associative arrays, a data structure commonly known as a dictionary or hash table. The dictionary contains a collection of records, each with different fields containing data. These records are stored and retrieved using a unique key. This unique approach to data management differs from traditional relational databases and makes a key-value database an optimal solution for use cases where simplicity, speed, and scalability are paramount. Key-value databases are the &lt;a href="https://memgraph.com/blog/types-of-nosql-databases-deep-dive"&gt;simplest form of NoSQL databases&lt;/a&gt;. Each item in the database is stored as an attribute name, or key, together with its value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining key-value stores
&lt;/h2&gt;

&lt;p&gt;A key-value database, or key-value store, uses a simple key-value method to store data. Each key-value pair represents a specific piece of data. The 'key' serves as a unique identifier that is used to find the data within the database. Key-value databases treat the data as a single opaque collection, which may have different fields for every record. This offers considerable flexibility and more closely aligns with modern concepts like object-oriented programming.&lt;/p&gt;

&lt;p&gt;The primary features of a key-value database include simplicity, high performance, and the ability to handle large volumes of data efficiently. Because placeholders or input parameters do not represent optional values, key-value databases often use far less memory to store the same data, which can lead to significant performance gains in certain workloads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lGJCeU5G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/key-value-database.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lGJCeU5G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/key-value-database.png" alt="key value database" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with a key-value database
&lt;/h2&gt;

&lt;p&gt;Key-value databases are known for their ease of use, making them a good starting point for beginners in the database realm. Thanks to their straightforward data structure, they provide a simple, user-friendly interface. The process involves storing unique keys associated with their corresponding data values and retrieving the associated value using its unique key.&lt;/p&gt;

&lt;p&gt;Key-value databases excel in &lt;a href="https://databasetown.com/key-value-database-use-cases/"&gt;use cases that involve frequently accessed data&lt;/a&gt;. For instance, in e-commerce platforms, a key-value database could be used to store product details. The unique identifier or 'key' could be the product ID, with all the related product data stored as the associated 'value'. Another scenario is user logs, where key-value stores prove to be efficient. Popular key-value database examples include Redis, DynamoDB, Riak, and RocksDB have active community support and extensive documentation, making it easier for developers to get started and troubleshoot issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits and advantages of a key-value database
&lt;/h2&gt;

&lt;p&gt;Developers and organizations &lt;a href="https://www.geeksforgeeks.org/key-value-data-model-in-nosql/"&gt;choose key-value databases for several reasons&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed
&lt;/h3&gt;

&lt;p&gt;One of the main reasons is their speed. Key-value databases can handle large volumes of reads and writes with minimal latency. The simplicity of the data structures used in a key-value store makes it easy for developers to quickly store and retrieve data. They offer impressive speed and performance, handling large volumes of data and providing rapid, random data access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Horizontal scaling
&lt;/h3&gt;

&lt;p&gt;Scalability is a critical factor for modern applications dealing with ever-growing data volumes and increasing user demands. Key-value stores offer an advantage in this area, as they can easily scale horizontally. Horizontal scaling involves adding more servers to the existing network to distribute the data and workload across multiple nodes. As a result, key-value databases can maintain their performance levels even as data grows, ensuring that applications can handle a high number of concurrent users and massive data storage needs. This ability to scale out effectively makes them a preferred choice for applications that require elasticity and flexibility.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QkfJCRJt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/pros-vs-cons.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QkfJCRJt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/pros-vs-cons.png" alt="pros vs cons" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ease of use and development
&lt;/h3&gt;

&lt;p&gt;Key-value databases provide a simple and straightforward interface for data storage and retrieval. Developers can easily interact with the database using basic operations like "get" and "put" based on the associated keys. The straightforward API and data model reduce the complexity of the application code, making it easier to develop and maintain. Additionally, the ease of integration with various programming languages and frameworks allows developers to quickly incorporate key-value stores into their applications without a steep learning curve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible data models
&lt;/h3&gt;

&lt;p&gt;Key-value databases are schema-less, meaning that they do not enforce a fixed data structure or data types. This flexibility allows developers to store and manage various types of data within the same database without strict predefined schemas. This is particularly advantageous for applications dealing with diverse and evolving data formats. Whether it's storing user profiles, session data, configurations, or complex objects, key-value databases can handle different data formats efficiently, eliminating the need for complex and costly data transformations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential drawbacks of a key-value database
&lt;/h2&gt;

&lt;p&gt;While key-value databases are powerful, they &lt;a href="https://www.techtarget.com/searchdatamanagement/tip/NoSQL-database-types-explained-Key-value-store"&gt;aren't always the ideal choice&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex queries
&lt;/h3&gt;

&lt;p&gt;They lack the ability to perform complex queries or handle sophisticated relationships between data, which relational databases excel at. If your use case involves complex queries or requires understanding the relationships between different data entities, then a relational database or a graph database might be a better fit. Also, they may not be suitable for applications that require multi-record transactions or complex data manipulation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lack of data relationships
&lt;/h3&gt;

&lt;p&gt;Key-value databases do not inherently support relationships between data items. While data can be organized and retrieved efficiently based on keys, establishing complex relationships between different pieces of data requires additional application logic. This can lead to potential data inconsistencies and increased complexity in managing relationships outside the database layer. For applications heavily reliant on data relationships, such as social networks or recommendation systems, graph databases may provide more natural and performant solutions, as they are specifically designed to handle and traverse complex data relationships efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling complex data types
&lt;/h3&gt;

&lt;p&gt;Another challenge with key-value databases is the handling of complex data types. While they can handle structured, semi-structured, and unstructured data, they lack the advanced capabilities of a document database in managing complex objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data size and indexing
&lt;/h3&gt;

&lt;p&gt;As the data size grows significantly, key-value databases may face challenges with indexing and maintaining performance. While they excel at handling fast key-based lookups, large datasets can impact the efficiency of these operations. Proper index design and tuning are crucial to ensure optimal performance. Additionally, some key-value databases may not offer sophisticated indexing options, limiting their capabilities to efficiently handle specific types of queries or data access patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overcoming limitations of a key-value database
&lt;/h2&gt;

&lt;p&gt;Despite these limitations, there are strategies and tools that can help overcome them. For example, secondary indexing and query languages like Redis's RediSearch and Amazon DynamoDB's Query Language can help perform more complex queries. Hybrid models, combining a key-value database with other database types like document databases, can handle complex queries or manage complex relationships between data entities. Additional technologies that can be incorporated into key-value databases to enhance functionality include secondary indexing to create efficient index structures to accelerate application responses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oq50WUSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/success.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oq50WUSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://public-assets.memgraph.com/what-is-a-key-value-database/success.png" alt="success" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Key-value databases offer a compelling mix of simplicity, speed, and scalability that can be highly beneficial in certain situations. As with any technology, it's important to understand its strengths and weaknesses to make the most of it. The key-value database world is constantly evolving, and it's an exciting area to explore for any developer or organization looking to optimize their data storage and retrieval needs.&lt;/p&gt;

&lt;p&gt;They are a fantastic choice for use cases that involve handling large volumes of frequently accessed data or where horizontal scalability is required. However, it's crucial to understand the capabilities and limitations of key-value databases before choosing them as a solution. Overall, with ongoing evolution and innovation in the database world, the future looks promising for the key-value database scene.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When to Use a NoSQL Database</title>
      <dc:creator>Katarina Supe</dc:creator>
      <pubDate>Fri, 21 Jul 2023 13:44:05 +0000</pubDate>
      <link>https://dev.to/memgraph/when-to-use-a-nosql-database-201k</link>
      <guid>https://dev.to/memgraph/when-to-use-a-nosql-database-201k</guid>
      <description>&lt;p&gt;How we manage and process data changes rapidly over the years, and staying on track with the newest technology trends is important. Traditional relational database management systems, such as MySQL, Oracle, and SQL Server, have always been the first choice to maintain data integrity and for fast querying, but with the rise of big data, NoSQL (Not Only SQL) databases emerged and became more popular due to their speed, flexibility, and scalability. Now, the question that pops up naturally is when is the right time to use a NoSQL database?&lt;/p&gt;

&lt;p&gt;This blog post will explore NoSQL databases and how they differ from traditional databases. Besides, you will learn when and why to utilize NoSQL databases. Whether you’re a developer, data engineer, or decision maker, this blog post will provide insights into modern databases that will come in handy to boost your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding NoSQL databases
&lt;/h2&gt;

&lt;p&gt;NoSQL databases are non-relational databases with flexible schema designed for high performance at a massive scale. Unlike traditional relational databases, which use tables and predefined schemas, NoSQL databases use a variety of data models. There are 4 main types of NoSQL databases - document, graph, key-value, and column-oriented databases. NoSQL databases generally are well-suited for unstructured data, large-scale applications, and agile development processes. The most popular examples of NoSQL databases are &lt;a href="https://www.mongodb.com/" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; (document), &lt;a href="https://memgraph.com/" rel="noopener noreferrer"&gt;Memgraph&lt;/a&gt; (graph),  &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; (key-value store) and &lt;a href="https://hbase.apache.org/" rel="noopener noreferrer"&gt;Apache HBase&lt;/a&gt; (column-oriented).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fnosql-databases.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fnosql-databases.png" alt="nosql databases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These &lt;a href="https://memgraph.com/blog/types-of-nosql-databases-deep-dive" rel="noopener noreferrer"&gt;types of NoSQL databases&lt;/a&gt; store data in their own unique ways offering pros and cons, which are presented below:&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: If you’ve used an SQL database before, you are probably familiar with its strict schema. That can be a hassle with data rapidly changing. NoSQL databases, with their dynamic and flexible schemas, have a huge advantage in handling unstructured and semi-structured data, making an excellent choice for diverse data types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Data volumes can grow exponentially, and scalability becomes crucial, especially with the rise of big data. Many NoSQL databases offer horizontal scalability, allowing you to add more servers to increase the capacity. On the other hand, SQL databases usually scale only vertically. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Many NoSQL databases are optimized to deliver high performance, even when dealing with large data volumes or data streams. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maturity&lt;/strong&gt;: SQL (standing for Structured Query Language) databases have been popular in the database world for a long time, and because of that, they offer robustness, tools and community that NoSQL databases have not managed to match yet. That does not mean that NoSQL will not overtake over the years, just like it happens often with modern technologies. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: The learning curve with NoSQL databases is steeper than with SQL databases, especially because there is no standard query language. This follows from the maturity and the fact that NoSQL databases are more complex to design, implement and manage. But, the results you gain by storing your data in a proper database might be worth it. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACID compliance&lt;/strong&gt;: Opposite to NoSQL databases, many SQL databases are usually ACID-compliant. However, as an exception, Memgraph is a NoSQL graph database that is ACID compliant. If you’re unsure what that means for your application, you are invited to check out our recent blog on &lt;a href="https://memgraph.com/blog/acid-transactions-meaning-of-isolation-levels" rel="noopener noreferrer"&gt;ACID transactions and isolation levels&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5 reasons to choose a NoSQL database
&lt;/h2&gt;

&lt;p&gt;Based on the above-mentioned advantages and disadvantages of NoSQL databases, there are various scenarios where NoSQL databases are the optimal solution for your project. Let’s take a look at 5 scenarios where NoSQL databases are great:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Handling large volumes of data at scale seamlessly
&lt;/h3&gt;

&lt;p&gt;NoSQL databases can handle large amounts of data by spreading it across multiple servers. Hence, the NoSQL database is a perfect solution if you have large amounts of growing data. You don’t have to worry that you don’t have enough resources to scale vertically; instead, you should design your database system properly to get the most insights from your data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fvertical-vs-horizontal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fvertical-vs-horizontal.png" alt="vertical vs horizontal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Working easily with unstructured or semi-structured data
&lt;/h3&gt;

&lt;p&gt;Predefined schemas can be good sometimes, but if you’ve always found that a hassle for your unstructured or semi-structured data which is often changing, NoSQL databases are the correct approach. They are built with flexible data schema, which speeds up the development process and lowers the efforts on database management. Problems with data types like XML, JSON and others have become issues of the past with NoSQL databases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fstructured-semi-structured-unstructured-data.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fstructured-semi-structured-unstructured-data.png" alt="structured and unstructured data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Enabling rapid development
&lt;/h3&gt;

&lt;p&gt;Again, because of the NoSQL flexibility, your data model can rapidly change, meaning you can update your application on the fly without schema updates. Nowadays, development is fast, and iterations are quick, so removing the task of updating schemas constantly saves you valuable time that can be spent on even faster development.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. High read/write speed
&lt;/h3&gt;

&lt;p&gt;If you’re working on applications that require real-time data processing, you might be stuck with traditional databases that don’t offer the required speed. NoSQL databases are optimized for high-speed read and write operations and are ideal for chat, IoT, gaming, fraud detection, and similar applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Managing complex relationships
&lt;/h3&gt;

&lt;p&gt;Complex data relationships, such as parent-child or many-to-many relationships, arise in relational databases when data from different tables is related or somehow interconnected. Querying it requires hopping from one table to another and joining it with slow and resource-intensive join operations. A graph database is a type of NoSQL database that handles highly-connected data especially well and is a good choice for social networks, recommendation engines, fraud detection, or any application where you need to traverse through interconnected data points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fdata-pouring.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-assets.memgraph.com%2Fwhen-to-use-nosql-database%2Fdata-pouring.png" alt="data pouring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Concluding thoughts
&lt;/h2&gt;

&lt;p&gt;If you still don’t know whether you need an NoSQL or a relational database management system, we prepared &lt;a href="https://memgraph.com/blog/how-to-choose-a-database-for-your-needs" rel="noopener noreferrer"&gt;another article&lt;/a&gt; on that topic that may speed up your decision process. Keep in mind that it doesn’t always have to be a fight, SQL vs NoSQL, you can surely consider a hybrid approach and get the best out of both SQL and NoSQL databases. But if you did find that your use case fits the description above, then NoSQL is a database for you! We are always open to discussions on this and other topics in the database scene, so &lt;a href="https://www.discord.gg/memgraph" rel="noopener noreferrer"&gt;join the conversation&lt;/a&gt; on our Discord server to be a part of the community.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Build a Graph Web Application With Python, Flask, Docker &amp; Memgraph</title>
      <dc:creator>Memgraph</dc:creator>
      <pubDate>Thu, 20 Jul 2023 11:24:36 +0000</pubDate>
      <link>https://dev.to/memgraph/how-to-build-a-graph-web-application-with-python-flask-docker-memgraph-1nmd</link>
      <guid>https://dev.to/memgraph/how-to-build-a-graph-web-application-with-python-flask-docker-memgraph-1nmd</guid>
      <description>&lt;p&gt;The goal is straightforward (or at least it seems simple enough). Let's build a&lt;br&gt;
web application in &lt;strong&gt;Python&lt;/strong&gt; that can visualize a graph and run some cool graph&lt;br&gt;
algorithms out of the box. Maybe it's not your flavor, but I prefer the&lt;br&gt;
&lt;strong&gt;Flask&lt;/strong&gt; web framework for such occasions, so bear with me through this&lt;br&gt;
tutorial.&lt;/p&gt;

&lt;p&gt;Now, I am going to show you an example of how to accomplish this. You can also&lt;br&gt;
take a look at the &lt;a href="https://github.com/g-despot/graph-web-application" rel="noopener noreferrer"&gt;finished&lt;br&gt;
app&lt;/a&gt;&lt;br&gt;
on GitHub if you want to see the complete code.&lt;/p&gt;

&lt;p&gt;The general outline of the tutorial is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a Flask server&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dockerize your application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import the data into Memgraph&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query the database&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Graph visualizations will be covered in &lt;strong&gt;part two&lt;/strong&gt; of the tutorial so stay&lt;br&gt;
tuned! Spoiler alert, we are going to use D3.js to draw our graph.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you will need to install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; &lt;em&gt;(which is included with
Docker on Windows and macOS)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Docker, we don't need to worry about installing Python, Flask, Memgraph...&lt;br&gt;
essentially anything. Everything will be installed automatically and run&lt;br&gt;
smoothly inside Docker containers!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: Docker fanboy alert&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  1. Create a Flask server
&lt;/h2&gt;

&lt;p&gt;I included comments in the code to make it more understandable, but if at any&lt;br&gt;
point you feel like something is unclear, &lt;a href="https://memgr.ph/discord" rel="noopener noreferrer"&gt;join our Discord&lt;br&gt;
Server&lt;/a&gt; and share your thoughts. First, create the&lt;br&gt;
file &lt;code&gt;app.py&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ArgumentParser&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;gqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Memgraph&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Logging enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Set the log level for werkzeug to WARNING because it will print out too much info otherwise
&lt;/span&gt;    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;werkzeug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WARNING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other than the imports, the first few lines focus on setting up the logging. No&lt;br&gt;
web application is complete without logging, so we will add the bare minimum and&lt;br&gt;
disable the pesky &lt;em&gt;werkzeug&lt;/em&gt; logger, which sometimes prints too much info.&lt;/p&gt;

&lt;p&gt;Now, let's create an argument parser. This will enable you to easily change the&lt;br&gt;
behavior of the app on startup using arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Parse the input arguments for the app
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Parse command line arguments.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Host address.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;App port.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--template-folder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public/template&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Flask templates.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--static-folder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Flask static files.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--path-to-input-file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;graph.cypherl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Graph input file.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--debug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;store_true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Web server in debug mode.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s time to create your server instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create the Flask server instance
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;template_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;template_folder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;static_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;static_folder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;static_url_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can finally create the view functions that will be invoked from the browser&lt;br&gt;
via HTTP requests. In layman's terms, the homepage is called by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Retrieve the home page for the app
&lt;/span&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing that’s left is to implement and call the &lt;code&gt;main()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Entrypoint for the app that will be executed first
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Code that should only be run once
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WERKZEUG_RUN_MAIN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The somewhat strange statement &lt;code&gt;os.environ.get("WERKZEUG_RUN_MAIN") == "true"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;will make sure that this code is only executed once. Confused? A problem arises&lt;br&gt;
when working with Flask in development mode because each code change triggers a&lt;br&gt;
reload of the server, which in turn could result in parts of your code executing&lt;br&gt;
multiple times (for example, like the main function).&lt;/p&gt;

&lt;p&gt;So, if you need to execute something only once in Flask at the beginning like&lt;br&gt;
loading data, this is the perfect place for it.&lt;/p&gt;

&lt;p&gt;The next step is to create the following files, which we will work on in the&lt;br&gt;
next tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt; in &lt;code&gt;public/template&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;index.js&lt;/code&gt; in &lt;code&gt;public/js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style.css&lt;/code&gt; in &lt;code&gt;public/css&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more file is needed and this one will specify all the Python dependencies&lt;br&gt;
that need to be installed. Create &lt;code&gt;requirements.txt&lt;/code&gt; with the following&lt;br&gt;
contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gqlalchemy==1.0.6
Flask==2.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your current project structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app
├── public
│  ├── css
│  │   └── style.css
│  ├── js
│  │   └── index.js
│  └── templates
│      └── index.html
├── app.py
└── requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Dockerize your application
&lt;/h2&gt;

&lt;p&gt;This is much simpler than you might think. Most often, you will need a&lt;br&gt;
Dockerfile in which you will specify how your Docker image should be created.&lt;br&gt;
Let's take a look at our &lt;code&gt;Dockerfile&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.9&lt;/span&gt;

&lt;span class="c"&gt;# Install CMake&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apt-get &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;cmake &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Install Python packages&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Copy the source code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; public /app/public&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; app.py /app/app.py&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Set the environment variables&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; FLASK_ENV=development&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; LC_ALL=C.UTF-8&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; LANG=C.UTF-8&lt;/span&gt;

&lt;span class="c"&gt;# Start the web application&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["python3", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line indicates that we are basing our image on a Linux image that has&lt;br&gt;
Python 3.9 preinstalled. The next step is to install CMake (which is needed for&lt;br&gt;
the Memgraph Python driver) with &lt;code&gt;RUN&lt;/code&gt; and the standard Linux installation&lt;br&gt;
command &lt;code&gt;apt-get ...&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;We copy the &lt;code&gt;requirements.txt&lt;/code&gt; file and install the Python packages with&lt;br&gt;
&lt;strong&gt;pip&lt;/strong&gt;. The source code also needs to be copied to the image in order for us to&lt;br&gt;
start the web application. The &lt;code&gt;ENTRYPOINT&lt;/code&gt; command is responsible for starting&lt;br&gt;
the desired process inside the container.&lt;/p&gt;

&lt;p&gt;But we are not finished with Docker yet. We need to create a&lt;br&gt;
&lt;code&gt;docker-compose.yml&lt;/code&gt; file that will tell Docker which containers to start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5000:5000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MEMGRAPH_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;memgraph&lt;/span&gt;
      &lt;span class="na"&gt;MEMGRAPH_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;7687"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;memgraph&lt;/span&gt;

  &lt;span class="na"&gt;memgraph&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memgraph/memgraph"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;7687:7687"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two services/containers in our app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt;: Uses the &lt;code&gt;Dockerfile&lt;/code&gt; to build a Docker image and run it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memgraph&lt;/strong&gt;: This is our database. Docker will automatically download the
image and start it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because we are supplying environment variables, let's load them in &lt;code&gt;app.py&lt;/code&gt;&lt;br&gt;
right after the imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEMGRAPH_HOST = os.getenv("MEMGRAPH_HOST", "memgraph")
MEMGRAPH_PORT = int(os.getenv("MEMGRAPH_PORT", "7687"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your current project structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app
├── public
│  ├── css
│  │   └── style.css
│  ├── js
│  │   └── index.js
│  └── templates
│      └── index.html
├── app.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can even start our app with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose build
docker-compose up
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Import the data into Memgraph
&lt;/h2&gt;

&lt;p&gt;This task will be done inside the &lt;code&gt;main()&lt;/code&gt; function because it only needs to be&lt;br&gt;
executed once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;memgraph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WERKZEUG_RUN_MAIN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;init_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;memgraph&lt;/span&gt;
        &lt;span class="n"&gt;memgraph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Memgraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MEMGRAPH_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;MEMGRAPH_PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;load_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path_to_input_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How do we import the data into Memgraph? I prepared a file with the Cypher&lt;br&gt;
queries that need to be executed in order to populate the database. You just&lt;br&gt;
need to download the file in your root directory and add the following&lt;br&gt;
&lt;code&gt;load_data()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_input_file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load data into the database.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;memgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop_database&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_input_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;memgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Data loading error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we clear everything in the database, and then we go over each line in the&lt;br&gt;
file &lt;code&gt;graph.cypherl&lt;/code&gt; and execute them. And that's it. Once we start the web&lt;br&gt;
application, Memgraph will import the dataset.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Query the database
&lt;/h2&gt;

&lt;p&gt;We will create a function that will execute a Cypher query and return the&lt;br&gt;
results. It returns the whole graph, but we will limit ourselves to 100 nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_and_fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;MATCH (n)-[]-(m)
                RETURN n as from, m AS to
                LIMIT 100;&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The view function &lt;code&gt;get_data()&lt;/code&gt; which fetches all the nodes and relationships&lt;br&gt;
from the database, filters out the most important information, and returns it in&lt;br&gt;
JSON format for visualization. To can the network load at a minimum, you will&lt;br&gt;
send a list with every node id (no other information about the nodes) and a list&lt;br&gt;
that specifies how they are connected to each other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/get-graph&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load everything from the database.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Sets for quickly checking if we have already added the node or edge
&lt;/span&gt;        &lt;span class="c1"&gt;# We don't want to send duplicates to the frontend
&lt;/span&gt;        &lt;span class="n"&gt;nodes_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;links_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;source_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;target_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="n"&gt;nodes_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;nodes_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;links_set&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;links_set&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;links_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes_set&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;links_set&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nodes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;links&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Data loading error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;As you can see, it’s very easy to connect to Memgraph and run graph algorithms,&lt;br&gt;
even from a web application. While this part of the tutorial focused on the&lt;br&gt;
backend, in the next one, we will talk about graph visualizations and the D3.js&lt;br&gt;
framework.&lt;/p&gt;

</description>
      <category>flask</category>
      <category>docker</category>
      <category>memgraph</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Visualize a Social Network in Python with a Graph Database: Flask + Docker + D3.js</title>
      <dc:creator>Memgraph</dc:creator>
      <pubDate>Wed, 19 Jul 2023 13:15:58 +0000</pubDate>
      <link>https://dev.to/memgraph/how-to-visualize-a-social-network-in-python-with-a-graph-database-flask-docker-d3js-1g15</link>
      <guid>https://dev.to/memgraph/how-to-visualize-a-social-network-in-python-with-a-graph-database-flask-docker-d3js-1g15</guid>
      <description>&lt;p&gt;When you think about a web application, a graph database doesn’t usually spring to mind. Instead, most people just take the familiar route of using an SQL database to store information. While this is perfectly acceptable for most use cases there are sometimes those that would see tremendous benefits by using a graph database.&lt;br&gt;
In this tutorial, I will show you how to make a basic web application using Flask that stores all of its information in a graph database. To be more precise we are using &lt;strong&gt;Memgraph DB&lt;/strong&gt;, an in-memory database that can easily handle a lot of information and perform read/write instructions quite quickly.&lt;br&gt;&lt;br&gt;&lt;br&gt;
Our use case is a &lt;strong&gt;Social Network Graph&lt;/strong&gt; (in the code referred to as &lt;strong&gt;SNG&lt;/strong&gt; for convenience) representing users and the connections between them. Usually, such a graph would contain millions of relationships and the algorithms that are performed on them don’t do well with data being stored in relational databases.&lt;br&gt;&lt;br&gt;&lt;br&gt;
In this tutorial, I will show you step by step how to build a simple Python web application from the bottom up so you get a basic understanding of the technologies that are used. You can also find all of the code &lt;a href="https://github.com/g-despot/sng-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you don't want to work on it as you go through the tutorial. If at any point in this tutorial you have a question or something is not working for you, feel free to post on &lt;a href="https://stackoverflow.com/questions/tagged/memgraphdb" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; with the tag &lt;code&gt;memgraphdb&lt;/code&gt;.&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
   &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S-33qubq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/9/9b/Social_Network_Analysis_Visualization.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-33qubq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/9/9b/Social_Network_Analysis_Visualization.png" alt="" width="800" height="596"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Because we are building a complete web application there is a number of tools that you will need to install before we begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://python-poetry.org/docs/" rel="noopener noreferrer"&gt;Poetry&lt;/a&gt;&lt;/strong&gt;: a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://flask.palletsprojects.com/en/1.1.x/quickstart/" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;&lt;/strong&gt;: a very powerful web framework that provides you with tools, libraries and technologies used in web development. A Flask application can be as small as a single web page or as complex as a management interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker and Compose&lt;/a&gt;&lt;/strong&gt;: an open platform for developing, shipping, and running applications. It enables us to separate our application from our infrastructure (host machine). If you are installing Docker on Windows, Compose will be already included. For Linux and macOS visit &lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;this site&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.memgraph.com/memgraph/quick-start" rel="noopener noreferrer"&gt;Memgraph DB&lt;/a&gt;&lt;/strong&gt;: a native fully distributed in-memory graph database built to handle real-time use-cases at enterprise scale. Follow the &lt;strong&gt;Docker Installation&lt;/strong&gt; instructions on the Quick Start page. While it's completely optional, I encourage you to also install &lt;strong&gt;&lt;a href="https://memgraph.com/product/lab" rel="noopener noreferrer"&gt;Memgraph Lab&lt;/a&gt;&lt;/strong&gt; so you can execute &lt;strong&gt;openCypher&lt;/strong&gt; queries on the database directly and see visualized results.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Creating the Project Structure and Handling Dependencies
&lt;/h2&gt;

&lt;p&gt;Sometimes standard packaging systems and dependency management in Python can be confusing for beginners so we decided to use Poetry.&lt;br&gt;&lt;br&gt;
To start building our project structure choose a working directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;poetry new sng-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should have a directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sng-demo
├── pyproject.toml
├── README.rst
├── sng_demo
│  └── __init__.py
└── tests
   ├── __init__.py
   └── test_poetry_demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this tutorial, we won’t use the testing functionalities so go on ahead and delete the directory &lt;code&gt;tests&lt;/code&gt; as well as the file &lt;code&gt;README.rst&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to add the dependencies for our project. Given that we are going to run the app inside a Docker container we don't need the dependencies installed locally, only inside the container. Copy the files &lt;a href="https://github.com/g-despot/sng-demo/blob/master/pyproject.toml" rel="noopener noreferrer"&gt;&lt;code&gt;project.toml&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/g-despot/sng-demo/blob/master/poetry.lock" rel="noopener noreferrer"&gt;&lt;code&gt;poetry.lock&lt;/code&gt;&lt;/a&gt; and place them in the root directory of the project. The only other thing we need to do about dependency management is to tell Docker how to run Poetry on startup so it can install/update all the necessary dependencies inside the container.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerizing an Application
&lt;/h2&gt;

&lt;p&gt;In the root directory of the project create two files, &lt;code&gt;Dockerfile&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt;. At the beginning of the &lt;code&gt;Dockerfile&lt;/code&gt;, we specify the Python version and instruct the container to install &lt;strong&gt;CMake&lt;/strong&gt;, &lt;strong&gt;poetry&lt;/strong&gt;, &lt;strong&gt;mgclient&lt;/strong&gt; and &lt;strong&gt;pymgclient&lt;/strong&gt;. Poetry is necessary to manage our dependencies inside the container while CMake and mgclient are required for pymgclient, the Python driver for &lt;strong&gt;Memgraph DB&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
You don’t have to focus too much on this part just copy the code to your &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.7&lt;/span&gt;

&lt;span class="c"&gt;#Install CMake&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apt-get &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;cmake

&lt;span class="c"&gt;#Install poetry&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; pip &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="${PATH}:/root/.poetry/bin"&lt;/span&gt;

&lt;span class="c"&gt;#Install mgclient&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git cmake make gcc g++ libssl-dev &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  git clone https://github.com/memgraph/mgclient.git /mgclient &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;cd &lt;/span&gt;mgclient &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  git checkout 5ae69ea4774e9b525a2be0c9fc25fb83490f13bb &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;mkdir &lt;/span&gt;build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;cd &lt;/span&gt;build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  cmake .. &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  make &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;#Install pymgclient&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/memgraph/pymgclient /pymgclient &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;cd &lt;/span&gt;pymgclient &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  python3 setup.py build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  python3 setup.py &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define the working directory with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; poetry.lock pyproject.toml /app/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second command will enable us to cache the project requirements and only reinstall them when &lt;code&gt;pyproject.toml&lt;/code&gt; or &lt;code&gt;poetry.lock&lt;/code&gt; are changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;poetry config virtualenvs.create &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  poetry &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; &lt;span class="nt"&gt;--no-ansi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don’t need to create a virtual environment because our application is already isolated by being in a Docker container. To disable it &lt;code&gt;virtualenvs.create&lt;/code&gt; needs to be set to false.&lt;br&gt;&lt;br&gt;
The second line in the command ensures that Poetry asks us no interactive questions while installing/updating dependencies and it makes the output more log friendly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 5000&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; [ "poetry", "run" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where we essentially create all the directories and files inside of our container. The &lt;code&gt;EXPOSE&lt;/code&gt; command informs Docker that the container listens on the specified network port at runtime.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Next, we need to create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. &lt;strong&gt;Compose&lt;/strong&gt; is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. For our project, we need two services. One is the web application (&lt;code&gt;sng_demo&lt;/code&gt;) and the other a database instance (&lt;code&gt;memgraph&lt;/code&gt;).&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If you followed the instructions on &lt;a href="https://docs.memgraph.com/memgraph/quick-start" rel="noopener noreferrer"&gt;how to setup Memgraph DB with Docker&lt;/a&gt; correctly you only need to add the following code to your &lt;code&gt;docker-compose.yml&lt;/code&gt; file to run the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;memgraph&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memgraph"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;7687:7687"&lt;/span&gt;
  &lt;span class="na"&gt;sng_demo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5000:5000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MG_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;memgraph&lt;/span&gt;
      &lt;span class="na"&gt;MG_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7687&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;memgraph&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it comes to the &lt;code&gt;ports&lt;/code&gt; key, there is an important distinction between the &lt;strong&gt;HOST_PORT&lt;/strong&gt; and the &lt;strong&gt;CONTAINER_PORT&lt;/strong&gt;. The first number in the key is the &lt;strong&gt;HOST_PORT&lt;/strong&gt; and it can be used to connect from your host machine to the service (for example with &lt;strong&gt;Memgraph Lab&lt;/strong&gt;). The second number specifies the &lt;strong&gt;CONTAINER_PORT&lt;/strong&gt; which is used for service-to-service communication. More precisely, our service &lt;code&gt;sng_db&lt;/code&gt; can use this port to access the service &lt;code&gt;memgraph&lt;/code&gt; and connect to the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;environment&lt;/code&gt; key contains &lt;code&gt;MG_HOST&lt;/code&gt; and &lt;code&gt;MG_PORT&lt;/code&gt; which represent environment variables in the service’s container. They store the &lt;code&gt;memgraph&lt;/code&gt; service address and port which are needed to establish a database connection.&lt;br&gt;
The &lt;code&gt;depends_on&lt;/code&gt; key is used to start services in dependency order because we need the database to start before the web application.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;build&lt;/code&gt; key allows us to tell Compose where to find the build instructions as well as the files and/or folders used during the build process. By using the &lt;code&gt;volumes&lt;/code&gt; key, we bypass the need to constantly restart our image to load new changes to it from the host machine.&lt;/p&gt;

&lt;p&gt;Finally, we have a dockerized project that utilizes Poetry! This approach is great for development because it enables us to run our project on completely different operating systems and environments without having to worry about compatibility issues.&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Web Development with Flask
&lt;/h2&gt;

&lt;p&gt;Flask is very simple to use so why not create a &lt;strong&gt;Hello World!&lt;/strong&gt; page to try out our Docker+Poetry setup.&lt;br&gt; &lt;br&gt;
In the project root directory create a file called &lt;code&gt;app.py&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/index&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we imported the Flask class and then created an instance of it. The &lt;code&gt;route()&lt;/code&gt; decorator tells Flask what URL should trigger our function.&lt;br&gt;
Now, we need to tell Docker how to run our app. This can be done by creating a simple script in the project root directory. Let’s call it &lt;code&gt;start.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app.py
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development
flask run &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting &lt;code&gt;FLASK_ENV&lt;/code&gt; to &lt;code&gt;development&lt;/code&gt; will enable the debug mode. This makes Flask use an interactive debugger and reloader.&lt;br&gt; &lt;br&gt;
Setting &lt;code&gt;FLASK_APP&lt;/code&gt; to &lt;code&gt;app.py&lt;/code&gt; specifies how to start the application.&lt;br&gt; &lt;br&gt;
We need to tell Docker when and how to run this script so put the following code in your &lt;code&gt;Dockerfile&lt;/code&gt; after the line &lt;code&gt;EXPOSE 5000&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; start.sh /&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /start.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;chmod +x&lt;/code&gt; makes the script executable by setting the right permission.&lt;br&gt; &lt;br&gt;
To execute the script, add the following command after the line &lt;code&gt;ENTRYPOINT [ "poetry", "run" ]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/start.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! Our first web page is ready so let’s start our app to make sure we don’t have any errors.&lt;br&gt; &lt;br&gt;
In the project root directory execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first build will take some time because Docker has to download and install a lot of dependencies.&lt;br&gt; &lt;br&gt;
After it finishes run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The URL of our web application is &lt;a href="http://localhost:5000/" rel="noopener noreferrer"&gt;http://localhost:5000/&lt;/a&gt;. When you open it there should be a message &lt;strong&gt;Hello World!&lt;/strong&gt; which means that the app is up and running.&lt;br&gt;&lt;br&gt;&lt;br&gt;
Now it’s time to create a more complex web page that will contain our Social Network Graph. In the project root directory create a folder called &lt;code&gt;templates&lt;/code&gt; and in it a file with the name &lt;code&gt;base.html&lt;/code&gt;. This will be our base HTML template for other pages. Copy the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1, shrink-to-fit=no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/static/css/style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://code.jquery.com/jquery-3.3.1.slim.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://d3js.org/d3.v4.min.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Social Network Graph Demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    {% block content %} {% endblock %}
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to create an HTML file for our actual landing site that utilizes this base file and an accompanying JavaScript file. Create the HTML file in the same location with the name &lt;code&gt;index.html&lt;/code&gt; and copy the following code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% extends 'base.html' %} {% block content %}
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Hello World!
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/js/index.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
{% endblock %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the project root directory create a folder called &lt;code&gt;static&lt;/code&gt; with one subfolder called &lt;code&gt;js&lt;/code&gt; and another called &lt;code&gt;css&lt;/code&gt;. The &lt;code&gt;js&lt;/code&gt; folder will contain all of the needed local JavaScript files while the &lt;code&gt;css&lt;/code&gt; folder will contain all the CSS stylesheets. In the &lt;code&gt;js&lt;/code&gt; folder create a file called &lt;code&gt;index.js&lt;/code&gt; and in the &lt;code&gt;css&lt;/code&gt; folder one called &lt;code&gt;style.css&lt;/code&gt;. Just leave them empty for now.&lt;br&gt;&lt;br&gt;&lt;br&gt;
If you want to find out more about web development with Flask I suggest you try out &lt;a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Your current project structure should like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sng-demo
├── sng_demo
│  └── __init__.py
├── templates
│  ├── base.html
│  └── index.html
├── static
│  ├── css
│  │  └── style.css
│  └── js
│     └── index.js
├── app.py
├── docker-compose.yml
├── Dockerfile
├── poetry.lock
├── pyproject.toml
└── start.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  The Data Model and Database Connection
&lt;/h2&gt;

&lt;p&gt;In the app directory &lt;code&gt;sng-demo&lt;/code&gt; create a folder called &lt;code&gt;database&lt;/code&gt;. This folder will contain all of the modules that we need to communicate with the database. You can find them &lt;a href="https://github.com/g-despot/sng-demo/tree/master/sng_demo/database" rel="noopener noreferrer"&gt;here&lt;/a&gt; and just copy their contents. They are closely related to the database driver and if you wish to examine them a bit more I suggest you look up the driver documentation &lt;a href="https://github.com/memgraph/pymgclient" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
In the app directory &lt;code&gt;sng-demo&lt;/code&gt; create the module &lt;code&gt;db_operations.py&lt;/code&gt;. This is where all the custom database related commands will be located.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;sng_demo&lt;/code&gt; directory should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sng_demo
├── __init__.py
├── db_operations.py
└── database
   ├── __init__.py
   ├── memgraph.py
   ├── connection.py
   └── models.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use a very simple data model that can be easily upgraded later on.&lt;br&gt;&lt;br&gt;
There is only one node with the label &lt;code&gt;User&lt;/code&gt; and each &lt;code&gt;User&lt;/code&gt; has two properties, a numerical &lt;code&gt;id&lt;/code&gt; and a string &lt;code&gt;name&lt;/code&gt;. Nodes are connected with edges of the type &lt;code&gt;FRIENDS&lt;/code&gt;:&lt;/p&gt;


&lt;p&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zAOgKMRI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/user.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zAOgKMRI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/user.png%3Fraw%3Dtrue" alt="" width="737" height="781"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;


&lt;p&gt;There are several methods to populate our database (&lt;a href="https://docs.memgraph.com/memgraph/how-to-guides-overview/import-data" rel="noopener noreferrer"&gt;more on that here&lt;/a&gt;) but we will be doing it manually by executing &lt;strong&gt;openCypher&lt;/strong&gt; queries so you can get a better understanding of how to communicate with the database. You will find all the necessary queries to populate the database in the files &lt;a href="https://github.com/g-despot/sng-demo/blob/master/resources/data_big.txt" rel="noopener noreferrer"&gt;&lt;code&gt;data_big.txt&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/g-despot/sng-demo/blob/master/resources/data_small.txt" rel="noopener noreferrer"&gt;&lt;code&gt;data_small.txt&lt;/code&gt;&lt;/a&gt;. The former just has a larger dataset than the latter.&lt;br&gt;&lt;br&gt;
In the project root directory create a folder called &lt;code&gt;resources&lt;/code&gt; and place the files in it. Now you can add an import method to your web application.&lt;br&gt;&lt;br&gt;
In the module &lt;code&gt;db_operations.py&lt;/code&gt; add the following import and method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MATCH (node) DETACH DELETE node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;populate_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method &lt;code&gt;clear()&lt;/code&gt; deletes any data that might have been left in the database before populating it.&lt;br&gt;&lt;br&gt;
The method &lt;code&gt;populate_database()&lt;/code&gt; reads all of the &lt;strong&gt;openCypher&lt;/strong&gt; queries in the specified file and executes them.&lt;br&gt; &lt;br&gt;
In the module &lt;code&gt;app.py&lt;/code&gt; change the imports and method &lt;code&gt;index()&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;make_response&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sng_demo.database&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Memgraph&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sng_demo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db_operations&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/index&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Memgraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;db_operations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;db_operations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;populate_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resources/data_small.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every time we refresh our index page the database is cleared and repopulated with new data. While this is not suitable for the production stage, it is highly useful during development because it will enable us to make changes in the data without having to restart the whole application or working directly on the database.&lt;br&gt;&lt;br&gt;
If you want to examine the graph before proceeding, I suggest you open &lt;strong&gt;Memgraph Lab&lt;/strong&gt; and run the query &lt;code&gt;MATCH (n1)-[e:FRIENDS]-(n2) RETURN n1,n2,e;&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The result should be:&lt;/p&gt;


&lt;p&gt;&lt;br&gt;
   &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1OoXhKMA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_lab.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1OoXhKMA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_lab.png%3Fraw%3Dtrue" alt="" width="800" height="389"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;br&gt;

&lt;p&gt;We also need a method in our app to fetch all the relevant data from the database when a client requests it.&lt;br&gt;&lt;br&gt;
Let’s call it &lt;code&gt;get_graph()&lt;/code&gt; and place it in the &lt;code&gt;db_operations.py&lt;/code&gt; module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MATCH (n1)-[e:FRIENDS]-(n2) RETURN n1,n2,e;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
   &lt;span class="n"&gt;relationships&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_and_fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="n"&gt;link_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="n"&gt;node_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="n"&gt;added_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;relationships&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
       &lt;span class="n"&gt;link_objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;n1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;added_nodes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
           &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
           &lt;span class="n"&gt;node_objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;added_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;n2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;added_nodes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
           &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
           &lt;span class="n"&gt;node_objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;added_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;links&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link_objects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nodes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node_objects&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to execute the &lt;strong&gt;openCypher&lt;/strong&gt; query &lt;code&gt;MATCH (n1)-[e:FRIENDS]-(n2) RETURN n1,n2,e;&lt;/code&gt; and return its results from the database. These results will contain all the edges in the graph as well as all the nodes that are connected to those edges. Nodes that don't have connections will not be returned and that's ok for now.&lt;br&gt;&lt;br&gt;&lt;br&gt;
The results (the object &lt;code&gt;relationships&lt;/code&gt;) are in the form of a generator which we can iterate over and access its contents by using the node/edge names specified in our initial query (&lt;code&gt;n1&lt;/code&gt;,&lt;code&gt;n2&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt;).&lt;br&gt;&lt;br&gt;
We also need to check if a node has already been appended to the &lt;code&gt;node_objects&lt;/code&gt; list because multiple edges can contain (point to or from) the same node. All of the objects are stored in key-value pairs suitable for later JSON conversion.&lt;br&gt;&lt;br&gt;
The final result is a JSON object containing: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;links&lt;/code&gt;: all the relationships that are in the graph as pairs of &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;target&lt;/code&gt; id properties,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nodes&lt;/code&gt;: all the nodes from the graph that form relationships with other nodes. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your &lt;code&gt;app.py&lt;/code&gt; module add the following method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/get-graph&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Memgraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_operations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is responsible for responding to POST requests from the client. It returns the graph data that we fetched from the server in the previous method.&lt;br&gt;&lt;br&gt;&lt;br&gt;
Now let's do something with this data! Copy the contents for your &lt;code&gt;index.js&lt;/code&gt; file &lt;a href="https://github.com/g-despot/sng-demo/blob/master/static/js/index.js" rel="noopener noreferrer"&gt;from here&lt;/a&gt;&lt;br&gt;
and the &lt;code&gt;style.css&lt;/code&gt; file &lt;a href="https://github.com/g-despot/sng-demo/blob/master/static/css/style.css" rel="noopener noreferrer"&gt;from here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
We also need to add the actual SVG graphic to our page so change the &lt;code&gt;index.html&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{% extends 'base.html' %} {% block content %}
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border rounded mt-3"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"960"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-color:white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/js/index.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
{% endblock %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won't go into much detail about how to use &lt;strong&gt;D3.js&lt;/strong&gt; so if you want to find out more I encourage you to visit &lt;a href="https://d3js.org/" rel="noopener noreferrer"&gt;their website&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;br&gt;
In short, we fetch all the nodes and edges from the database and add them to an SVG element. The visual representation of the graph is made by simulating how physical forces act on particles (charge and gravity). You can drag and drop the nodes, hover over them to see the value of their name property, zoom in and out of the graph and move the SVG graphic.&lt;br&gt;&lt;br&gt;&lt;/p&gt;


&lt;p&gt;&lt;br&gt;
   &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2yNGLPYM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_d3.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2yNGLPYM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_d3.png%3Fraw%3Dtrue" alt="" width="800" height="456"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;br&gt;
&lt;h2&gt;
  
  
  Additional Functionalities
&lt;/h2&gt;

&lt;p&gt;Go ahead and copy the file &lt;a href="https://github.com/g-despot/sng-demo/blob/master/static/js/query.js" rel="noopener noreferrer"&gt;&lt;code&gt;query.js&lt;/code&gt;&lt;/a&gt; to the directory &lt;code&gt;static/js&lt;/code&gt; and &lt;a href="https://github.com/g-despot/sng-demo/blob/master/templates/query.html" rel="noopener noreferrer"&gt;&lt;code&gt;query.html&lt;/code&gt;&lt;/a&gt; to the directory &lt;code&gt;templates&lt;/code&gt;. You can find the updated &lt;code&gt;base.html&lt;/code&gt; file &lt;a href="https://github.com/g-despot/sng-demo/blob/master/templates/base.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Copy the necessary methods from the &lt;a href="https://github.com/g-despot/sng-demo/blob/master/sng_demo/db_operations.py" rel="noopener noreferrer"&gt;db_operations.py&lt;/a&gt; module and &lt;a href="https://github.com/g-despot/sng-demo/blob/master/app.py" rel="noopener noreferrer"&gt;app.py&lt;/a&gt; module.&lt;br&gt;&lt;br&gt;
After you made the changes, just open &lt;a href="http://localhost:5000/query/" rel="noopener noreferrer"&gt;http://localhost:5000/query/&lt;/a&gt; and see the results.&lt;br&gt;&lt;br&gt;
This page will make your life easier if you want to debug the data being fetched from the server. It returns all the nodes or edges and shows them in a JSON highlighted format.&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0aqG7iV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_query.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0aqG7iV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_query.png%3Fraw%3Dtrue" alt="" width="800" height="478"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;

&lt;p&gt;Your current project structure should like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sng-demo
├── resources
│  ├── data_big.py
│  └── data_small.txt
├── sng_demo
│  ├── __init__.py
│  ├── db_operations.py
│  └── database
│     ├── __init__.py
│     ├── memgraph.py
│     ├── connection.py
│     └── models.py
├── templates
│  ├── base.html
│  ├── index.html
│  └── query.html
├── static
│   ├── css
│   │  └── style.css
│   └── js
│      ├── index.js
│      └── query.js
├── app.py
├── docker-compose.yml
├── Dockerfile
├── poetry.lock
├── pyproject.toml
└── start.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;


&lt;p&gt;Even though graph databases have been around for a long time, they are still not considered a mainstream tool in software development. &lt;strong&gt;Relational database-management systems&lt;/strong&gt; model data as a set of predetermined structures. Complex joins and self-joins are necessary when the dataset becomes too inter-related. Modern datasets require technically complex queries which are often very inefficient in real-time scenarios.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Graph databases&lt;/strong&gt; offer powerful data modelling and analysis capabilities for many real-world problems such as social networks, business relationships, dependencies, shipping, logistics... and they have been adopted by many of the worlds leading tech companies. With this tutorial, I hope to shed some light on how easy it is to integrate a graph database in your development process and I encourage you to try it out yourself.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
As I said at the beginning, feel free to ask us any questions about this tutorial or Memgraph in general on &lt;a href="https://stackoverflow.com/questions/tagged/memgraphdb" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; with the tag &lt;code&gt;memgraphdb&lt;/code&gt; or on our &lt;a href="https://discord.gg/memgraph" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt;. &lt;strong&gt;Good luck with your coding!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;
   &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tAReKrvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_demo_screenshot.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tAReKrvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/g-despot/images/blob/master/sng_demo_screenshot.png%3Fraw%3Dtrue" alt="" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;&lt;br&gt;
&lt;br&gt;

</description>
      <category>flask</category>
      <category>docker</category>
      <category>d3js</category>
      <category>memgraph</category>
    </item>
  </channel>
</rss>
