<?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: Ayaka Hara</title>
    <description>The latest articles on DEV Community by Ayaka Hara (@aykhara).</description>
    <link>https://dev.to/aykhara</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%2Fuser%2Fprofile_image%2F619368%2Fc81c45b3-9f29-4936-b90f-418b97af6291.jpg</url>
      <title>DEV Community: Ayaka Hara</title>
      <link>https://dev.to/aykhara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aykhara"/>
    <language>en</language>
    <item>
      <title>How to Deploy a PDF Chatbot as a REST Endpoint and Test with Postman</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Thu, 25 Jan 2024 00:39:11 +0000</pubDate>
      <link>https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3</link>
      <guid>https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3</guid>
      <description>&lt;p&gt;Utilizing Azure AI Studio's Prompt Flow, we were able to easily implement a chatbot that answers questions about PDF documents. Furthermore, we conducted an evaluation of this chatbot to verify its accuracy. In this blog post, we will take you through the next step: moving beyond just testing the chatbot within Azure AI Studio's chat feature. We will demonstrate how to deploy this chatbot as a REST endpoint and test it using Postman, a popular tool for API development and testing by developers and test engineers.&lt;/p&gt;




&lt;p&gt;This post is a part of a series that serves as a step-by-step guide to developing a chatbot with RAG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc"&gt;How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure AI Studio's Prompt Flow&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56"&gt;How to Evaluate a PDF Chatbot Response with Prompt Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3"&gt;How to Deploy a PDF Chatbot as a REST Endpoint and Test with Postman&lt;/a&gt; &lt;strong&gt;← YOU ARE HERE!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
1. Modify a flow

&lt;ul&gt;
&lt;li&gt;1-1. Replace with vector db lookup&lt;/li&gt;
&lt;li&gt;1-2. Delete an unnecessary node&lt;/li&gt;
&lt;li&gt;1-3. Change the value of search result node&lt;/li&gt;
&lt;li&gt;1-4. Try chat&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
2. Deploy a flow

&lt;ul&gt;
&lt;li&gt;2-1. Deploy a flow from Prompt Flow tab&lt;/li&gt;
&lt;li&gt;2-2. Test the deployed endpoint&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
3. Test the endpoint with Postman

&lt;ul&gt;
&lt;li&gt;3-1. Copy Rest endpoint and Primary key&lt;/li&gt;
&lt;li&gt;3-2. Configure on Postman&lt;/li&gt;
&lt;li&gt;3-3. Test the endpoint&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Complete to create a flow (see &lt;a href="https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc"&gt;How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure Prompt Flow&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Download &lt;a href="https://www.postman.com/downloads/"&gt;Postman&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Optional : Complete to evaluate a flow (see &lt;a href="https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56"&gt;How to Evaluate a PDF Chatbot Response with Prompt Flow&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Modify a flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1-1. Replace with vector db lookup
&lt;/h3&gt;

&lt;p&gt;Need to replace the "index lookup tool" with "vector db lookup".&lt;br&gt;
Add "Vector DB Lookup" from More tools.&lt;br&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%2Ffncv6z1pppevintq3r0s.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%2Ffncv6z1pppevintq3r0s.png" alt="Image description" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, enter a node name (e.g. search) and add it to the flow&lt;br&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%2Frzzm5qufytsy8o478gda.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%2Frzzm5qufytsy8o478gda.png" alt="Image description" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, input values for the node and Save the change.&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%2F8qu31vm328c4bgba2fmw.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%2F8qu31vm328c4bgba2fmw.png" alt="Image description" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to know where these information come from, you can check them in Azure AI Search on Azure portal and navigate to indexes as below.&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%2Fj9plihf4omcrynx28uzf.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%2Fj9plihf4omcrynx28uzf.png" alt="Image description" width="800" height="505"&gt;&lt;/a&gt;&lt;br&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%2F400buqxl41rhd65b4kgy.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%2F400buqxl41rhd65b4kgy.png" alt="Image description" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the "Vector DB Lookup" node your graph will look like the screenshot below.&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%2Fvk5fyhj3jzcxe4zhs3x6.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%2Fvk5fyhj3jzcxe4zhs3x6.png" alt="Image description" width="496" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-2. Delete an unnecessary node
&lt;/h3&gt;

&lt;p&gt;Delete the "Vector Index Lookup - search_question_from_indexed_docs" and Save the change&lt;br&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%2F1nv0i1w1tbukii9ak0ir.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%2F1nv0i1w1tbukii9ak0ir.png" alt="Image description" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-3. Change the value of search result node
&lt;/h3&gt;

&lt;p&gt;Change the value of search_result to "$(search.output)" in generate_prompt_context node and Save the change&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%2F94k9eeo7e0ktoh1ekwgq.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%2F94k9eeo7e0ktoh1ekwgq.png" alt="Image description" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After completing all the steps to replace the "index lookup tool" with "vector db lookup" your graph will look like the screenshot below.&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%2Fqxbvurpzxe9b2edyiq1s.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%2Fqxbvurpzxe9b2edyiq1s.png" alt="Image description" width="382" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-4. Try chat
&lt;/h3&gt;

&lt;p&gt;Try the chat with your PDFs to make sure if it works as expected.&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%2Fjt6xpa4zfqvp09uc5xe5.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%2Fjt6xpa4zfqvp09uc5xe5.png" alt="Image description" width="472" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Deploy a flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2-1. Deploy a flow from Prompt Flow tab
&lt;/h3&gt;

&lt;p&gt;Click "Deploy",&lt;br&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%2Fsa7jy87u1y9buklnh57d.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%2Fsa7jy87u1y9buklnh57d.png" alt="Image description" width="800" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and change basic settings if you wish.&lt;br&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%2F183fwqqk6c7b3w7d7si3.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%2F183fwqqk6c7b3w7d7si3.png" alt="Image description" width="800" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review the deployment settings and Create it.&lt;br&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%2Fo6lr08zr7p95oo7ko59p.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%2Fo6lr08zr7p95oo7ko59p.png" alt="Image description" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will take around 10 minutes to complete the deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2-2. Test the deployed endpoint
&lt;/h3&gt;

&lt;p&gt;Move to Deployments tab and select the deployed endpoint,&lt;br&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%2Fid2ezbc2u56x5xdyrmc0.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%2Fid2ezbc2u56x5xdyrmc0.png" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then test the endpoint.&lt;br&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%2F3vkara4xdsxuzvbdkfxz.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%2F3vkara4xdsxuzvbdkfxz.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Test the endpoint with Postman
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3-1. Copy Rest endpoint and Primary key
&lt;/h3&gt;

&lt;p&gt;Copy REST endpoint and Primary key from Consume tab&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%2Fobqbvfgb11x0yj0tth1k.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%2Fobqbvfgb11x0yj0tth1k.png" alt="Image description" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3-2. Configure on Postman
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;POST : REST endpoint&lt;/li&gt;
&lt;li&gt;Headers&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;KEY&lt;/th&gt;
&lt;th&gt;VALUE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Bearer {Primary key}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;application/json&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Body : raw (json)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"who are you"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"chat_history"&lt;/span&gt;&lt;span class="p"&gt;:[]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Foco6665iznzmzxbvxox4.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%2Foco6665iznzmzxbvxox4.png" alt="Image description" width="800" height="562"&gt;&lt;/a&gt;&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%2Fd5pbhqy9hm8s9vqgiwso.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%2Fd5pbhqy9hm8s9vqgiwso.png" alt="Image description" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3-3. Test the endpoint
&lt;/h3&gt;

&lt;p&gt;Click "Send" and get the response!&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%2Fw00er4yse4evn6znoduz.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%2Fw00er4yse4evn6znoduz.png" alt="Image description" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this blog, we have explored how to deploy the chatbot, implemented using Azure AI Studio's Prompt Flow, as a REST endpoint and how to test it using Postman. Next, we plan to introduce a method for implementing a simple application that utilizes the REST endpoint we've just deployed. &lt;/p&gt;

</description>
      <category>azure</category>
      <category>openai</category>
      <category>rag</category>
    </item>
    <item>
      <title>How to Evaluate a PDF Chatbot Response with Prompt Flow</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Thu, 25 Jan 2024 00:38:37 +0000</pubDate>
      <link>https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56</link>
      <guid>https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56</guid>
      <description>&lt;p&gt;Using Azure AI Studio's Prompt Flow, we've managed to easily implement a chatbot that can answer questions about PDF documents. However, it's crucial to verify whether this chatbot is accurately extracting and providing answers from the PDFs. In this blog, as the next step, we'll delve into preparing test data and conducting an evaluation of the chatbot. This process will help us determine the accuracy of its responses, ensuring that the chatbot is effectively serving its intended purpose.&lt;/p&gt;




&lt;p&gt;This post is a part of a series that serves as a step-by-step guide to developing a chatbot with RAG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc"&gt;How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure AI Studio's Prompt Flow&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56"&gt;How to Evaluate a PDF Chatbot Response with Prompt Flow&lt;/a&gt; &lt;strong&gt;← YOU ARE HERE!&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3"&gt;How to Deploy a PDF Chatbot as a REST Endpoint and Test with Postman&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;1. Prepare test data&lt;/li&gt;
&lt;li&gt;2. Add test data on Azure AI Studio&lt;/li&gt;
&lt;li&gt;3. Evaluate a flow&lt;/li&gt;
&lt;li&gt;4. Check the evaluation result&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Complete to create a flow (see &lt;a href="https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc"&gt;How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure Prompt Flow&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prepare test data
&lt;/h2&gt;

&lt;p&gt;Prepare test data based on the PDF data used to create chatbot. Here, as an example, we will prepare a csv file with the expected correct answers to the questions to &lt;a href="https://github.com/Azure-Samples/azure-search-openai-demo/tree/main/data" rel="noopener noreferrer"&gt;azure-search-openai-demo&lt;/a&gt; sample data.&lt;/p&gt;

&lt;p&gt;Ideally, it would be desirable to prepare between 50 to 100 test data samples, and if possible, up to 200. However, for this trial, we will start by preparing 5 samples.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: you should choose an appropriate format when saving the file, as Japanese and other characters may be garbled.&lt;br&gt;
file format : e.g. CSV UTF-8&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0iw0ogefjcc885zlkak.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0iw0ogefjcc885zlkak.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;question,chat_history,answer,context&lt;br&gt;
What is PerksPlus?,[],It's the ultimate benefits program designed to support the health nd wellness of employees.,&lt;br&gt;
What are not covered under the PErksPlus?,[],"Non-fitness related expenses, Medical treatments and procedures, Travel expenses (unless related to a fitness program), and Food and supplements.",&lt;br&gt;
What is Contoso Electronics?,[],"It's a leader in the aerospace industry, providing advanced electronic components for both commercial and military aircraft.",&lt;br&gt;
What is Northwind Health Plus?,[],"It's a comprehensive plan that provides comprehensive coverage for medical, vision, and dental services.",&lt;br&gt;
How much does it cost for one employee to enroll in Northwind Health Plus?,[],$55.00,&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Add test data on Azure AI Studio
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h2&gt;


&lt;p&gt;Before starting the evaluation, test data should be registered on Azure AI Studio.&lt;/p&gt;

&lt;p&gt;Move to "Data" tab and click "New 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kgyy2j0un5b3d4848tw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kgyy2j0un5b3d4848tw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, select "Upload files/folders" and upload the test data from local.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjbmyil87khldcz0aamz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjbmyil87khldcz0aamz.png" alt="Image description"&gt;&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3thbpz79kk13ozsr91zh.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3thbpz79kk13ozsr91zh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, put the data name and finally create 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx4iqxf5q6h33tuglx7n.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx4iqxf5q6h33tuglx7n.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your test data is correctly uploaded you can see the data details like the following screenshot.&lt;br&gt;
&lt;a href="https://media.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%2Fai537gtekz03b4fgjcj0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fai537gtekz03b4fgjcj0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Evaluate a flow
&lt;/h2&gt;

&lt;p&gt;Now, we're ready to start evaluating a flow.&lt;/p&gt;

&lt;p&gt;Move to "Evaluation" tab and click "New evaluation".&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3m1n3j66zcsb9f4ic94.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3m1n3j66zcsb9f4ic94.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Put an evaluation name and select "Question and answering pairs" as kind of evaluation scenario this time.&lt;br&gt;
&lt;a href="https://media.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%2Floqawbkw5832rekux0jj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floqawbkw5832rekux0jj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, select a flow which you want to evaluate. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far3zka6qijo15i35j2al.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far3zka6qijo15i35j2al.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the metrics, for instance, Groundedness, Relevance, Coherence, and GPT similarity.&lt;br&gt;
Please refer to more details of metrics: &lt;a href="https://learn.microsoft.com/en-us/azure/machine-learning/prompt-flow/how-to-bulk-test-evaluate-flow?view=azureml-api-2#understand-the-built-in-evaluation-metrics" rel="noopener noreferrer"&gt;built-in evaluation metrics&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh31iuxfg0z78lorem72b.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh31iuxfg0z78lorem72b.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select configuration test data to evaluate. Since we have already registered test data, select "Use existing dataset".&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmb9zipxxex7rhyg04d5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmb9zipxxex7rhyg04d5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change dataset mapping. Answer should be what comes out from the flow, so configure answer and ground_truth as follows.&lt;br&gt;
&lt;a href="https://media.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%2Fv1e806rfb1noppp5ffhn.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1e806rfb1noppp5ffhn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, review the evaluation configuration and submit it.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprtpuelpu42kkdqp42ey.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprtpuelpu42kkdqp42ey.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check the evaluation result
&lt;/h2&gt;

&lt;p&gt;Once evaluation has been done, you can find the completed sign like below.&lt;br&gt;
&lt;a href="https://media.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%2F7t6bto242hnhcex1sx2v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7t6bto242hnhcex1sx2v.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are metrics scores and detailed metrics result.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metrics scores

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coherence&lt;/strong&gt; : The measure evaluates the coherence and naturalness of the generated text. It measures how well the language model can produce output that flows smoothly, reads naturally, and resembles human-like language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similarity&lt;/strong&gt; : Similarity is a measure that quantifies the similarity between a ground truth sentence (or document) and the prediction sentence generated by an AI model. It is calculated by first computing sentence-level embeddings using the embeddings API for both the ground truth and the model's prediction. These embeddings represent high-dimensional vector representations of the sentences, capturing their semantic meaning and context.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The Similarity bar graph illustrates that one of the five test data had the lowest score, 1.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19lv0zgo9sa2397t1bi4.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19lv0zgo9sa2397t1bi4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further review of the delayed metrics results shows that a speculative price of "$55.00" is obtained for the question "How much does it cost for one employee to enroll in Northwind Health Plus? However, no such response was received.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eg3l3qgrwbfmj9q8fwi.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eg3l3qgrwbfmj9q8fwi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The actual PDF data showed that this price was in a table, from which it could not be successfully output as a response.　(Ref : &lt;a href="https://github.com/Azure-Samples/azure-search-openai-demo/blob/main/data/Benefit_Options.pdf" rel="noopener noreferrer"&gt;Benefit_Options.pdf&lt;/a&gt;)&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7xedzg3z1x51e9gf9by.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7xedzg3z1x51e9gf9by.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this blog post, we've shared how to prepare test data and conduct an evaluation of the chatbot, a necessary step to confirm the accuracy of its answers. Having established this, our next focus will be on deploying the chatbot, developed using Azure AI Studio's Prompt Flow, as a REST endpoint. Next in our series, &lt;a href="https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3"&gt;"How to Deploy a PDF Chatbot as a REST Endpoint and Test with Postman"&lt;/a&gt;, we will then explore how to test this deployment using Postman. &lt;/p&gt;

</description>
      <category>azure</category>
      <category>openai</category>
      <category>rag</category>
    </item>
    <item>
      <title>How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure AI Studio's Prompt Flow</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Thu, 25 Jan 2024 00:38:20 +0000</pubDate>
      <link>https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc</link>
      <guid>https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc</guid>
      <description>&lt;p&gt;Developing a chatbot that can answer questions about PDF documents might seem like a task requiring extensive time and effort. However, with Azure AI Studio's Prompt Flow, the implementation becomes surprisingly straightforward. In this blog, we will delve into the process of creating a chatbot with RAG (Retrieval-Augmented Generation) that can respond to queries related to sample PDF data. We’ll also guide you through testing this chatbot using the chat feature in Azure AI Studio.&lt;/p&gt;




&lt;p&gt;This post is a part of a series that serves as a step-by-step guide to developing a chatbot with RAG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-easily-build-a-pdf-chatbot-with-rag-retrieval-augmented-generation-using-azure-ai-studios-prompt-flow-boc"&gt;How to Easily Build a PDF Chatbot with RAG (Retrieval-Augmented Generation) Using Azure AI Studio's Prompt Flow&lt;/a&gt; &lt;strong&gt;← YOU ARE HERE!&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56"&gt;How to Evaluate a PDF Chatbot Response with Prompt Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3&lt;/strong&gt; : &lt;a href="https://dev.to/aykhara/how-to-deploy-a-pdf-chatbot-as-a-rest-endpoint-and-test-with-postman-4jp3"&gt;How to Deploy a PDF Chatbot as a REST Endpoint and Test with Postman&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
1. Create a project on Azure AI Studio

&lt;ul&gt;
&lt;li&gt;1-1. Build your own copilot&lt;/li&gt;
&lt;li&gt;1-2. Configure project details&lt;/li&gt;
&lt;li&gt;1-3. Create an Azure AI resource for your projects&lt;/li&gt;
&lt;li&gt;1-4. Review and create a project&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
2. Deploy Azure OpenAI models

&lt;ul&gt;
&lt;li&gt;2-1. Create a new deployment&lt;/li&gt;
&lt;li&gt;2-2. Select a model&lt;/li&gt;
&lt;li&gt;2-3. Deploy model&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
3. Create an index on Azure AI Search

&lt;ul&gt;
&lt;li&gt;3-1. Select your dataset&lt;/li&gt;
&lt;li&gt;3-2. Configure index storage&lt;/li&gt;
&lt;li&gt;3-3. Configure search settings&lt;/li&gt;
&lt;li&gt;3-4. Configure index settings&lt;/li&gt;
&lt;li&gt;3-5. Review and create an index&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
4. Configure Prompt Flow

&lt;ul&gt;
&lt;li&gt;4-1. Create runtime&lt;/li&gt;
&lt;li&gt;4-2. Configure parameters in each node&lt;/li&gt;
&lt;li&gt;4-3. Save all configuration changes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;5. Try Chat!&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Prepare PDF data
As a demo I'm going to use sample data from &lt;a href="https://github.com/Azure-Samples/azure-search-openai-demo/tree/main/data"&gt;azure-search-openai-demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create Azure AI Search&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Create a project on Azure AI Studio
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1-1. Build your own copilot
&lt;/h3&gt;

&lt;p&gt;Access to &lt;a href="//ai.azure.com"&gt;ai.azure.com&lt;/a&gt; and make sure that the right directory (subscription) is selected.&lt;br&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%2F2c6j0xq3m9sawov79qla.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%2F2c6j0xq3m9sawov79qla.png" alt="Image description" width="472" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select "Build your own copilot".&lt;br&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%2Fg57n9vw4rnjqy6yayq8j.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%2Fg57n9vw4rnjqy6yayq8j.png" alt="Image description" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, click "Create a new project".&lt;br&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%2Fmtbwhdbhbtp6f7621443.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%2Fmtbwhdbhbtp6f7621443.png" alt="Image description" width="705" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-2. Configure project details
&lt;/h3&gt;

&lt;p&gt;Input project name and select "Create a new resource", then click next.&lt;br&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%2Flh9fp5l8rgd0ga7oqp3a.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%2Flh9fp5l8rgd0ga7oqp3a.png" alt="Image description" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-3. Create an Azure AI resource for your projects
&lt;/h3&gt;

&lt;p&gt;Input resource name(Your Azure AI resource name must be different from your project name) and select an appropriate Azure location, then next.&lt;br&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%2F4yf929uvefxf67srflci.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%2F4yf929uvefxf67srflci.png" alt="Image description" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1-4. Review and create a project
&lt;/h3&gt;

&lt;p&gt;Click "Create a project" in Review and finish pane&lt;br&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%2F4jww37zmt0dhrikidh5b.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%2F4jww37zmt0dhrikidh5b.png" alt="Image description" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will take around 2 minutes to deploy all required resources to Azure.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Deploy Azure OpenAI models
&lt;/h2&gt;

&lt;p&gt;Once deploying all resources to Azure, you will automatically navigate to Playground in Azure AI Studio.&lt;br&gt;
At the same time, you will find the information message "No deployment exists: You need a deployment to work in the playground. Navigate to the Deployment page to create a deployment." Please click the link "Deployment page".&lt;br&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%2F01yk5du95lx3eghsw5ck.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%2F01yk5du95lx3eghsw5ck.png" alt="Image description" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need at least two models including one for embedding.&lt;/p&gt;

&lt;h3&gt;
  
  
  2-1. Create a new deployment
&lt;/h3&gt;

&lt;p&gt;Move to "Deployment" pane and click "Create".&lt;/p&gt;

&lt;h3&gt;
  
  
  2-2. Select a model
&lt;/h3&gt;

&lt;p&gt;Select a model:text-embedding-ada-002, then Confirm&lt;br&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%2Foaxcxuygoxbvmo1397qw.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%2Foaxcxuygoxbvmo1397qw.png" alt="Image description" width="714" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2-3. Deploy model
&lt;/h3&gt;

&lt;p&gt;Finally deploy a selected model.&lt;br&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%2Fb80o8dptxm9tkuom4dfm.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%2Fb80o8dptxm9tkuom4dfm.png" alt="Image description" width="671" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat 2-1 to 2-3 above for other model (e.g. gpt-35-turbo) as well.&lt;/p&gt;

&lt;p&gt;Once done with deploying models, they are listed in the Deployment pane.&lt;br&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%2Fwzvbwt62xlo72qkhus4b.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%2Fwzvbwt62xlo72qkhus4b.png" alt="Image description" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create an index on Azure AI Search
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3-1. Select your dataset
&lt;/h3&gt;

&lt;p&gt;Select "Upload files/folders" as Data source,&lt;br&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%2Fpazmmozgfkf4srmr9vbt.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%2Fpazmmozgfkf4srmr9vbt.png" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
and then click "Upload" &amp;gt; "Upload files"&lt;br&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%2Flrgp0yb1z6ak3lgetooc.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%2Flrgp0yb1z6ak3lgetooc.png" alt="Image description" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3-2. Configure index storage
&lt;/h3&gt;

&lt;p&gt;Select the following settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Connect other Azure AI Search resource"&lt;/li&gt;
&lt;li&gt;Azure subscription which you deployed the Azure AI Search on&lt;/li&gt;
&lt;li&gt;Azure AI Search service which you deployed already.
&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%2Ffgnfwlfgq0pa1udwd6yj.png" alt="Image description" width="800" height="541"&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3-3. Configure search settings
&lt;/h3&gt;

&lt;p&gt;Confirm the acknowledgement&lt;br&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%2F30y9hum7moe0w4ljjaam.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%2F30y9hum7moe0w4ljjaam.png" alt="Image description" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3-4. Configure index settings
&lt;/h3&gt;

&lt;p&gt;Insert index name and select virtual machine* (e.g. auto select) &lt;br&gt;
*Selected virtual machine will be used to run indexing jobs.&lt;br&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%2Fsvn01ien74ynlyjszfzk.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%2Fsvn01ien74ynlyjszfzk.png" alt="Image description" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3-5. Review and create an index
&lt;/h3&gt;

&lt;p&gt;Finally click "Create"&lt;br&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%2Fw6reux87275kd1ed7bnl.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%2Fw6reux87275kd1ed7bnl.png" alt="Image description" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will take around 10 minutes to get done with all jobs.&lt;br&gt;
If you want to know what is happening behind, "job details" navigates you to Azure ML Studio for more details.&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%2Fptq1fh8qw5h3t6u3qlo6.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%2Fptq1fh8qw5h3t6u3qlo6.png" alt="Image description" width="800" height="362"&gt;&lt;/a&gt;&lt;br&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%2Fsokz5qwungsy99luh2wy.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%2Fsokz5qwungsy99luh2wy.png" alt="Image description" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once all jobs are completed you can find the index with "ready" sign.&lt;br&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%2Fyztzltuacfosh7us920b.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%2Fyztzltuacfosh7us920b.png" alt="Image description" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configure Prompt Flow
&lt;/h2&gt;

&lt;p&gt;If you move to Prompt flow pane you can find "(your-index-name)-sample-flow" in the flow list.&lt;br&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%2Fa04d8z4kcagcp32puqqf.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%2Fa04d8z4kcagcp32puqqf.png" alt="Image description" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you select the flow you may notice that the basic flow is already prepared. However, there are still some manual configuration required.&lt;br&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%2Fod5j71cdv65d0cgka86x.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%2Fod5j71cdv65d0cgka86x.png" alt="Image description" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4-1. Create runtime
&lt;/h3&gt;

&lt;p&gt;Create runtime by simply selecting "automatic runtime start".&lt;br&gt;
It will take 5 minutes or so.&lt;br&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%2F71e9aru1x6ewwftfp8yo.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%2F71e9aru1x6ewwftfp8yo.png" alt="Image description" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4-2. Configure parameters in each node
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;modify_query_with_history&lt;/strong&gt; : Select deployment name and set max token (e.g. 1000), then click "Validate and purse input"&lt;br&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%2F0i5a27llhk8j4h6pqew5.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%2F0i5a27llhk8j4h6pqew5.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;embed_the_question&lt;/strong&gt; : Click "Validate and purse input"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note : Perhaps a deployment name will be removed due to some reasons after clicking validate button. Please make sure that the right deployment name for embedding is set.&lt;/p&gt;
&lt;/blockquote&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%2Fne03d3ixgba7887udxma.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%2Fne03d3ixgba7887udxma.png" alt="Image description" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;search_question_from_indexed_docs&lt;/strong&gt; : Click "Validate and purse input"&lt;br&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%2Fa75mh7vddr20jyx532ab.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%2Fa75mh7vddr20jyx532ab.png" alt="Image description" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;generate_prompt_context&lt;/strong&gt; : Click "Validate and purse input"&lt;br&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%2F55293mepvmj2i9ns96k7.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%2F55293mepvmj2i9ns96k7.png" alt="Image description" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt_variants&lt;/strong&gt; : : Click "Validate and purse input"&lt;br&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%2Fliz3cv92spr0i9l98gd0.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%2Fliz3cv92spr0i9l98gd0.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;answer_the_question_with_context&lt;/strong&gt; : Select deployment name and set max token (e.g. 1000), then click "Validate and purse input"&lt;br&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%2F9zgoktaj712aoatu5mvk.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%2F9zgoktaj712aoatu5mvk.png" alt="Image description" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4-3. Save all configuration changes
&lt;/h3&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%2Fp2z1hjz69trqitpu0s85.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%2Fp2z1hjz69trqitpu0s85.png" alt="Image description" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Try Chat!
&lt;/h2&gt;

&lt;p&gt;Finally it's time to chat with your PDFs.&lt;br&gt;
Click "Chat" button,&lt;br&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%2Fvs4a7d0hwpvy2sa2nyfs.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%2Fvs4a7d0hwpvy2sa2nyfs.png" alt="Image description" width="800" height="179"&gt;&lt;/a&gt;&lt;br&gt;
and then put your question in the chat!&lt;br&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%2Fhdjtrkl7i57k0ml2ejtm.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%2Fhdjtrkl7i57k0ml2ejtm.png" alt="Image description" width="380" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The answer will be returned in the same language with your input.&lt;br&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%2Fvx0bwddaplffy7gndhd3.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%2Fvx0bwddaplffy7gndhd3.png" alt="Image description" width="378" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this blog, we have introduced how to implement a chatbot with RAG (Retrieval-Augmented Generation) that answers questions about sample PDF data using Azure AI Studio's Prompt Flow, and how to practically test it within Azure AI Studio's chat feature. Next in our series, &lt;a href="https://dev.to/aykhara/how-to-evaluate-a-pdf-chatbot-response-with-prompt-flow-c56"&gt;"How to Evaluate a PDF Chatbot Response with Prompt Flow"&lt;/a&gt;, we will delve into methods for evaluating the performance of the chatbot we've just implemented.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>openai</category>
      <category>rag</category>
    </item>
    <item>
      <title>Optimizing satellite image processing with pyvips</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Mon, 27 Nov 2023 06:03:45 +0000</pubDate>
      <link>https://dev.to/aykhara/optimizing-satellite-image-processing-with-pyvips-4n3f</link>
      <guid>https://dev.to/aykhara/optimizing-satellite-image-processing-with-pyvips-4n3f</guid>
      <description>&lt;p&gt;Developing Payload Applications (PAs) for satellites involves a crucial step of preparing and processing test satellite images. In the wide array of image processing libraries available today, choosing the right one can significantly influence the efficiency and success of your project. &lt;/p&gt;

&lt;p&gt;In this blog, we will explore why pyvips emerged as the best fit for processing satellite images, particularly for our needs, and conclude with a practical example using pyvips to process a JPEG2000 (jp2) format image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obtaining test satellite images
&lt;/h2&gt;

&lt;p&gt;Before diving into image processing, let's briefly touch on how to acquire test satellite images. While this topic is extensively covered in &lt;a href="https://dev.to/aykhara/getting-free-satellite-images-for-your-own-payload-app-development-5h2f"&gt;another blog post&lt;/a&gt;, it's worth noting that there are several free resources available for obtaining satellite imagery, crucial for testing and development phases of PAs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing image processing libraries
&lt;/h2&gt;

&lt;p&gt;When working with satellite images, it's important to choose an image processing library that fits your needs. Let's look at some popular libraries in a simple way and see how they compare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Suitable Use-case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://opencv.org/"&gt;OpenCV&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time processing, advanced tasks&lt;/td&gt;
&lt;td&gt;Can be too complex for simple tasks, uses more resources&lt;/td&gt;
&lt;td&gt;Image analysis and processing requiring real-time capabilities and advanced functionality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://pillow.readthedocs.io/en/stable/"&gt;Pillow&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy to use, good for basic tasks&lt;/td&gt;
&lt;td&gt;Not great for very large or complex images&lt;/td&gt;
&lt;td&gt;Basic image manipulation and simple tasks where ease of use is important&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://scikit-image.org/"&gt;scikit-image&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scientific analysis, more complex tasks&lt;/td&gt;
&lt;td&gt;Not as efficient for very large images&lt;/td&gt;
&lt;td&gt;Scientific image analysis and more complex image processing tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/libvips/pyvips"&gt;pyvips&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large images, efficient processing&lt;/td&gt;
&lt;td&gt;Lesser known, less community support&lt;/td&gt;
&lt;td&gt;Handling very large images efficiently, especially in scenarios where performance is critical&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each library has things it's good at. For example, OpenCV is great if you need to do a lot of different things with your images, but it might be too much for simple tasks. pyvips is really good for big images like the ones from satellites, because it doesn't use a lot of computer memory and works fast. The one you choose depends on what you need for your project, like how big your images are and what you want to do with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pyvips for satellite images?
&lt;/h2&gt;

&lt;p&gt;When processing satellite images, pyvips stands out as an excellent choice for a number of compelling reasons:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Efficient handling of large images
&lt;/h4&gt;

&lt;p&gt;Satellite images are often very large, posing a significant challenge for many image processing libraries. pyvips is designed for low memory usage, even with large files. It cleverly manages memory by loading images in smaller parts rather than all at once, making it much more efficient for handling these massive images.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Speed
&lt;/h4&gt;

&lt;p&gt;In image processing, speed is crucial, especially when dealing with large datasets like satellite images. pyvips processes images faster than many other libraries, an advantage that saves considerable time in both development and execution phases.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Support for various formats
&lt;/h4&gt;

&lt;p&gt;pyvips supports a wide range of image formats, including JPEG2000, a popular choice in satellite imagery due to its efficient compression. This versatility is invaluable when working with different types of satellite data.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Low-memory reading
&lt;/h4&gt;

&lt;p&gt;One of pyvips' standout features is its ability to read images using minimal memory. This is particularly useful for satellite images, as it allows for the processing of high-resolution images on machines with limited memory resources.&lt;/p&gt;

&lt;p&gt;In summary, pyvips' ability to efficiently process large images, its speed, support for multiple formats, and low-memory image reading capabilities make it a top choice for satellite image processing. These features collectively ensure that pyvips is well-equipped to handle the challenges of satellite imagery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing pyvips – Sample Code
&lt;/h2&gt;

&lt;p&gt;To work with JPEG2000 format images using pyvips, you need to install it by running the following command:&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="nv"&gt;$ &lt;/span&gt;conda &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--channel&lt;/span&gt; conda-forge pyvips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also refer to &lt;a href="https://github.com/libvips/pyvips#install"&gt;the README&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;Now, let's dive into some practical applications of pyvips with satellite images. Here is sample code demonstrating various operations:&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Code 1: Resizing and color space conversion of images
&lt;/h3&gt;

&lt;p&gt;Satellite image preprocessing often involves resizing the captured image to a uniform size and converting its color space. In this example, we will demonstrate how to resize the image to 50% of its original size and perform a color space conversion from sRGB to CMYK.&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;pyvips&lt;/span&gt;

&lt;span class="c1"&gt;# Load the image from a file
&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;input.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequential&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Resize the image
&lt;/span&gt;&lt;span class="n"&gt;resized_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Resize to 50% of the original size
&lt;/span&gt;
&lt;span class="c1"&gt;# Perform a color space conversion (e.g., from sRGB to CMYK)
&lt;/span&gt;&lt;span class="n"&gt;cmyk_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resized_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;colourspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cmyk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Save the resized and color-converted image in JPEG2000 format
&lt;/span&gt;&lt;span class="n"&gt;cmyk_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jp2ksave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;resized_cmyk_image.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lossless&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pyvips.Image.new_from_file()&lt;/code&gt;: Load an image from a file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image.resize()&lt;/code&gt;: Resize the image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image.colourspace()&lt;/code&gt;: Perform a color space conversion.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image.jp2ksave()&lt;/code&gt;: Save the image in JPEG2000 format.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample Code 2: Rotation and monochrome conversion of images
&lt;/h3&gt;

&lt;p&gt;Depending on the angle and orientation of satellite imagery, it might be necessary to rotate the image or convert it to monochrome for processing in PAs. This example will introduce how to rotate the image by 90 degrees and convert the rotated image to monochrome (black and white).&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;pyvips&lt;/span&gt;

&lt;span class="c1"&gt;# Load the image from a file
&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;input.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequential&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Rotate the image by 90 degrees
&lt;/span&gt;&lt;span class="n"&gt;rotated_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rot90&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Convert the image to monochrome
&lt;/span&gt;&lt;span class="n"&gt;monochrome_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rotated_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;colourspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b-w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Save the rotated and monochrome image in JPEG2000 format
&lt;/span&gt;&lt;span class="n"&gt;monochrome_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jp2ksave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rotated_monochrome_image.jp2&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;ul&gt;
&lt;li&gt;
&lt;code&gt;image.rot90()&lt;/code&gt;: Rotate the image by 90 degrees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample Code 3: Image splitting
&lt;/h3&gt;

&lt;p&gt;By splitting the image into smaller segments, we can process large images more effectively in machine learning models, potentially improving accuracy in tasks like image recognition. In this example, we will demonstrate how to calculate the division of the loaded image into a specified number of segments, in this case, 7 x 7, and how to save these divided images.&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;pyvips&lt;/span&gt;

&lt;span class="c1"&gt;# Load the image from a file
&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;input.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequential&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define the number of segments per axis (7x7 grid)
&lt;/span&gt;&lt;span class="n"&gt;num_segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

&lt;span class="c1"&gt;# Calculate segment dimensions
&lt;/span&gt;&lt;span class="n"&gt;segment_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;num_segments&lt;/span&gt;
&lt;span class="n"&gt;segment_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;num_segments&lt;/span&gt;

&lt;span class="c1"&gt;# Loop through the grid and save each segment
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_segments&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;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_segments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Calculate the position of the current segment
&lt;/span&gt;        &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;segment_width&lt;/span&gt;
        &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;segment_height&lt;/span&gt;

        &lt;span class="c1"&gt;# Extract the segment
&lt;/span&gt;        &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment_height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Save the segment
&lt;/span&gt;        &lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jp2ksave&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;segment_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.jp2&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;ul&gt;
&lt;li&gt;
&lt;code&gt;image.width&lt;/code&gt; and &lt;code&gt;image.height&lt;/code&gt; (Properties of pyvips Image Object): Retrieve the width and height of the loaded image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image.crop&lt;/code&gt;: Extracts a specified portion of the image based on given coordinates and dimensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample Code 4: Adding an alpha channel
&lt;/h3&gt;

&lt;p&gt;Due to the hardware of some satellites, the captured images may include a fourth dimension, such as an alpha channel. This example will show how to add an alpha channel to the loaded image and verify the change in the number of channels before and after processing.&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;pyvips&lt;/span&gt;

&lt;span class="c1"&gt;# Load the image from a file
&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;input.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequential&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Print the current number of bands in the image
&lt;/span&gt;&lt;span class="nf"&gt;print&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;Original number of bands: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bands&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="c1"&gt;# Add an alpha channel to the image
&lt;/span&gt;&lt;span class="n"&gt;image_with_alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addalpha&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Save the image with the alpha channel in JPEG2000 format
&lt;/span&gt;&lt;span class="n"&gt;image_with_alpha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jp2ksave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;image_with_alpha.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Reload the saved image to verify the band count
&lt;/span&gt;&lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;image_with_alpha.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Print the number of bands in the modified image
&lt;/span&gt;&lt;span class="n"&gt;modified_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyvips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_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;image_with_alpha.jp2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequential&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Modified number of bands: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;modified_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bands&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;ul&gt;
&lt;li&gt;
&lt;code&gt;image.bands&lt;/code&gt; (Property of pyvips Image Object): Returns the number of bands (channels) in the image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image.addalpha()&lt;/code&gt;: Adds an alpha channel to the image for transparency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples showcase the capability of pyvips to handle complex image processing tasks efficiently, making it a valuable tool for working with high-resolution satellite imagery.&lt;/p&gt;

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

&lt;p&gt;When making payload applications for satellites, picking the right tool to process your images is really important. pyvips is a really useful tool for anyone working with satellite images, whether you're just starting out or have lots of experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting free satellite images for your own payload app development</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Mon, 27 Nov 2023 06:01:58 +0000</pubDate>
      <link>https://dev.to/aykhara/getting-free-satellite-images-for-your-own-payload-app-development-5h2f</link>
      <guid>https://dev.to/aykhara/getting-free-satellite-images-for-your-own-payload-app-development-5h2f</guid>
      <description>&lt;p&gt;Creating payload applications for satellites means you need test images from space. But, getting these images can be really expensive. They can cost a few thousand dollars each, and even more if you need very detailed or special kinds of images – sometimes more than tens of thousands of dollars. This makes it hard for many people to buy these images, especially when they're just starting to develop their payload applications. &lt;/p&gt;

&lt;p&gt;Also, these satellite images come in different formats, like JPEG 2000, PNG, and GeoTIFF, depending on who's giving them and what you need them for. &lt;/p&gt;

&lt;p&gt;In this blog, I'm going to show you how to get JPEG 2000 and PNG images for free, which you can use for testing your own payload applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copernicus Browser
&lt;/h2&gt;

&lt;p&gt;If you're looking for JPEG2000 data, you might find it on &lt;a href="https://dataspace.copernicus.eu/browser/"&gt;Copernicus Data Space Ecosystem　　- Copernicus Browser&lt;/a&gt;.&lt;br&gt;
Previously, it was possible to search via the &lt;a href="https://scihub.copernicus.eu/"&gt;Copernicus Open Access Hub&lt;/a&gt;, but its operations ended at the end of October 2023. Copernicus Sentinel data are now fully available in the &lt;a href="https://dataspace.copernicus.eu/"&gt;Copernicus Data Space Ecosystem&lt;/a&gt;. This new service provides not only access to a wide range of Earth observation data and services but also offers new tools, a GUI, and APIs to support the exploration and analysis of satellite imagery.&lt;/p&gt;

&lt;p&gt;The primary goal of the service is to ensure instant data availability to users. The full data archive acquired by the Copernicus Sentinel satellites will be available online and can be accessed in real-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  License
&lt;/h3&gt;

&lt;p&gt;The data will be available free of charge via designated quotes for &lt;strong&gt;individual use&lt;/strong&gt;. Users that wish to build large scale operations can use practically unlimited resources available under commercial terms. (Ref - &lt;a href="https://dataspace.copernicus.eu/about"&gt;About the&lt;br&gt;
Copernicus Data Space Ecosystem&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  How to download data
&lt;/h3&gt;

&lt;p&gt;1.Open &lt;a href="https://dataspace.copernicus.eu/browser/"&gt;Copernicus Browser&lt;/a&gt; in a new window or tab. &lt;/p&gt;

&lt;p&gt;2.Register or log in. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P2MMIc-3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfdo05n9aqmktye8qy8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P2MMIc-3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfdo05n9aqmktye8qy8q.png" alt="Image description" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JKnA9nU1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owun2e5ozwa57mtmlvag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JKnA9nU1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owun2e5ozwa57mtmlvag.png" alt="Image description" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.Zoom in on somewhere you like on the map with the scroll wheel of your mouse.&lt;br&gt;
4.Specify the data criteria via Search tab: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the satellite (as of Nov 2023, Sentinel-1, Sentinel-2, Sentinel-3, Sentinel-5P and Sentinel-6 are supported. Please refer to &lt;a href="https://documentation.dataspace.copernicus.eu/Data.html"&gt;the documentation about data&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, if you select Sentinel-2, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the MultiSpectral Instrument (MSI): L1C(&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-1c"&gt;Level-1C&lt;/a&gt;) and L2A(&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-2a"&gt;Level-2A&lt;/a&gt;). (Ref - &lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types"&gt;Sentinel-2 MSI User Guide - Product Types&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Specify cloud cover percentage (e.g., 100% for all images, 50% for images with less than 50% cloud cover) &lt;/li&gt;
&lt;li&gt;Select the Auxiliary Data File: AUX_GNSSRD, AUX_PROQUA and AUX_POEORB. Please refer to &lt;a href="https://documentation.dataspace.copernicus.eu/Data/Sentinel2.html#sentinel-2-precise-orbit-determination-pod-products"&gt;Sentinel-2 Precise Orbit Determination (POD) products&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Observation date/time range&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the comparison between L1C and L2A (Ref - &lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types"&gt;Sentinel-2 MSI User Guide - Product Types&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Users&lt;/th&gt;
&lt;th&gt;Production &amp;amp; Distribution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User Product&lt;/td&gt;
&lt;td&gt;Level-1C&lt;/td&gt;
&lt;td&gt;Top-of-atmosphere reflectances in cartographic geometry&lt;/td&gt;
&lt;td&gt;All Users&lt;/td&gt;
&lt;td&gt;Systematic generation and online distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User Product&lt;/td&gt;
&lt;td&gt;Level-2A&lt;/td&gt;
&lt;td&gt;Atmospherically corrected Surface Reflectances in cartographic geometry&lt;/td&gt;
&lt;td&gt;All Users&lt;/td&gt;
&lt;td&gt;Systematic generation and online distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d6I_IgSe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24f1suvf7chex6vn7z1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d6I_IgSe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24f1suvf7chex6vn7z1m.png" alt="Image description" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5.Select from the list or map. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_JBeXllB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7fgmfyz2s4bvbp9r78p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_JBeXllB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7fgmfyz2s4bvbp9r78p.png" alt="Image description" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6.Click on the download icon for the desired image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FMvuyEoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmg2ei4i0mmhx8vvfeuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FMvuyEoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmg2ei4i0mmhx8vvfeuh.png" alt="Image description" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you would like to try more advanced search, please refer to &lt;a href="https://documentation.dataspace.copernicus.eu/Applications/Browser.html#product-search"&gt;the Product Search&lt;/a&gt; page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Kaggle
&lt;/h2&gt;

&lt;p&gt;If you're looking for PNG data, you might find it on &lt;a href="https://www.kaggle.com/"&gt;Kaggle&lt;/a&gt;. &lt;br&gt;
Kaggle is a platform primarily known for hosting data science competitions but offers much more, including a vast repository of datasets, a public data platform, and an online community for data scientists and machine learning practitioners. It was acquired by Google in 2017 and is part of the Google Cloud suite of services.&lt;/p&gt;

&lt;h3&gt;
  
  
  License
&lt;/h3&gt;

&lt;p&gt;Regarding copyright of the data on Kaggle, it varies depending on the dataset. Each dataset on Kaggle comes with its own licensing terms, set by the dataset provider. These terms specify how the data can be used, and they can range from completely open and free for any use (like those under the Public Domain or Creative Commons licenses) to more restrictive terms that might limit use to non-commercial purposes or require attribution. It's important to note that just because data is accessible on Kaggle, it does not automatically mean it's free of copyright or restrictions on use.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to download data
&lt;/h3&gt;

&lt;p&gt;Here are some examples of Kaggle Dataset you might want to check.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Image Format&lt;/th&gt;
&lt;th&gt;Number of Data&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/datasets/andrewmvd/ship-detection"&gt;Ship Detection from Aerial Images&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;PNG&lt;/td&gt;
&lt;td&gt;621 (with ship)&lt;/td&gt;
&lt;td&gt;CC0: Public Domain - No Copyright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.kaggle.com/datasets/rhammell/ships-in-satellite-imagery"&gt;Ships in Satellite Imagery&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;PNG (80x80 RGB images)&lt;/td&gt;
&lt;td&gt;1000 (with ship), 3000 (without ship)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://creativecommons.org/licenses/by-sa/4.0/"&gt;CC BY-SA 4.0&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Need to purchase satellite images for testing?
&lt;/h2&gt;

&lt;p&gt;Some might wonder if free satellite images are sufficient for testing purposes. However, upon conducting actual searches, you'll realize that finding images that meet specific and detailed criteria can be extremely challenging. For instance, let's say you need satellite images taken near a port, where several ships are visible on the sea, with a cloud cover of around 30%, and even airplanes in the sky. Searching for such images using the tools mentioned above can be a time-consuming task, or you might not find them at all.&lt;/p&gt;

&lt;p&gt;As the time to deploy your payload application to the satellite approaches and you need to test it with more detailed test cases, you may need to consider purchasing expensive satellite images.&lt;/p&gt;

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

&lt;p&gt;To wrap up, making payload applications for satellites doesn't have to be expensive when it comes to getting test images. This blog has shown you how you can easily get JPEG 2000 and PNG images without spending a lot of money. You can use the Copernicus Data Space Ecosystem to get a wide variety of free Sentinel satellite images, which is great for anyone needing fresh and different types of images. Also, Kaggle is a good place to find different datasets, including PNG images, where you often don't have to worry much about copyright because of flexible licensing.&lt;/p&gt;

&lt;p&gt;These resources are a big help in cutting down costs for satellite images. They open up more chances for creative work in making payload applications, whether you're experienced or just beginning. With these platforms, you have access to lots of data for your projects, making it easier to work on satellite-based applications without worrying about high costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://documentation.dataspace.copernicus.eu/Applications/Browser.html#product-search"&gt;About the browser - Product Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi"&gt;Sentinel-2 MSI User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types"&gt;Sentinel-2 MSI User Guide - Product Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-1c"&gt;Level-1C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-2a"&gt;Level-2A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://documentation.dataspace.copernicus.eu/Data/Sentinel2.html#sentinel-2-precise-orbit-determination-pod-products"&gt;Sentinel-2 Precise Orbit Determination (POD) products&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kaggle.com/"&gt;Kaggle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kaggle.com/datasets/andrewmvd/ship-detection"&gt;Ship Detection from Aerial Images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kaggle.com/datasets/rhammell/ships-in-satellite-imagery"&gt;Ships in Satellite Imagery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Deploying Minimum Viable Dataspace to Azure: A Step-by-Step Guide</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Wed, 19 Apr 2023 04:39:30 +0000</pubDate>
      <link>https://dev.to/aykhara/deploying-minimum-viable-dataspace-to-azure-a-step-by-step-guide-51j7</link>
      <guid>https://dev.to/aykhara/deploying-minimum-viable-dataspace-to-azure-a-step-by-step-guide-51j7</guid>
      <description>&lt;h2&gt;
  
  
  What is Minimum Viable Dataspace (MVD)?
&lt;/h2&gt;

&lt;p&gt;The Minimum Viable Dataspace (MVD) is a sample implementation of a dataspace that leverages the Eclipse Dataspace Components (EDC). The main purpose is to demonstrate the capabilities of the EDC, make dataspace concepts tangible based on a specific implementation, and to serve as a starting point to implement a custom dataspace. &lt;/p&gt;

&lt;p&gt;Since I will not explain what EDC is in this article, I recommend that those who want to learn about EDC first refer to &lt;a href="https://projects.eclipse.org/projects/technology.edc" rel="noopener noreferrer"&gt;the official Eclipse Foundation documents&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure deployment for MVD
&lt;/h2&gt;

&lt;p&gt;In the past, there was an Azure deployment workflow on the MVD repository. However, it does not exist on the repo anymore.&lt;/p&gt;

&lt;p&gt;There were some reasons for removing the deployment to Azure. Please refer to &lt;a href="https://github.com/eclipse-edc/MinimumViableDataspace/issues/128" rel="noopener noreferrer"&gt;this GitHub issue&lt;/a&gt; if you want to know more details.&lt;/p&gt;

&lt;p&gt;Some of you may still want to deploy MVD to Azure like me. In this article, how to achieve Azure deployment with the previous workflow will be illustrated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Initializing an Azure environment for CD

&lt;ul&gt;
&lt;li&gt;
1. Create a service identity for GitHub Actions

&lt;ul&gt;
&lt;li&gt;1-1. Create App Registration for GitHub Actions&lt;/li&gt;
&lt;li&gt;1-2. Configure main Branch Credentials&lt;/li&gt;
&lt;li&gt;1-3. Configure Pull Request Credentials&lt;/li&gt;
&lt;li&gt;1-4. Create a new application secret&lt;/li&gt;
&lt;li&gt;1-5. Grant Permissions for Azure Subscription&lt;/li&gt;
&lt;li&gt;1-6. Configure GitHub Secrets for GitHub Actions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

2. Create Service Identity for MVD Runtimes

&lt;ul&gt;
&lt;li&gt;2-1. Create App Registration for MVD Runtimes&lt;/li&gt;
&lt;li&gt;2-2. Create Client Secret for MVD Runtimes&lt;/li&gt;
&lt;li&gt;2-3. Get Application Object ID&lt;/li&gt;
&lt;li&gt;2-4. Configure GitHub Secrets for MVD Runtimes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;3. Configure CD Settings&lt;/li&gt;

&lt;li&gt;4. Deploying CD resources&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Create a new dataspace instance&lt;/li&gt;

&lt;li&gt;Ready to use MVD!&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;Before proceeding to the actual preparation of the environment, we must first revert to &lt;a href="https://github.com/eclipse-edc/MinimumViableDataspace/commit/9362f36f09123d7ceca67b8239cae2b82bacca3a" rel="noopener noreferrer"&gt;the old commit where the Deploy pipeline for Azure existed&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A fork of the &lt;a href="https://github.com/eclipse-dataspaceconnector/MinimumViableDataspace" rel="noopener noreferrer"&gt;MVD repository&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Back to a previous commit&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please run the following commands on your local to reset the code in your fork to &lt;a href="https://github.com/eclipse-edc/MinimumViableDataspace/commit/9362f36f09123d7ceca67b8239cae2b82bacca3a" rel="noopener noreferrer"&gt;a previous commit where the Deploy pipeline exists&lt;/a&gt;. The commit id should be &lt;code&gt;9362f36f09123d7ceca67b8239cae2b82bacca3a&lt;/code&gt;.&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;git log
git reset --hard (COMMIT-ID)
git push REMOTE-NAME LOCAL-BRANCH-NAME:REMOTE-BRANCH-NAME
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a previous commit is successfully backed you will find that there are 6 yaml files (cd.yaml, check.yaml, cloud-cd.yaml, &lt;strong&gt;deploy.yaml&lt;/strong&gt;, destroy.yaml, and initialize.yaml) in the workflow folder.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare an Azure subscription&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A GitHub workflow then needs to be run to provision the Azure resources used for CD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing an Azure environment for CD
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a service identity for GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Further documentation for the following steps can be found in the Microsoft Docs to &lt;a href="https://docs.microsoft.com/azure/active-directory/develop/workload-identity-federation-create-trust-github" rel="noopener noreferrer"&gt;Configure an app to trust a GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  1-1. Create App Registration for GitHub Actions
&lt;/h4&gt;

&lt;p&gt;Sign in to the &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;, navigate to &lt;em&gt;App registrations&lt;/em&gt; and select &lt;em&gt;New registration&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Register a new application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Provide a display name for the application, e.g. &lt;em&gt;"MVD GitHub Actions App"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Supported Account Types&lt;/strong&gt;, select &lt;strong&gt;Accounts in this organizational directory only&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Don't enter anything for &lt;strong&gt;Redirect URI (optional)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select &lt;strong&gt;Register&lt;/strong&gt; to create the app registration.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F822e77i1sc5az6b15mt7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F822e77i1sc5az6b15mt7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the &lt;em&gt;Application (client) ID&lt;/em&gt; (will be required to configure a GitHub secret below).&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhpfydbt1igna9du9f1y.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhpfydbt1igna9du9f1y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we create two types of credentials: two federated credentials to authenticate GitHub Actions, and a client secret for Terraform (required as Terraform does not yet support Azure CLI login with a service principal).&lt;br&gt;
Follow the instructions to &lt;a href="https://docs.microsoft.com/azure/active-directory/develop/workload-identity-federation-create-trust-github?tabs=azure-portal#configure-a-federated-identity-credential" rel="noopener noreferrer"&gt;Configure a federated identity credential&lt;/a&gt; for the &lt;code&gt;main&lt;/code&gt; branch and Pull requests.&lt;/p&gt;

&lt;h4&gt;
  
  
  1-2. Configure main Branch Credentials
&lt;/h4&gt;

&lt;p&gt;Select the previously created application (e.g. &lt;em&gt;"MVD GitHub Actions App"&lt;/em&gt;) and navigate to &lt;strong&gt;Certificates &amp;amp; secrets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;Federated credentials&lt;/strong&gt;, click &lt;strong&gt;Add credential&lt;/strong&gt; and define the following values.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk75fvah1iofqyhezvk11.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk75fvah1iofqyhezvk11.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;Federated credential scenario&lt;/strong&gt;, select &lt;strong&gt;GitHub actions deploying Azure resources&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Organization&lt;/strong&gt;, add your GitHub organization. For example, your organization is &lt;em&gt;YourGitHubOrg&lt;/em&gt; if the URL of your GitHub repository is &lt;a href="https://github.com/YourGitHubOrg/MinimumViableDataspace" rel="noopener noreferrer"&gt;https://github.com/YourGitHubOrg/MinimumViableDataspace&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Entity Type&lt;/strong&gt;, select &lt;strong&gt;Branch&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;GitHub branch name&lt;/strong&gt;, enter &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Name&lt;/strong&gt;, enter a name for the credential, e.g. &lt;em&gt;"mvd-main-branch"&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to create the credential.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsoykq748er0h761xbvh.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsoykq748er0h761xbvh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can add additional credentials to deploy from other branches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1-3. Configure Pull Request Credentials
&lt;/h4&gt;

&lt;p&gt;Now, we set up a federated credential for pull requests, which allows to run a cloud deployment to validate pull requests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This step is only required if you plan to create pull requests for the MVD.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click &lt;strong&gt;Add credential&lt;/strong&gt; to add another credential (for the previously created application (e.g. &lt;em&gt;"MVD GitHub Actions App"&lt;/em&gt;), under &lt;strong&gt;Certificates &amp;amp; secrets&lt;/strong&gt;, &lt;strong&gt;Federated credentials&lt;/strong&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;Federated credential scenario&lt;/strong&gt;, select &lt;strong&gt;GitHub actions deploying Azure resources&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Organization&lt;/strong&gt;, add your GitHub organization. For example, your organization is &lt;em&gt;YourGitHubOrg&lt;/em&gt; if the URL of your GitHub repository is &lt;a href="https://github.com/YourGitHubOrg/MinimumViableDataspace" rel="noopener noreferrer"&gt;https://github.com/YourGitHubOrg/MinimumViableDataspace&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Entity Type&lt;/strong&gt;, select &lt;strong&gt;Pull Request&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Name&lt;/strong&gt;, enter a name for the credential, e.g. &lt;em&gt;"mvd-pull-requests"&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to create the credential.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuje19s09w0mv9s3linl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuje19s09w0mv9s3linl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  1-4. Create a new application secret
&lt;/h4&gt;

&lt;p&gt;Create a client secret by following the section "Create a new application secret" in the page on &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#option-2-create-a-new-application-secret" rel="noopener noreferrer"&gt;Creating a an Azure AD application to access resources&lt;/a&gt;. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i3nxnlgi9fmfp99kn21.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i3nxnlgi9fmfp99kn21.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the client secret and keep it safe.&lt;/p&gt;

&lt;h4&gt;
  
  
  1-5. Grant Permissions for Azure Subscription
&lt;/h4&gt;

&lt;p&gt;To allow GitHub Actions to deploy resources to your Azure subscription, grant the application created above Owner permissions on your Azure subscription.&lt;br&gt;
Further documentation for the following steps can be found under &lt;a href="https://docs.microsoft.com/azure/role-based-access-control/role-assignments-portal" rel="noopener noreferrer"&gt;Assign Azure roles using the Azure portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Navigate to your &lt;strong&gt;subscription&lt;/strong&gt; you want to deploy the MVD resources to, select &lt;strong&gt;Access control (IAM)&lt;/strong&gt; and click on &lt;strong&gt;Add role assignment&lt;/strong&gt;.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl8rtldd8oel0ymvx6jv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl8rtldd8oel0ymvx6jv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;strong&gt;Add role assignment&lt;/strong&gt; page, select &lt;strong&gt;Owner&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcei27w4wogdmipgr7ts.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcei27w4wogdmipgr7ts.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on &lt;strong&gt;Select members&lt;/strong&gt;, search for the application created above (e.g. &lt;em&gt;"MVD GitHub Actions App"&lt;/em&gt;), click &lt;strong&gt;Select&lt;/strong&gt; and then click on &lt;strong&gt;Next&lt;/strong&gt; and then on &lt;strong&gt;Review + assign&lt;/strong&gt; to assign the application Owner permissions on your Azure subscription.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dmqxlibqzt8jipaorv2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dmqxlibqzt8jipaorv2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need to enter the full application name when searching for the application, the application will not show up if you only enter a partial name (e.g. &lt;em&gt;"MVD GitHub Act"&lt;/em&gt; in the example above).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1-6. Configure GitHub Secrets for GitHub Actions
&lt;/h4&gt;

&lt;p&gt;Finally, the application (client) ID needs to be made available to your GitHub repository using &lt;a href="https://docs.github.com/en/actions/security-guides/encrypted-secrets" rel="noopener noreferrer"&gt;GitHub secrets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To configure GitHub Secrets, navigate to your &lt;code&gt;MinimumViableDataspace&lt;/code&gt; repository, select &lt;strong&gt;Settings&lt;/strong&gt;, navigate to &lt;strong&gt;Secrets&lt;/strong&gt; and then &lt;strong&gt;Actions&lt;/strong&gt;, and click &lt;strong&gt;New repository secret&lt;/strong&gt; to create a new secret.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdyxrjkyr19e9sv6omxq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdyxrjkyr19e9sv6omxq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure the following GitHub secrets with the value from the steps above:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ARM_CLIENT_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The application (client) ID of the application created above (e.g. &lt;em&gt;"MVD GitHub Actions App"&lt;/em&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ARM_CLIENT_SECRET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The application client secret.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Create Service Identity for MVD Runtimes
&lt;/h3&gt;

&lt;p&gt;Further documentation for the following steps can be found in the Microsoft Docs to &lt;a href="https://docs.microsoft.com/azure/active-directory/develop/workload-identity-federation-create-trust-github" rel="noopener noreferrer"&gt;Create and configure an Azure AD application for the application runtimes&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2-1. Create App Registration for MVD Runtimes
&lt;/h4&gt;

&lt;p&gt;Sign in to the &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;, navigate to &lt;em&gt;App registrations&lt;/em&gt; and select &lt;em&gt;New registration&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Register a new application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Provide a display name for the application, e.g. &lt;em&gt;"MVD Runtimes App"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Supported Account Types&lt;/strong&gt;, select &lt;strong&gt;Accounts in this organizational directory only&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Don't enter anything for &lt;strong&gt;Redirect URI (optional)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select &lt;strong&gt;Register&lt;/strong&gt; to create the app registration.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F829u4wq3enuyqx30tcm0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F829u4wq3enuyqx30tcm0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the &lt;em&gt;Application (client) ID&lt;/em&gt; (will be required to configure a GitHub secret below).&lt;/p&gt;

&lt;h4&gt;
  
  
  2-2. Create Client Secret for MVD Runtimes
&lt;/h4&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Certificates &amp;amp; secrets&lt;/strong&gt; and then to the &lt;strong&gt;Client secrets&lt;/strong&gt; tab (for the previously created application (e.g. &lt;em&gt;"MVD Runtimes App"&lt;/em&gt;), and select &lt;strong&gt;New client secret&lt;/strong&gt;. Create a new client secret by entering a &lt;strong&gt;Description&lt;/strong&gt; (e.g. &lt;em&gt;"mvd-runtimes-app-client-secret"&lt;/em&gt;) and clicking &lt;strong&gt;Add&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Take note of the client secret (&lt;strong&gt;Value&lt;/strong&gt;) and keep it safe (will be required to configure a GitHub secret below).&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4dpctad0cfmydayodea.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4dpctad0cfmydayodea.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2-3. Get Application Object ID
&lt;/h4&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Azure Active Directory&lt;/strong&gt; and select &lt;strong&gt;Enterprise Applications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Take note of the enterprise application &lt;strong&gt;Object ID&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure you use the Object ID of the &lt;em&gt;Enterprise application&lt;/em&gt;, and not the Object ID of the &lt;em&gt;App Registration&lt;/em&gt;!&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r8yf3kpr0xb3rvu5yzd.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r8yf3kpr0xb3rvu5yzd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2-4. Configure GitHub Secrets for MVD Runtimes
&lt;/h4&gt;

&lt;p&gt;Configure the following GitHub secrets with the values from the steps above:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_CLIENT_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The application (client) ID.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_CLIENT_SECRET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The application client secret.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_OBJECT_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The ID of the service principal object associated with this application.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;See instructions under Configure GitHub Secrets for GitHub Actions on how to configure GitHub secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Configure CD Settings
&lt;/h3&gt;

&lt;p&gt;Configure the following GitHub secrets which are required by the CD pipeline:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ARM_TENANT_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Azure Active Directory &lt;strong&gt;Tenant ID&lt;/strong&gt;. Navigate to Azure Active Directory and copy the Tenant ID from the &lt;em&gt;Overview&lt;/em&gt; page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ARM_SUBSCRIPTION_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Azure &lt;strong&gt;Subscription ID&lt;/strong&gt; to deploy resources to. Navigate to Subscriptions and copy the &lt;em&gt;Subscription ID&lt;/em&gt; of your subscription.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMMON_RESOURCE_GROUP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Azure resource group name to deploy common resources to, such as Azure Container Registry. Choose any valid resource group name, e.g. &lt;em&gt;rg-mvd-common&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMMON_RESOURCE_GROUP_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The location where common resources should be deployed to, e.g. &lt;em&gt;eastus&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACR_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The name of the Azure Container Registry to deploy. Use only lowercase letters and numbers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TERRAFORM_STATE_STORAGE_ACCOUNT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The name of the storage account used to store the Terraform state container, e.g. &lt;em&gt;mvdterraformstates&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TERRAFORM_STATE_CONTAINER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The name of the container used to store the Terraform state blob, e.g. &lt;em&gt;mvdterraformstates&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Deploying CD resources
&lt;/h3&gt;

&lt;p&gt;Common resources need to be deployed once, these resources will be used by all CD pipelines.&lt;/p&gt;

&lt;p&gt;Manually run the &lt;code&gt;Initialize CD&lt;/code&gt; GitHub Actions workflow and make sure that it passes successfully.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq2huo8zakugufweltz2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq2huo8zakugufweltz2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since &lt;code&gt;workflow_dispatch&lt;/code&gt; is already in deploy pipeline a ‘Run workflow’ button should be on the Actions tab, enabling you to easily trigger a run. (&lt;a href="https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/" rel="noopener noreferrer"&gt;GitHub Actions: Manual triggers with workflow_dispatch&lt;br&gt;
&lt;/a&gt;) If you cannot find the button like the screenshot below I would suggest you to try changing the file extension, from &lt;em&gt;deploy.yaml&lt;/em&gt; to &lt;em&gt;deploy.yml&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw774tvaciqjfwmwrebv0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw774tvaciqjfwmwrebv0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your infrastructure is now set up to run deployments, you can now run the &lt;code&gt;Deploy&lt;/code&gt; GitHub Actions workflow in the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new dataspace instance
&lt;/h2&gt;

&lt;p&gt;Once your environment is set up, follow these steps to create a new dataspace instance:&lt;/p&gt;

&lt;p&gt;Select the &lt;code&gt;Deploy&lt;/code&gt; GitHub Actions workflow and provide your own resources name prefix. Please, use at most 3 characters, composed of lower case letters and numbers.&lt;/p&gt;

&lt;p&gt;Click on &lt;code&gt;Run workflow&lt;/code&gt; to manually run the &lt;code&gt;Deploy&lt;/code&gt; GitHub Actions workflow.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi859gk54cv5d9gyt3kpk.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi859gk54cv5d9gyt3kpk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure that it passes successfully.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnsduo8x3yjnankkcq7j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnsduo8x3yjnankkcq7j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to use MVD!
&lt;/h2&gt;

&lt;p&gt;Once Deploy pipeline passes successfully then you can now access to MVD which just has been deployed with your own resources name prefix.&lt;/p&gt;

&lt;p&gt;The Data Dashboard is a web application (development UI) on top of EDC's DataManagementAPI and is deployed for each participant. It can be accessed at the URLs provided in the GitHub workflow run page like below. &lt;br&gt;
For instance, if the name prefix was &lt;code&gt;dragon&lt;/code&gt;:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4jpjjw25gqxwulz0on7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4jpjjw25gqxwulz0on7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will have three Data Dashboards for three participants: company 1, company 2 and company 3 as below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;company 1&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.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%2F8vjr80027bwkabvj35ql.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vjr80027bwkabvj35ql.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;company 2&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.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%2Fmddfxqxc0kvcx6cfarjg.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmddfxqxc0kvcx6cfarjg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;company 3&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.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%2Fvlb1g7jjkzuzu66x0rgv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlb1g7jjkzuzu66x0rgv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to demonstrate the possibilities of Dataspaces please refer to &lt;a href="https://github.com/eclipse-edc/MinimumViableDataspace/blob/main/Vision%20Demonstrator/Vision%20Demonstrator%20Introduction.md" rel="noopener noreferrer"&gt;Vision Demonstrator document&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Azure deployment workflow has been removed from the MVD repo but it still can be deployed with the previous commit. Please be aware of that it will not be updated anymore.&lt;br&gt;
Hope this step-by-step guide is helpful for some of you who want to try MVD on Azure.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>edc</category>
    </item>
    <item>
      <title>How to configure Azure SQL Always Encrypted for Mac users</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Thu, 18 Aug 2022 00:26:00 +0000</pubDate>
      <link>https://dev.to/aykhara/how-to-configure-azure-sql-always-encrypted-for-mac-users-1n0k</link>
      <guid>https://dev.to/aykhara/how-to-configure-azure-sql-always-encrypted-for-mac-users-1n0k</guid>
      <description>&lt;p&gt;Always Encrypted is a feature included in Azure SQL Server. Data is encrypted all the time, not only at rest but also in motion. Furthermore, the encryption keys which are essential for both encrypting and decrypting are not stored in the database.&lt;br&gt;
For more information on Always Encrypted, please refer to &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver16" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are multiple ways to configure Always Encrypted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/configure-always-encrypted-using-powershell?view=azuresqldb-current" rel="noopener noreferrer"&gt;Configure Always Encrypted using PowerShell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/configure-always-encrypted-using-sql-server-management-studio?view=azuresqldb-current" rel="noopener noreferrer"&gt;Configure Always Encrypted using SQL Server Management Studio (SSMS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kenakamu/visual-studio-database-project-and-always-encrypted-n4p"&gt;Configure Always Encrypted using Visual Studio Database Project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of the methods listed above, SSMS and Visual Studio Database Project are only available for Windows.&lt;br&gt;
If you need to run on macOS or Linux, &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver16" rel="noopener noreferrer"&gt;Azure Data Studio&lt;/a&gt; or Visual Studio Code is for you.&lt;br&gt;
In this article, I'm going to explain how to configure Always Encrypted with Azure Data Studio on macOS.&lt;/p&gt;
&lt;h3&gt;
  
  
  TOC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pre-requisites&lt;/li&gt;
&lt;li&gt;1. Install the SQL Database Projects extension&lt;/li&gt;
&lt;li&gt;2. Create new database project&lt;/li&gt;
&lt;li&gt;
3. Create keys

&lt;ul&gt;
&lt;li&gt;3.1 Create Column Master Key (CMK)&lt;/li&gt;
&lt;li&gt;3.2 Create Column Encryption Key (CEK)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;4. Create table with encrypted columns&lt;/li&gt;
&lt;li&gt;5. Build/Publish with Data Studio&lt;/li&gt;
&lt;li&gt;6. Confirm the result&lt;/li&gt;
&lt;li&gt;How DACPAC looks like?&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Pre-requisites &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There are several combination patterns, but for this example we will use SQL database and Key Vault to store a master key. The following Azure resources will be used here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL Server&lt;/li&gt;
&lt;li&gt;SQL Database&lt;/li&gt;
&lt;li&gt;Key Vault&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, if you haven't installed yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver16" rel="noopener noreferrer"&gt;Download and install Azure Data Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.2" rel="noopener noreferrer"&gt;Installing PowerShell on macOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1. Install the SQL Database Projects extension&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Firstly, install &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-database-project-extension?view=sql-server-ver16" rel="noopener noreferrer"&gt;the SQL Database Projects extension&lt;/a&gt; in Azure Data Studio.&lt;br&gt;
It is an Azure Data Studio and VS Code extension for developing SQL databases including for SQL Server, Azure SQL Database, and Azure SQL Managed Instance in a project-based development environment. &lt;br&gt;
*This extension is still in preview. (as of 18th Aug 2022)&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbf5pkfy9to737ts938t.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbf5pkfy9to737ts938t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Create new database project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now, let's create a database project using the extensions we have just installed.&lt;br&gt;
Click &lt;code&gt;Create new&lt;/code&gt; in Database Projects pane,&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhsw816s86pgeh445uhs.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhsw816s86pgeh445uhs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then select &lt;code&gt;Azure SQL Database&lt;/code&gt; as type and give it a project name such as DB.&lt;br&gt;
&lt;a href="https://media.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%2Fy6sm8k1oyi9abj1sk3jf.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6sm8k1oyi9abj1sk3jf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Create keys&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Two keys are required for Always Encrypted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Column Master Key (Store in Key Vault)&lt;/li&gt;
&lt;li&gt;Column Encryption Key (Store in SQL database)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3.1 Create Column Master Key (CMK) &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  3.1.1 Create Column Master Key in Azure Key Vault
&lt;/h4&gt;

&lt;p&gt;We can manually create CMK in Azure Key Vault via Azure portal or by running the following PowerShell script. (Ref: &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/configure-always-encrypted-keys-using-powershell?view=azuresqldb-current#azure-key-vault-without-role-separation-example" rel="noopener noreferrer"&gt;Azure Key Vault without Role Separation (Example)&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a column master key in Azure Key Vault.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Az&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Connect-AzAccount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SubscriptionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Azure SubscriptionId&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$resourceGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rg-ayhara-playground"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$azureLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"japaneast"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$akvName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kv-ayhara-sample"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$akvKeyName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CMKAuto1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$azureCtx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-AzConteXt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-SubscriptionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SubscriptionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;#Sets the context for the below cmdlets to the specified subscription.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;New-AzResourceGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$resourceGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$azureLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Creates a new resource group - skip, if your desired group already exists.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;New-AzKeyVault&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-VaultName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$akvName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ResourceGroupName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$resourceGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$azureLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Creates a new key vault - skip if your vault already exists.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-AzKeyVaultAccessPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-VaultName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$akvName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ResourceGroupName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$resourceGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PermissionsToKeys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;unwrapKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UserPrincipalName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$azureCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$akvKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Add-AzKeyVaultKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-VaultName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$akvName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$akvKeyName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Destination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Software"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please confirm that the CMK has been created in the Key Vault as expected and copy the Key Identifier for use in the next step.&lt;br&gt;
&lt;a href="https://media.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%2Fpprngtmd3xwpzy893g50.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpprngtmd3xwpzy893g50.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to make sure that the required permissions as well, i.e. &lt;code&gt;get, create, delete, list, wrapKey,unwrapKey, sign, verify&lt;/code&gt;, are granted. &lt;br&gt;
&lt;a href="https://media.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%2F8iqixowc1zno1mmvzhze.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8iqixowc1zno1mmvzhze.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3.1.2 Set Key Vault information to master key
&lt;/h4&gt;

&lt;p&gt;Let's go back to Data Studio.&lt;br&gt;
Since the CMK and CEK templates in Visual Studio are not available in Data Studio unfortunately, we require to add script as item.&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Add new item&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.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%2F939pznn3dvghgpr67og3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F939pznn3dvghgpr67og3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then put &lt;code&gt;ColumnMasterKey&lt;/code&gt; in the field and press &lt;code&gt;Enter&lt;/code&gt; to confirm.&lt;br&gt;
&lt;a href="https://media.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%2Fmrqr0ye4bjl1x5zfefej.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrqr0ye4bjl1x5zfefej.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following Transact-SQL should be added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;MASTER&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CMK_Auto1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;KEY_STORE_PROVIDER_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;'AZURE_KEY_VAULT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;KEY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;'https://kv-ayhara-sample-ado.vault.azure.net/keys/CMKAuto1/ecffa3fdcb2f432b9b0b8474770ade38'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 Create Column Encryption Key (CEK) &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Next, Column Encryption Key (CEK).&lt;br&gt;
Let's creates the encrypted value of a column encryption key with &lt;a href="https://docs.microsoft.com/en-us/powershell/module/sqlserver/new-sqlcolumnencryptionkeyencryptedvalue?view=sqlserver-ps" rel="noopener noreferrer"&gt;New-SqlColumnEncryptionKeyEncryptedValue&lt;/a&gt;.&lt;br&gt;
(Unfortunately, &lt;code&gt;The New-SqlColumnEncryptionKeyEncryptedValue cmdlet is only available in PowerShell 5&lt;/code&gt; which is available in Windows only. Please run the following commands to create the encrypted value of a column encryption key by using &lt;strong&gt;PowerShell 5 in Windows&lt;/strong&gt;. - As of Aug 2022)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cmkSettings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-SqlAzureKeyVaultColumnMasterKeySettings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KeyUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://kv-ayhara-sample-ado.vault.azure.net/keys/CMKAuto1/ecffa3fdcb2f432b9b0b8474770ade38"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$encryptedValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-SqlColumnEncryptionKeyEncryptedValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TargetColumnMasterKeySettings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$cmkSettings&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="nv"&gt;$encryptedValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Clipboard&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As with CMK, we need to add script as item.&lt;br&gt;
&lt;a href="https://media.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%2Fnlccul0vffl8nk2b13f2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnlccul0vffl8nk2b13f2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then use the following Transact-SQL with the encrypted value which we just copied above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;ENCRYPTION&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CEK_Auto1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;COLUMN_MASTER_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CMK_Auto1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
     &lt;span class="n"&gt;ALGORITHM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'RSA_OAEP'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;ENCRYPTED_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x01B6000001&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;h1&gt;
  
  
  4. Create table with encrypted columns &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let's say we creates a table named &lt;code&gt;User&lt;/code&gt;, with columns named &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt;, and that the password column is &lt;strong&gt;encrypted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Add table&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.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%2F8ms9teg9w72xeqndfg33.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ms9teg9w72xeqndfg33.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then put &lt;code&gt;User&lt;/code&gt; in the field and press &lt;code&gt;Enter&lt;/code&gt; to confirm.&lt;br&gt;
&lt;a href="https://media.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%2Fxs383e0n47j4zjqsff9k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs383e0n47j4zjqsff9k.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the following Transact-SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;(&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;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="k"&gt;ENCRYPTED&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COLUMN_ENCRYPTION_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CEK_Auto1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;ENCRYPTION_TYPE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RANDOMIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;ALGORITHM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'AEAD_AES_256_CBC_HMAC_SHA_256'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  5. Build/Publish with Data Studio &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;After creating the Data Project, the first step is to build it.&lt;br&gt;
Right-click on &lt;code&gt;DB&lt;/code&gt; and select &lt;code&gt;Build&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Febl43a41q1vuse7gnx67.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febl43a41q1vuse7gnx67.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once build succeeded now we're ready to publish it to database.&lt;br&gt;
If the build fails, saving all files once and reopening the sqlproj file again in data studio may help.&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Publish&lt;/code&gt;,&lt;br&gt;
&lt;a href="https://media.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%2Fwg4k3gfxxnxqqeofgjew.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg4k3gfxxnxqqeofgjew.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and select connection.&lt;br&gt;
&lt;a href="https://media.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%2Fb75ma0dchr90wyv1rdnu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb75ma0dchr90wyv1rdnu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to put all required connection details here and click &lt;code&gt;Connect&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Fznd4peq0bx2tetdv657k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznd4peq0bx2tetdv657k.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If Server and Database are set as expected, then publish it.&lt;br&gt;
&lt;a href="https://media.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%2Fpvwuj5pdfxrf0fppkx6h.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvwuj5pdfxrf0fppkx6h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please confirm that 'Deploy dacpac succeeded' is displayed in the Window.&lt;/p&gt;
&lt;h1&gt;
  
  
  6. Confirm the result&lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let's see if the database is configured as expected.&lt;br&gt;
Go to Connection pane in Data Studio and click new query.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4frl83lsz1w7bjxkzwv2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4frl83lsz1w7bjxkzwv2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can confirm it by running the following Transact-SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_master_keys&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_master_key_definitions&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_encryption_keys&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_encryption_key_values&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;encryption_type_desc&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_columns&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Password'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, we can also add data and retrieve plaintext values stored in encrypted columns.&lt;br&gt;
Firstly, enabling Always Encrypted for a database connection.&lt;br&gt;
Right-click on the server name and select &lt;code&gt;Edit Connection&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Flx1nbkoontjp2g11x7oj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx1nbkoontjp2g11x7oj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Advanced Properties&lt;/code&gt; on the lower right,&lt;br&gt;
&lt;a href="https://media.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%2Fy08ff02iebpzy10fduqu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy08ff02iebpzy10fduqu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change Always Encrypted in the Security section to &lt;code&gt;Enabled&lt;/code&gt; and press OK.&lt;br&gt;
&lt;a href="https://media.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%2Fhrxnv9sgljk56nqi8s3l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrxnv9sgljk56nqi8s3l.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, enable Parameterization for Always Encrypted. (Ref - &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-query-columns-ads?view=sql-server-ver16#parameterization-for-always-encrypted" rel="noopener noreferrer"&gt;Parameterization for Always Encrypted&lt;/a&gt;)Parameterization for Always Encrypted is disabled by default.&lt;br&gt;
Click on the Manage icon and open &lt;code&gt;Settings&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Fbr71xcihfhg8bjjndr0o.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbr71xcihfhg8bjjndr0o.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Use the search box and set Enable Parameterization for Always Encrypted.&lt;br&gt;
&lt;a href="https://media.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%2Fw5pt2foxm5qynuttsii5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5pt2foxm5qynuttsii5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, let's add the actual data and see the result. For instance, add sample data as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&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;Password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Ayaka'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ccixm2hzqcs32do9nkc.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ccixm2hzqcs32do9nkc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How DACPAC looks like? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A data-tier application (DAC) is a logical database entity that defines all of the SQL Server objects - such as tables, views, and instance objects, including logins - associated with a user's database. A DAC is a self-contained unit of the entire database model and is portable in an artifact known as a DAC package, or .dacpac. Please refer to &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/data-tier-applications?view=sql-server-ver16" rel="noopener noreferrer"&gt;official document&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;We can export DACPAC with Data Studio.&lt;br&gt;
Firstlly, &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-server-dacpac-extension?view=sql-server-ver16" rel="noopener noreferrer"&gt;SQL Server dacpac extension&lt;/a&gt; should be installed.&lt;br&gt;
&lt;a href="https://media.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%2Far1ju9xbv3i2vkojt94l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far1ju9xbv3i2vkojt94l.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;Connections&lt;/code&gt; tab and click &lt;code&gt;Data-tier Application Wizard&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Fq930zwbs1z680o3d7u29.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq930zwbs1z680o3d7u29.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 1 : Select &lt;code&gt;Extract a data-tier application&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Ff8e46ql9r5cxvbugmcjd.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8e46ql9r5cxvbugmcjd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2 : Select extract DACPAC settings.&lt;br&gt;
&lt;a href="https://media.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%2F5qdy78ebp1tlgw6tmfuj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qdy78ebp1tlgw6tmfuj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 3 : If the contents of the Summary are as expected, click &lt;code&gt;Extract&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.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%2Fu263sao6npr433snxxcp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu263sao6npr433snxxcp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the dacpac file is created at the specified location, compress it by appending .zip after .dacpac.&lt;br&gt;
&lt;a href="https://media.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%2F710uoo7duqfx8suw9vec.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F710uoo7duqfx8suw9vec.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Extract the zip file and open it in Editor such as Visual Studio Code. We can see that DACPAC consists of four files: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/visualstudio/extensibility/the-structure-of-the-content-types-dot-xml-file?view=vs-2022" rel="noopener noreferrer"&gt;[Content_Types].xml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DacMetadata.xml&lt;/li&gt;
&lt;li&gt;model.xml&lt;/li&gt;
&lt;li&gt;Origin.xml&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;model.xml contains information on CMK, CEK, and columns which we just configured.&lt;br&gt;
&lt;a href="https://media.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%2Fbbjpckaotnu1kul0uojv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbjpckaotnu1kul0uojv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Always Encrypted is a great feature when Azure SQL Server is used. As I introduced above it can be configured by the Data Studio extension, which is currently in preview, even if we are using MacOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  References&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver16" rel="noopener noreferrer"&gt;Download and install Azure Data Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/what-is-azure-data-studio?view=sql-server-ver16#feature-comparison-with-sql-server-management-studio-ssms" rel="noopener noreferrer"&gt;Feature comparison with SQL Server Management Studio (SSMS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-query-columns-ads?view=sql-server-ver16" rel="noopener noreferrer"&gt;Query columns using Always Encrypted with Azure Data Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-database-project-extension?view=sql-server-ver16" rel="noopener noreferrer"&gt;SQL Database Projects extension (Preview)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-server-dacpac-extension?view=sql-server-ver16" rel="noopener noreferrer"&gt;SQL Server dacpac extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/data-tier-applications?view=sql-server-ver16" rel="noopener noreferrer"&gt;Data-tier applications (DAC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>sql</category>
      <category>security</category>
    </item>
    <item>
      <title>Query table data in Azure Data Explorer with Kusto to analyse load test results</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Thu, 19 Aug 2021 03:11:19 +0000</pubDate>
      <link>https://dev.to/aykhara/query-table-data-in-azure-data-explorer-with-kusto-to-analyse-load-test-results-1b93</link>
      <guid>https://dev.to/aykhara/query-table-data-in-azure-data-explorer-with-kusto-to-analyse-load-test-results-1b93</guid>
      <description>&lt;p&gt;There are situations where we want to query Table data, such as analysing load test results.&lt;br&gt;
Since the maximum number of entities* that are returned in a single query with LINQ Take operator is 1,000 (&lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/writing-linq-queries-against-the-table-service#returning-the-top-n-entities" rel="noopener noreferrer"&gt;Ref - Returning the Top n Entities&lt;/a&gt;), you may need to code more to retrieve what you want.&lt;/p&gt;

&lt;p&gt;*Entities are sets of properties and can be thought of like rows in a database. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsangh2tby4gf8q30918h.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsangh2tby4gf8q30918h.png" alt="architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LINQ has an upper limit of 1000, while Data Explorer with Kusto allows to query large numbers of entities.&lt;/p&gt;

&lt;p&gt;In this article, how to query with Kusto in Azure Data Explorer (ADX) will be explained in particular.&lt;/p&gt;
&lt;h3&gt;
  
  
  TOC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pre-requisites&lt;/li&gt;
&lt;li&gt;Objective&lt;/li&gt;
&lt;li&gt;Example table data&lt;/li&gt;
&lt;li&gt;Kusto queries to calculate processing time&lt;/li&gt;
&lt;li&gt;Result&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Reference&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Pre-requisites &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;First of all, you need to complete the steps to ingest data from Table Storage into Data Explorer via Data Factory to prepare to query large numbers of entities with Kusto.&lt;br&gt;
Please refer to &lt;a href="https://dev.to/aykhara/ingest-data-from-azure-table-storage-into-data-explorer-133c"&gt;the post "Ingest data from Azure Table Storage into Data Explorer"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once done with the steps above, you're ready to query data ingested from Azure Table Storage with Kusto.&lt;/p&gt;
&lt;h1&gt;
  
  
  Objective &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;In this article, I will use an example from &lt;a href="https://dev.to/aykhara/cost-comparison-between-azure-services-to-determine-architecture-579o"&gt;the post "Cost comparison between Azure services to determine architecture"&lt;/a&gt; to illustrate how to query Table data with Kusto. &lt;/p&gt;

&lt;p&gt;The purpose of querying the table data here is to make sure that one of the requirements, &lt;strong&gt;the processing time between device and storage is less than 10 seconds&lt;/strong&gt;, is met.&lt;/p&gt;
&lt;h1&gt;
  
  
  Example table data &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let's see how an example table data looks like. It is assumed that there are around 1.2 million entities adding into a single table.&lt;/p&gt;

&lt;p&gt;Table Name : telemetry202108180820&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PartitionKey&lt;/th&gt;
&lt;th&gt;RowKey&lt;/th&gt;
&lt;th&gt;Timestamp&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;992c9af9-b490-44cd-bf95-d9fa61bc3aa4&lt;/td&gt;
&lt;td&gt;abcdefghigklmn&lt;/td&gt;
&lt;td&gt;2021-08-18T10:33:25.355Z&lt;/td&gt;
&lt;td&gt;{&lt;br&gt;"deviceId": "992c9af9-b490-44cd-bf95-d9fa61bc3aa4",&lt;br&gt;"connectivity": "Online",&lt;br&gt;"eventType": "Telemetry",&lt;br&gt;"timestamp": "2021-08-18T19:12:08.1844379+09:00",&lt;br&gt;"telemetry": {&lt;br&gt;"6E8E2CE5-3A7D-4997-9056-297BAD62C601":&lt;br&gt;"12345678901234567890123456789",&lt;br&gt;"1023EF00-093C-4702-886F-6C9C8B4D3102":&lt;br&gt;"12345678901234567890123456789",&lt;br&gt;...&lt;br&gt;}&lt;br&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c06145f6-7843-420c-ae80-fc52710198b5&lt;/td&gt;
&lt;td&gt;abcdefghigklmn&lt;/td&gt;
&lt;td&gt;2021-08-18T10:33:25.433Z&lt;/td&gt;
&lt;td&gt;{&lt;br&gt;"deviceId": "c06145f6-7843-420c-ae80-fc52710198b5",&lt;br&gt;"connectivity": "Online",&lt;br&gt;"eventType": "Telemetry",&lt;br&gt;"timestamp": "2021-08-18T19:12:08.1933468+09:00",&lt;br&gt;"telemetry": {&lt;br&gt;"6E8E2CE5-3A7D-4997-9056-297BAD62C601":&lt;br&gt;"12345678901234567890123456789",&lt;br&gt;"1023EF00-093C-4702-886F-6C9C8B4D3102":&lt;br&gt;"12345678901234567890123456789",&lt;br&gt;...&lt;br&gt;}&lt;br&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;timestamp in column Data&lt;/strong&gt; is the time when telemetry message is sent from each device. &lt;strong&gt;Column Timestamp&lt;/strong&gt; is the time when telemetry message is ingested into Table Storage after processing it with Function App.&lt;br&gt;
These timestamp data will be used to calculate processing time between device and table storage.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86rf9ya01i1n0nl2azln.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86rf9ya01i1n0nl2azln.png" alt="Data_Timestamp"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Kusto queries to calculate processing time &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Here is an example of Kusto queries to calculate processing time between device and table storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telemetry202108180820
| project data = parse_json(Data), ingestedTime = Timestamp
| project generatedTime = todatetime(data, timestamp), ingestedTime
| project diff = datetime_diff("Millisecond", ingestedTime, generatedTime)
| summarize avg(diff), max(diff), min(diff), percentiles(diff, 5, 90, 99)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each step is doing will be explained as the following.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Reference to a table
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telemetry202108180820
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The statement starts with a reference to a table. In this article, the table 'telemetry202108180820' is being used as shown in the example table data section above.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Interpret column Data as a JSON
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| project 
    data = parse_json(Data), // Interpret column Data as a JSON and rename it to data
    ingestedTime = Timestamp // Rename column Timestamp to ingestedTime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;'project' is an operator to select the columns to include, rename or drop, and insert new computed columns.&lt;/p&gt;

&lt;p&gt;In the example here, Data is a string and it needs to be interpreted as a JSON value to extract just some properties from the JSON column later.&lt;br&gt;
Also, column Timestamp is renamed to ingestedTime to clarify the difference from another timestamp.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Convert timestamp in column Data to datetime
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| project 
    generatedTime = todatetime(data, timestamp), // Convert timestamp in column data to datetime scalar and rename it to generatedTime
    ingestedTime // Include ingestedTime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;'todatetime' is a function to convert input to datetime scalar. Timestamp in column data is renamed to generatedTime after converting with 'todatetime' function.&lt;br&gt;
ingestedTime which was renamed above is also included again.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Calculates calendarian difference between two datetime values
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| project 
    diff = datetime_diff("Millisecond", ingestedTime, generatedTime) // Calculates calendarian difference (millisecond) between two datetime values: ingestedTime and generatedTime, and rename it to diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;'datetime_diff' is a function to calculates calendarian difference between two datetime values.&lt;br&gt;
By calculating the difference in millisecond between the ingestedTimeand (when telemetry message is ingested into Table Storage) and the geteratedTime (when telemetry message is sent from each device), the processing time can be obtained. The value is renamed to diff.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Produce a table with aggregation functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| summarize 
    avg(diff), 
    max(diff), 
    min(diff), 
    percentiles(diff, 5, 50, 90, 99) // Produce a table including the average, maximum, minimum, percentile approximate of diff which is calendarian difference (millisecond) between ingestedTime and generatedTime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;'summarize' is an operator to produce a table that aggregates the content of the input table.&lt;br&gt;
As an example, the following four aggregation functions are used.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;avg : Returns an average value across the group&lt;/li&gt;
&lt;li&gt;max : Returns the maximum value across the group&lt;/li&gt;
&lt;li&gt;min : Returns the minimum value across the group&lt;/li&gt;
&lt;li&gt;percentiles : Returns the percentile approximate of the group&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Result &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Here is the result of the Kusto queries explained ealier. The average is about 5,023 milliseconds which means 5.023 seconds. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffm1azdj7a06sn31ukxi4.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffm1azdj7a06sn31ukxi4.png" alt="ADX_ProcessingTime_Average_result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result shows that the requirement which the processing time between device and storage should be less than 10 seconds.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This is just an example of how to query table data in Azure Data Explorer with Kusto to analyse load test results.&lt;br&gt;
If you want to retrieve/query large numbers of entities from Table Storage, much more than 1000, one way to do it is to use Kusto instead of LINQ.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reference &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/writing-linq-queries-against-the-table-service#returning-the-top-n-entities" rel="noopener noreferrer"&gt;Writing LINQ queries against the Table service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/" rel="noopener noreferrer"&gt;Overview - Kusto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/projectoperator" rel="noopener noreferrer"&gt;project operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/parsejsonfunction" rel="noopener noreferrer"&gt;parse_json()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/todatetimefunction" rel="noopener noreferrer"&gt;todatetime()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/datetime-difffunction" rel="noopener noreferrer"&gt;datetime_diff()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/summarizeoperator" rel="noopener noreferrer"&gt;summarize operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aykhara/ingest-data-from-azure-table-storage-into-data-explorer-133c"&gt;Ingest data from Azure Table Storage into Data Explorer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aykhara/cost-comparison-between-azure-services-to-determine-architecture-579o"&gt;Cost comparison between Azure services to determine architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
    </item>
    <item>
      <title>Cost comparison between Azure services to determine architecture</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Tue, 10 Aug 2021 05:54:32 +0000</pubDate>
      <link>https://dev.to/aykhara/cost-comparison-between-azure-services-to-determine-architecture-579o</link>
      <guid>https://dev.to/aykhara/cost-comparison-between-azure-services-to-determine-architecture-579o</guid>
      <description>&lt;p&gt;Cost is an important factor to consider when developing a cloud-based solution. The main purpose of cost estimation is to determine the architecture and to predict the future costs.&lt;/p&gt;

&lt;p&gt;First of all, let's take a look at the finalized architecture from the cost estimation results as well as project's specific requirements in the case we are going to use as an example.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mzmyuoznxoqsfh7lq1v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mzmyuoznxoqsfh7lq1v.png" alt="Determined architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I will explain how the cost estimation was done to determine this architecture, with actual data and requirements from a real project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : The content of this article is as of August 2021. The cost was calculated using "Pay as you go" rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  TOC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Requirements for cost estimation

&lt;ul&gt;
&lt;li&gt;1. Projected amount of data in the future&lt;/li&gt;
&lt;li&gt;2. Data storage&lt;/li&gt;
&lt;li&gt;3. Budget&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Architecture options&lt;/li&gt;

&lt;li&gt;

Cost comparison

&lt;ul&gt;
&lt;li&gt;
1. Where to send : IoT Hub vs Event Hubs

&lt;ul&gt;
&lt;li&gt;Selection criteria&lt;/li&gt;
&lt;li&gt;How to calculate&lt;/li&gt;
&lt;li&gt;Tips&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

2. Where to process : Stream Analytics vs Functions

&lt;ul&gt;
&lt;li&gt;Selection criteria&lt;/li&gt;
&lt;li&gt;How to calculate&lt;/li&gt;
&lt;li&gt;Tips&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

3. Where to persist : CosmosDB vs Table Storage

&lt;ul&gt;
&lt;li&gt;Selection criteria&lt;/li&gt;
&lt;li&gt;How to calculate&lt;/li&gt;
&lt;li&gt;Tips&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Other option : Data Explorer&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Result summary&lt;/li&gt;

&lt;li&gt;Importance of load testing&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;li&gt;References&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Requirements for cost estimation &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1. Projected amount of data in the future &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We perform cost estimation using projected scale information for the future, such as several years from now. The reason for this is that if we use the most recent data, scalability may not be able to be taken into account, or if the amount of data increases, the cost may greatly exceed the budget and the architecture may need to be reexamined.&lt;/p&gt;

&lt;p&gt;In this article, the projected data is going to be used as an example for cost estimation.&lt;/p&gt;

&lt;p&gt;The assumption in this example is that telemetry messages from 10 devices are consolidated into one array and it is sent to one connector, which then goes to Azure.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy5p3s775fhf7cuf90go.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy5p3s775fhf7cuf90go.png" alt="Telemetry messages from 10 devices is sent to one connector and then goes to Azure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Actual telemetry data
&lt;/h4&gt;

&lt;p&gt;Here is the example of how telemetry messages sent to Azure look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ffee4208-eaca-4f7b-8882-fee956b3776a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"connectivity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Online"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Telemetry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deviceTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-07-16T13:34:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"connectorTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-07-16T13:34:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"telemetryData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"6E8E2CE5-3A7D-4997-9056-297BAD62C617"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="err"&gt;KB&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"1023EF00-093C-4702-886F-6C9C8B4D3169"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"46B219AF-E355-479D-B02C-274E09A38BDC"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.234"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"44B5EF8A-0F54-4DBC-A343-58828892E2D2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"connectivity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Online"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Telemetry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deviceTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-07-16T13:34:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"connectorTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-07-16T13:34:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"telemetryData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="nl"&gt;"2F91F10F-63BC-4E84-A72D-95BABB37C155"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="err"&gt;KB&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"CB7C127D-D3EB-475F-9FCB-0F721B582C58"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"4ADE8439-961D-493D-B306-D2567F87429A"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.234"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned inline above, the data size of each data point could be up to 0.05KB (= 50Byte) and each device sends up to 50 data points (messages). In addition, messages from 10 devices are consolidated into one array. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45fp9zak4z847upczhqb.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45fp9zak4z847upczhqb.png" alt="Formula to calculate 1 message size"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This maximum size should be applied when cost is estimated.&lt;/p&gt;

&lt;h4&gt;
  
  
  Number of devices
&lt;/h4&gt;

&lt;p&gt;10 devices are connected to a connector. The total number of devices will expect to be 2000 which means there will be 200 connectors.&lt;/p&gt;

&lt;h4&gt;
  
  
  Frequency
&lt;/h4&gt;

&lt;p&gt;Telemetry messages for 10 devices are bundled together in connector units and sent every second.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data storage &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Keep data for a certain period of time
&lt;/h4&gt;

&lt;p&gt;Telemetry messages (raw data) are required to be kept for a certain period of time in hot/warm storage without deleting them since creating summaries and querying them frequently are planned.&lt;/p&gt;

&lt;p&gt;In this article, the cost will be calculated assuming that the data is retained for 48 hours as an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Budget &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Compared with competitors
&lt;/h4&gt;

&lt;p&gt;It is important to consider differences in both cost and functionality when comparing services. We modeled different usage scenarios representing differences in data volumes, frequency and data retention. Competing services' end-user pricing was used as a guide to determine the budget for our solution.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxozwokyug45ffbz34gi3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxozwokyug45ffbz34gi3.png" alt="Budget for Azure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Architecture options &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Now it's time to go through the cost comparison and decide on the architecture.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlfpb1ar8gv4g1wicjzy.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlfpb1ar8gv4g1wicjzy.png" alt="Architecture options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For comparison, the architecture of the Azure part will be divided into three major categories.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Where to send&lt;br&gt;
Compare IoT Hub and Event Hubs to see where to receive per-connector telemetry messages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where to process&lt;br&gt;
Compare Stream Analytics and Functions to see where telemetry messages sent in bulk by connector are decomposed to per device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where to persist&lt;br&gt;
Compare Cosmos DB and Table Storage to see where to store per-device telemetry messages.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The architecture decision was not based on solely on cost but also on project's specific requirements. Those requirements were explained in each selection criteria below.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost comparison &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This estimation will be based on the projected data volume and number of devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Where to send : IoT Hub vs Event Hubs &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Selection criteria &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A message size : 25KB&lt;/li&gt;
&lt;li&gt;Frequency : telemetry message from 200 connectors sent every second&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  How to calculate &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  IoT Hub
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Step 1 : Basic or Standard tier
&lt;/h6&gt;

&lt;p&gt;Firstly you need to decide which tier you want to use.&lt;br&gt;
In this project, Cloud-to-Device messaging is planning to be used in the future. Since Basic tier does not support that feature Standard tier is selected this time.&lt;/p&gt;

&lt;p&gt;Please refer to &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-scaling?branch=release-iotbasic" rel="noopener noreferrer"&gt;the document - Choose the right IoT Hub tier for your solution&lt;/a&gt; for more detailed information.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Number of messages per day
&lt;/h6&gt;

&lt;p&gt;Next, the amount of messages sent to the IoT Hub per day should be calculated.&lt;br&gt;
As mentioned earlier, a message is sent every second per connector, which means 200 messages are sent every second. The formula is as shown below.&lt;br&gt;
&lt;a href="https://media.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%2Fdh6ic86hkvl4sgb4w6eg.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdh6ic86hkvl4sgb4w6eg.png" alt="Formula to calculate number of messages per day"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 3 : Number of billing messages per day
&lt;/h6&gt;

&lt;p&gt;Then the amount of &lt;strong&gt;billing&lt;/strong&gt; messages sent to the IoT Hub per day should be calculated.&lt;br&gt;
The message meter size for both the Standard and Basic tiers is 4KB. (&lt;a href="https://azure.microsoft.com/en-us/pricing/details/iot-hub/" rel="noopener noreferrer"&gt;Ref - IoT Hub pricing&lt;/a&gt;)&lt;br&gt;
As mentioned above, since messages from 10 devices are consolidated into one array a message size per connector is 25KB. &lt;br&gt;
Based on the above information, the formula is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4ckoy1krrpnfk3sx2lo.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4ckoy1krrpnfk3sx2lo.png" alt="Formula to calculate number of billing messages per day"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 4 : Edition Type, Number of units
&lt;/h6&gt;

&lt;p&gt;There are three edition types under Standard tier : S1, S2, and S3. Each edition type has the limitation of total number of messages per day per IoT Hub unit. (&lt;a href="https://azure.microsoft.com/en-us/pricing/details/iot-hub/" rel="noopener noreferrer"&gt;Ref - IoT Hub pricing&lt;/a&gt;)  &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihhcqakjplfqj4jy225n.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihhcqakjplfqj4jy225n.png" alt="List of total number limitation of messages per day per IoT Hub unit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the above information, the formula to calculate the number of units required respectively ​is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnl33uvpph2m1vdtea4b.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnl33uvpph2m1vdtea4b.png" alt="Formula to calculate the number of units required and the cost of IoT Hub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Event Hubs
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Step 1 : Basic, Standard or Dedicated tier
&lt;/h6&gt;

&lt;p&gt;Since the max retention period for the Basic tier is 1 day, Standard tier needs to be selected to retain data for 48 hours.&lt;/p&gt;

&lt;p&gt;If Event Hubs events are retained for up to 90 days the Dedicated tier should be selected.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Ingress events
&lt;/h6&gt;

&lt;p&gt;Since 200 connectors send telemetry messages every second, the number of ingress events per month can be calculated by multiplying the number of connectors by the number of seconds per month.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcipvs305rrd6bpicy6t.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcipvs305rrd6bpicy6t.png" alt="Formula to calculate the number of ingress events per month"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 3 : Throughput units
&lt;/h6&gt;

&lt;p&gt;Then, the message size is multiplied by the number of connectors to calculate the ingress data size per second. In practice, in addition to the 25KB message size, the system message size and other factors need to be taken into account. Therefore, the total is calculated to be 6TU since 1TU is required for every 1000KB.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiseizzh1rg1xnu8adgc6.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiseizzh1rg1xnu8adgc6.png" alt="Formula to calculate the ingress data size per second and throughput units required"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 4 (Optional) : Capture feature
&lt;/h6&gt;

&lt;p&gt;The Azure Event Hubs Capture feature automatically processes and stores event data in your Azure storage account. The price is based on the number of Throughput Units selected for the Event Hubs. This time capture feature is not applied.&lt;br&gt;
For more information, please see &lt;a href="https://azure.microsoft.com/en-us/pricing/details/event-hubs/" rel="noopener noreferrer"&gt;the pricing details page&lt;/a&gt;.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F141v5mfxx83j7gc40tey.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F141v5mfxx83j7gc40tey.png" alt="Formula to calculate the cost of Event Hubs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Tips 1 - IoT Hub : Increase in cost
&lt;/h5&gt;

&lt;p&gt;The cost does not increase in proportion to the amount of data, but rather in a staircase pattern.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tips 2 - IoT Hub: Number of connectors allowed in S3 and calculation method
&lt;/h5&gt;

&lt;p&gt;The number of Connectors allowed in 1 unit of S3 is 555. The formula is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan5h0zlryqktalee8kr7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan5h0zlryqktalee8kr7.png" alt="Formula to calculate the number of Connectors allowed in 1 unit of S3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means, of course, that the cost per connector will be lower when 555 connectors are used than when 200 connectors are used.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tips 3 - Event Hubs: Consider the Auto-Inflate setting
&lt;/h5&gt;

&lt;p&gt;Event Hubs traffic is controlled by TUs (standard tier). For the limits such as ingress and egress rates per TU, see &lt;a href="https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas" rel="noopener noreferrer"&gt;Event Hubs quotas and limits&lt;/a&gt;.&lt;br&gt;
Auto-inflate enables you to start small with the minimum required TUs you choose. The feature then scales automatically to the maximum limit of TUs you need, depending on the increase in your traffic. Auto-inflate provides the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An efficient scaling mechanism to start small and scale up as you grow.&lt;/li&gt;
&lt;li&gt;Automatically scale to the specified upper limit without throttling issues.&lt;/li&gt;
&lt;li&gt;More control over scaling, because you control when and how much to scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Auto-Inflate is a &lt;strong&gt;scale-up only&lt;/strong&gt; feature. It will not automatically scale down.&lt;/p&gt;

&lt;p&gt;More informations is available &lt;a href="https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate#enable-auto-inflate-through-the-portal" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tips 4 - Event Hubs: Increase in cost
&lt;/h5&gt;

&lt;p&gt;As with IoT Hub, the cost does not increase in proportion to the amount of data, but rather in a staircase pattern.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tips 5 - Compare IoT Hub and Event Hubs
&lt;/h5&gt;

&lt;p&gt;While the IoT Hub can manage devices and provide two-way communication (C2D, D2C), the Event Hubs can only provide one-way communication. Thus, when choosing Event Hubs, it is another option to use it together with S1 of IoT Hub and security should also be considered.&lt;/p&gt;

&lt;p&gt;Please refer to &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-compare-event-hubs" rel="noopener noreferrer"&gt;Connecting IoT Devices to Azure: IoT Hub and Event Hubs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Where to process : Stream Analytics vs Functions &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Selection criteria &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A message size : 25KB&lt;/li&gt;
&lt;li&gt;Frequency : telemetry message from 200 connectors sent every second&lt;/li&gt;
&lt;li&gt;Processing details :

&lt;ul&gt;
&lt;li&gt;Decompose telemetry messages from per connector to per device (i.e. 200 messages from connectors to 2000 messages from devices)&lt;/li&gt;
&lt;li&gt;Save telemetry messages to specified storage dynamically&lt;/li&gt;
&lt;li&gt;The processing time between device and storage should be within 10 seconds&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  How to calculate &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Stream Analytics
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Step 1 : Standard or Dedicated plan
&lt;/h6&gt;

&lt;p&gt;There are two plans: Standard and Dedicated.&lt;br&gt;
For Dedicated plan, at least 36 streaming units (SUs) are required. Therefore, Standard plan is selected.&lt;/p&gt;

&lt;p&gt;Please refer to &lt;a href="https://azure.microsoft.com/en-us/pricing/details/stream-analytics/" rel="noopener noreferrer"&gt;Standard streaming unit section in the pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Number of streaming units (SUs)
&lt;/h6&gt;

&lt;p&gt;Choosing how many SUs are required for a particular job depends on the partition configuration for the inputs and on the query defined for the job. You can select up to your quota in SUs for a job. By default, each Azure subscription has a quota of up to 500 SUs for all the analytics jobs in a specific region. &lt;br&gt;
Valid values for SUs per job are 1, 3, 6, and up in increments of 6.&lt;/p&gt;

&lt;p&gt;The keys to determining the appropriate SU from load testing are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SU% utilization should not greater than 80% (must be less than 80%)&lt;/li&gt;
&lt;li&gt;Any backlogged input events should not be occurring (slowly increasing or non-zero) 
In this case, the workload may require more computing resources, and the number of units needs to be increased.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please refer to &lt;a href="https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-streaming-unit-consumption" rel="noopener noreferrer"&gt;Understand and adjust Streaming Units&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Load testing should be conducted to determine how many SUs are needed.&lt;/p&gt;

&lt;p&gt;Let's see how we checked the metrics to determine the number of SUs required when we conducted our load tests. We performed load tests on 1, 3, 6, 12, and 24 SUs respectively.&lt;/p&gt;

&lt;p&gt;Here are the metrics for the 3 SUs as an example.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4aaxw2z4nm6yhwpjr70.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4aaxw2z4nm6yhwpjr70.png" alt="Metics for 3SUs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown in the figure above, SU % utilization is 52%, which means that it meets the criteria of less than 80%.&lt;br&gt;
Watermark delay is the time stream got out minus the time stream got in. 3 SUs had a maximum delay of 3.18 min.&lt;br&gt;
Backlogged Input Event should be as close to 0 as possible. If not 0, it means that the number of SUs is not enough for the job. For 3 SUs, the backlogged input event was a large 5.95k, indicating that the processing was not able to keep up.&lt;/p&gt;

&lt;p&gt;The table below summarizes the results for the other patterns.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtjje0b3kow3gf0cnq26.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtjje0b3kow3gf0cnq26.png" alt="Comparison of SUs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a result of the load testing in our case, we found out that 6 SUs are required for the Standard plan.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwrmqcvuf1e9iulyj8pk.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwrmqcvuf1e9iulyj8pk.png" alt="Formula to calculate the cost of Stream Analytics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Additional required step : Consider combining services to save to a specified table name dynamically
&lt;/h6&gt;

&lt;p&gt;Stream Analytics has limited flexibility in export destination and cannot dynamically save to a specified table. Therefore, other services need to be combined to achieve that. In our project, we selected Functions and conducted load testing in combination with Stream Analytics.&lt;/p&gt;

&lt;p&gt;The cost of the Functions required to dynamically save to the specified table is shown in the figure below (The detailed costing method is described in the next section).&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3zd7m9qth1dw9zhruhs.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3zd7m9qth1dw9zhruhs.png" alt="Formula to calculate the cost of Functions (App Service plan)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just as explained above, if you choose Stream Analytics, you will need to combine it with Functions, which will cost you the sum of the costs of both services.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjfxbfufyxxkaw4drx43.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjfxbfufyxxkaw4drx43.png" alt="Formula to calculate the cost of Stream Analytics and Functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Functions
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Step 1 : Consumption, Premium or App Service Plan
&lt;/h6&gt;

&lt;p&gt;In our case, the system will potentially be scaled down or switched off periodically to reduce cost. Therefore, the consumption plan is not an option because it cannot be set to &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/dedicated-plan#always-on" rel="noopener noreferrer"&gt;Always on&lt;/a&gt; and will result in a cold start.&lt;br&gt;
Cold start is a term used to describe the phenomenon that applications which haven’t been used take longer to start up. In other words, a cold start is an increase in latency for Functions which haven’t been called recently. The Always on setting is available only on an App Service plan, which means that cold start isn’t really an issue.&lt;/p&gt;

&lt;p&gt;As for the Premium plan, it can avoid cold starts with perpetually warm instances. (&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal" rel="noopener noreferrer"&gt;Ref: Azure Functions Premium plan&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In our case, the cold start issue in  needs to be avoided since the system may be scaled down or switched off periodically to reduce cost.&lt;/p&gt;

&lt;p&gt;Based on the above, we will compare the premium plan and app service plan in the next step.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Instance, Number of instances
&lt;/h6&gt;

&lt;p&gt;Load testing should be conducted to determine which instance to use and how many instances are needed.&lt;/p&gt;

&lt;p&gt;The following are some examples of points to check the metrics in Functions during load test execution. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if all the messages you sent are processed&lt;/li&gt;
&lt;li&gt;Check if the CPU usage rate is not over 80%&lt;/li&gt;
&lt;li&gt;Check if the memory is settled&lt;/li&gt;
&lt;li&gt;Check that the total execution count matches the number of inputs to the functions as expected&lt;/li&gt;
&lt;li&gt;Check if the average duration for processing in the functions is not too long&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result of the load test, we found out that the Premium plan requires 6 EP2 instances, and the App Service plan requires 4 P1v3 instances.&lt;br&gt;
The results of the cost estimation are as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzbcgat06vuhxa0p3wsw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzbcgat06vuhxa0p3wsw.png" alt="Formula to calculate the cost of Functions (Premium plan and App Service plan）"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aside from the cost, the Premium Plan was not able to process as stably as the App Service Plan even when it scaled out sufficiently.&lt;/p&gt;

&lt;p&gt;Therefore, when selecting Functions, setting up 4 P1v3 instances of the App Service Plan was the optimal option for us.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Tips 1 - Stream Analytics : Limited flexibility for output destinations
&lt;/h5&gt;

&lt;p&gt;For example, if you want to store your telemetry messages in appropriate tables created in 10-minute increments based on the timestamps contained in the telemetry messages, Stream Analytics alone will not be able to accomplish this. &lt;br&gt;
If you have a requirement to dynamically specify the destination table like our case mentioned above, you will need to use a different service together, which will increase the cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Where to persist : CosmosDB vs Table Storage &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Selection criteria &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Keep data for 48 hours&lt;/li&gt;
&lt;li&gt;Retrieve the latest n data&lt;/li&gt;
&lt;li&gt;2 regions (Japan East / Japan West) for redundant failure&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  How to calculate &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  CosmosDB
&lt;/h5&gt;

&lt;p&gt;I recommend using &lt;a href="https://cosmos.azure.com/capacitycalculator/" rel="noopener noreferrer"&gt;capacity planner&lt;/a&gt; to calculate the cost of Cosmos DB.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 1 : API
&lt;/h6&gt;

&lt;p&gt;There are multiple choices: SQL API, Cassandra API, Gremlin API, Table API and Azure Cosmos DB API for MongoDB etc.&lt;/p&gt;

&lt;p&gt;In this example, SQL API is selected.&lt;/p&gt;

&lt;p&gt;If you are using API for MongoDB, see how to &lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/estimate-ru-capacity-planner" rel="noopener noreferrer"&gt;use capacity calculator with MongoDB article&lt;/a&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Number of regions
&lt;/h6&gt;

&lt;p&gt;Azure Cosmos DB is available in all Azure regions. The number of regions required should be selected for your workload. &lt;/p&gt;

&lt;p&gt;In this example, the requirement is for two regions, Japan East and Japan West, so enter 2 as the number of regions. The conditions will be aligned since we have selected GRS for the Functions described later.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 3 : Total data stored in transactional store
&lt;/h6&gt;

&lt;p&gt;Total projected data stored(GB) in the transactional store in a single region.&lt;/p&gt;

&lt;p&gt;The data will be stored for 48 hours and then deleted, which means that 48 hours of data will always be stored in the storage. Thus, the calculation formula is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fno9tl8erj2w1dhxbi3z6.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fno9tl8erj2w1dhxbi3z6.png" alt="Formula to calculate the total data stored in transactional store in GB per month"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 4 : Expected size of items/documents
&lt;/h6&gt;

&lt;p&gt;The expected size of the data item (for example, document), ranging from 1 KB to 2 MB.&lt;/p&gt;

&lt;p&gt;As mentioned above, the data size of a per-device telemetry message is 2.5KB.&lt;/p&gt;

&lt;p&gt;However, you can only input data in units of 1KB into the capacity planner. Therefore, in this example, we will use 2KB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiny advice&lt;/strong&gt; : When manipulating the expected size of items/documents in the capacity planner, the key cursor can be used to change small values.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 5 : Number of Point reads/Creates/Updates/Deletes operations expected per second per region to calculate RU (Request Unit)
&lt;/h6&gt;

&lt;p&gt;The calculation of RU (Request Unit) for Azure Cosmos DB is not as simple as 2k docs x 1000 = 2000RU.&lt;/p&gt;

&lt;p&gt;I highly recommend to use &lt;a href="https://cosmos.azure.com/capacitycalculator/" rel="noopener noreferrer"&gt;capacity planner&lt;/a&gt; to calculate RU by imputing number of Point reads/Creates/Updates/Deletes operations expected per second per region.&lt;/p&gt;

&lt;p&gt;The following figure shows the result of the cost estimation after inputting the above information into the capacity planner.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftz94sdmqap9hsvdbyp4u.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftz94sdmqap9hsvdbyp4u.png" alt="Screenshot of capacity planner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Table Storage
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Step 1 : Redundancy
&lt;/h6&gt;

&lt;p&gt;First of all, you need to select the best redundancy option.&lt;br&gt;
There are 6 options :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locally redundant storage (LRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within a single physical location in the primary region, the data is copied three times synchronously.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zone-redundant storage (ZRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy data synchronously between the three Azure Availability Zones in the primary region.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;geo-redundant storage (GRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replicate synchronously three times (at one physical location) in the primary region using local redundant storage (LRS), and then asynchronously to the secondary region.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read-access geo-redundant storage (RA-GRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to geo-redundant storage (GRS), you have read access to data located in a secondary region. If the primary becomes unavailable, you can read the data from the secondary.&lt;br&gt;
RA-GRS is more expensive to use than GRS, but avoids data read downtime while the primary region is unavailable and a failover to the secondary region is performed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;geo-zone-redundant storage (GZRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replicate synchronously between the three Azure Availability Zones in the primary region using Zone Redundant Storage (ZRS), and then asynchronously to the secondary region. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read-access geo-zone-redundant storage (RA-GZRS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to geo-zone-redundant storage (GZRS), you have read access to data located in a secondary region. If the primary becomes unavailable, you can read the data from the secondary.&lt;br&gt;
Although the cost of using RA-GZRS is higher than GZRS, it is recommended to use RA-GZRS when even a small amount of downtime due to failover is not acceptable.&lt;/p&gt;

&lt;p&gt;You can find out more about each redundancy option &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-redundancy" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our case, we chose &lt;strong&gt;GRS&lt;/strong&gt;, an option that allows data redundancy in another region hundreds of kilometers away geographically, and is more available, and sustainable than LRS or ZRS.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 2 : Storage capacity in GB per month
&lt;/h6&gt;

&lt;p&gt;The data will be stored for 48 hours and then deleted, which means that 48 hours of data will always be stored in the storage. Thus, the calculation formula is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfav8itc2jaj19qj7c3d.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfav8itc2jaj19qj7c3d.png" alt="Formula to calculate storage capacity in GB per month"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 3 : Storage transactions
&lt;/h6&gt;

&lt;p&gt;$0.00036 per 10,000 transactions for tables will be charged. (&lt;a href="https://azure.microsoft.com/en-us/pricing/details/storage/tables/" rel="noopener noreferrer"&gt;Ref - Table Storage pricing&lt;/a&gt;)&lt;br&gt;
Any type of operation against the storage is counted as a transaction, including reads, writes, and deletes.&lt;/p&gt;

&lt;p&gt;Since we plan to delete the entire table at once, the number of delete operations is very small. Therefore, only write operations are counted here.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxf8y57uskqc3b9zfirl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxf8y57uskqc3b9zfirl.png" alt="Formula to calculate storage transactions per month"&gt;&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxo6vuyebvxapa2d1cihb.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxo6vuyebvxapa2d1cihb.png" alt="Formula to calculate the cost of Table Storage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Tips 1 - Table Storage : Easy to retrieve the n entities most recently added
&lt;/h5&gt;

&lt;p&gt;If you consider only the cost, Blob Storage is cheaper than Table Storage. The cost of Blob Storage (Standard/48 hours in hot/GRS) is as follows.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1c389uzneia8dduyzw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1c389uzneia8dduyzw.png" alt="Formula to calculate the cost of Blob Storage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, as mentioned in the selection criteria, there is a requirement to retrieve the latest n data, and Blob Storage, which is not searchable, is not suitable for this requirement.&lt;/p&gt;

&lt;p&gt;Please see more details about &lt;a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-design-patterns#log-tail-pattern" rel="noopener noreferrer"&gt;log tail pattern and the solution&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Tips 2 - Table Storage : Easy to delete a table instead of entities
&lt;/h5&gt;

&lt;p&gt;As mentioned in the selection criteria, telemetry data will be stored for 48 hours and then deleted. &lt;/p&gt;

&lt;p&gt;Another advantages of using Table Storage is that it allows you to delete a table from the database, instead of deleting it by entity. In other words, the cost of the operation is lower than the cost of deleting them entity by entity because it can be deleted by table.&lt;/p&gt;

&lt;p&gt;Please refer to &lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Delete-Table?redirectedfrom=MSDN" rel="noopener noreferrer"&gt;the document about deleting table&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other option : Data Explorer &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Data Explorer was also considered as an option that combines both where to process and where to persist.&lt;/p&gt;

&lt;p&gt;I recommend using &lt;a href="https://dataexplorer.azure.com/AzureDataExplorerCostEstimator.html" rel="noopener noreferrer"&gt;Azure Data Explorer (Kusto) Cost Estimator&lt;/a&gt; to calculate the cost of Data Explorer.&lt;br&gt;
The data collected per day is 2160000 KB (i.e. 0.00216TB). However, since the estimator does not allow to be entered less than 0.01TB, 0.01TB was entered. &lt;/p&gt;

&lt;p&gt;The result of the cost estimation shown below is the minimum cost of Data Explorer (when data is retained in hot for 48 hours) without any load testing.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffr3rimqi9oa1ve7yys3k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffr3rimqi9oa1ve7yys3k.png" alt="Screenshot of Azure Data Explorer Cost Estimator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance, Data Explorer may seem low cost, but again, it is the minimum cost to prepare two E2A_v4, the smallest machine. (&lt;a href="https://azure.microsoft.com/en-us/pricing/details/data-explorer/" rel="noopener noreferrer"&gt;Ref - Azure Data Explorer pricing&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Moreover, in our case, the cost estimate was made considering future scalability. However, it should also be noted that this cost will be incurred even when the amount of data is not much larger than this estimate.&lt;/p&gt;

&lt;p&gt;With Data Explorer, the more data you have, the greater the cost benefit. Also, &lt;br&gt;
since the powerful analysis function is one of the most attractive features, choosing Data Explorer should be considered appropriately depending on the requirements, such as analyzing the stored data.&lt;/p&gt;

&lt;h1&gt;
  
  
  Result summary &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;So far we have detailed the cost estimation for each service to determine the architecture. &lt;br&gt;
The data used in the cost estimation was the projected data.&lt;/p&gt;

&lt;p&gt;Let's go over the requirements and potential services for each part of the overall architecture again.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcej7iqcvinytbtv4n5ea.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcej7iqcvinytbtv4n5ea.png" alt="Architecture options with result"&gt;&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc0w68y8eaiz0r4a934k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc0w68y8eaiz0r4a934k.png" alt="Target in several years"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to send
&lt;/h3&gt;

&lt;p&gt;Event Hubs resulted in significantly lower costs than IoT Hub.&lt;br&gt;
However, as mentioned earlier, while the IoT Hub can manage devices and provide two-way communication (C2D, D2C), the Event Hubs can only provide one-way communication. Thus, when choosing Event Hubs, it is another option to use it together with S1 of IoT Hub and security should also be considered.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbabea0evuld2gfzmcezj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbabea0evuld2gfzmcezj.png" alt="Where to send"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to process
&lt;/h3&gt;

&lt;p&gt;Since Stream Analytics has limited flexibility in output destination, it needs to be combined with other services such as Functions in order to dynamically store the data in the specified table storage, which is more expensive than Functions alone.&lt;/p&gt;

&lt;p&gt;In addition, there is a requirement that the processing time between device and storage should be less than 10 seconds, so performance must be checked in the load test to determine the appropriate number of throughput units and instances.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pnc6pbhjqwqes535ag7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pnc6pbhjqwqes535ag7.png" alt="Where to process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to persist
&lt;/h3&gt;

&lt;p&gt;Table Storage results in significantly lower cost than Cosmos DB. &lt;br&gt;
The reason for this is that with Cosmos DB, as the number of operations (Point reads, Creates, Updates, Deletes) increases, the RU increases and the cost becomes higher. &lt;/p&gt;

&lt;p&gt;Also, 2 regions was one of the selection criteria this time, which made the cost higher. If only one region is applied, the cost of Cosmos DB is simply halved, but Table Storage is still cheaper.&lt;/p&gt;

&lt;p&gt;Furthermore, the fact that Table Storage can be used to retrieve the latest n data was also a big advantage in this scenario.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg68taepdqy8p2cy05vop.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg68taepdqy8p2cy05vop.png" alt="Where to persist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Estimated cost of the determined architecture
&lt;/h3&gt;

&lt;p&gt;Based on the above cost comparison as well as project's specific requirements, the final architecture we decided on is shown in the figure below.&lt;br&gt;
&lt;a href="https://media.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%2F6mzmyuoznxoqsfh7lq1v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mzmyuoznxoqsfh7lq1v.png" alt="Determined architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the total cost of Azure for this architecture. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkylkcywhtnsf0x01flfd.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkylkcywhtnsf0x01flfd.png" alt="Final result of cost comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The architecture fits neatly into the budget of $8 per connector.&lt;br&gt;
The processing time between device and table storage also cleared the requirement of 10 seconds or less, and the average processing time was 3.934 seconds by querying 20 minutes of data.The method of how to calculate the processing time will be written in another article.&lt;/p&gt;

&lt;h1&gt;
  
  
  Importance of load testing &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;While some calculations can be done theoretically based on the amount of data etc, load testing was necessary to estimate the cost of Stream Analytics and Functions and measure the processing time between device and storage.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne6i5ppjk3vzlub3911q.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne6i5ppjk3vzlub3911q.png" alt="Overview of load testing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, we conducted load tests using &lt;a href="https://github.com/Azure-Samples/Iot-Telemetry-Simulator" rel="noopener noreferrer"&gt;the IoT telemetry simulator&lt;/a&gt;. Just as the maximum size of telemetry messages sent by 10 devices is applied in the cost estimation, the message to be sent using the simulator was also made to be the maximum size to put an assumed load on it (i.e. 25KB).&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Cost is an unavoidable issue in developing a cloud-based solution.&lt;/p&gt;

&lt;p&gt;Cost estimation has advantages beyond understanding the cost, such as finding the best method with a limited budget, having elements to beat the competition, and considering the architecture with future scalability.&lt;/p&gt;

&lt;p&gt;Although this might be a slightly complicated task, it is recommended to do a cost estimation when considering the architecture.&lt;br&gt;
Hope this article will be helpful for you to understand how to determine the architecture from the cost estimation.&lt;/p&gt;

&lt;h1&gt;
  
  
  References &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/iot-hub/" rel="noopener noreferrer"&gt;IoT Hub pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/event-hubs/" rel="noopener noreferrer"&gt;Event Hubs pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas" rel="noopener noreferrer"&gt;Azure Event Hubs quotas and limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate#enable-auto-inflate-through-the-portal" rel="noopener noreferrer"&gt;Automatically scale up Azure Event Hubs throughput units (standard tier)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-compare-event-hubs" rel="noopener noreferrer"&gt;Connecting IoT Devices to Azure: IoT Hub and Event Hubs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/stream-analytics/" rel="noopener noreferrer"&gt;Stream Analytics pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/functions/" rel="noopener noreferrer"&gt;Functions pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal" rel="noopener noreferrer"&gt;Azure Functions Premium plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/app-service/windows/" rel="noopener noreferrer"&gt;App Service pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/cosmos-db/" rel="noopener noreferrer"&gt;Cosmos DB pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cosmos.azure.com/capacitycalculator/" rel="noopener noreferrer"&gt;Cosmos DB capacity planner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/estimate-ru-with-capacity-planner" rel="noopener noreferrer"&gt;Estimate RU/s using the Azure Cosmos DB capacity planner - SQL API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally" rel="noopener noreferrer"&gt;Distribute your data globally with Azure Cosmos DB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/storage/tables/" rel="noopener noreferrer"&gt;Table Storage pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-redundancy" rel="noopener noreferrer"&gt;Azure Storage redundancy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-design-patterns" rel="noopener noreferrer"&gt;Table design patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Delete-Table?redirectedfrom=MSDN" rel="noopener noreferrer"&gt;Delete Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/delete-entity1" rel="noopener noreferrer"&gt;Delete Entity (Azure Storage）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dataexplorer.azure.com/AzureDataExplorerCostEstimator.html" rel="noopener noreferrer"&gt;Azure Data Explorer (Kusto) Cost Estimator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/data-explorer/" rel="noopener noreferrer"&gt;Azure Data Explorer pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure-Samples/Iot-Telemetry-Simulator" rel="noopener noreferrer"&gt;IoT telemetry simulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
    </item>
    <item>
      <title>Ingest data from Azure Table Storage into Data Explorer</title>
      <dc:creator>Ayaka Hara</dc:creator>
      <pubDate>Fri, 23 Apr 2021 12:16:22 +0000</pubDate>
      <link>https://dev.to/aykhara/ingest-data-from-azure-table-storage-into-data-explorer-133c</link>
      <guid>https://dev.to/aykhara/ingest-data-from-azure-table-storage-into-data-explorer-133c</guid>
      <description>&lt;p&gt;LINQ allows us to query multiple entities from Azure Table Storage. However, the maximum number of entities that are returned in a single query with LINQ Take operator is 1,000 (&lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/writing-linq-queries-against-the-table-service#returning-the-top-n-entities"&gt;MS doc&lt;/a&gt;) and you may need to code more to retrieve what you want.&lt;/p&gt;

&lt;p&gt;This blog illustrates how to ingest data from Table Storage into Data Explorer via Data Factory to prepare to query large numbers of entities with Kusto.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Create Azure Data Explorer
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Create Azure Data Explorer 
Here is an example setting:
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8aX9TiZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ezoixzweuz4yui13ff3.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Go to the resource and click "Create database"&lt;/li&gt;
&lt;li&gt;Create Azure Data Explorer Database (e.g. Database name: loadtest)&lt;/li&gt;
&lt;li&gt;Click the database (e.g. "loadtest") and select "Query"&lt;/li&gt;
&lt;li&gt;Click "Ingest new data"&lt;/li&gt;
&lt;li&gt;Create table in the database and ingest data 
&lt;strong&gt;Note: table name should be not including "-(dash)"&lt;/strong&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hMDkFWG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hyxd22d1lndvgxpk3etu.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Click "Edit schema"&lt;/li&gt;
&lt;li&gt;Select "Ignore the first record"&lt;/li&gt;
&lt;li&gt;Make sure all data type are correct
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q9IqJFUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ao3tx6b9ghxq8xo5loab.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Click "Start ingestion"
&lt;strong&gt;Note: Please copy the mapping name&lt;/strong&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dkWNtE3W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmo28fqy5gju3exq5803.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Step 2: Create Azure Data Factory
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Create Azure Data Factory&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Step 3: Prepare Azure Active Directory
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Go to Azure Active Directory&lt;/li&gt;
&lt;li&gt;Click "App registrations" and register an application
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--adHpRHTo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7a7iwq5ntyymndyq8m10.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Go to "Certificates &amp;amp; secrets" and add a client secret
&lt;strong&gt;Note: Please don't forget to copy the secret&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to Azure Data Explorer and click "Permissions"&lt;/li&gt;
&lt;li&gt;Add the service principal just created
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PhwWhv70--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rz2cs0g7bfl9w5v7yl7v.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Step 4: Set Azure Data Factory to copy data from Azure Table Storage
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 4-1: Create a base pipeline on Azure Data Factory
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create Data Factory (You can select "Configure Git later")&lt;/li&gt;
&lt;li&gt;Go to resource&lt;/li&gt;
&lt;li&gt;Click "Author &amp;amp; Monitor"&lt;/li&gt;
&lt;li&gt;Click "Author (pencil icon)"&lt;/li&gt;
&lt;li&gt;Click "Add new resource (plus icon)" and select "Pipeline"&lt;/li&gt;
&lt;li&gt;Click "Move &amp;amp; transform" and drag "Copy data" to the right pane&lt;/li&gt;
&lt;li&gt;Set General in the bottom pane
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Khh-Ur2H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqvazm7gb2b8eyl8ppiv.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4-2: Set up input data (Source)  from Table Storage - Source
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Click "Add new resource (plus icon)" again and select "Dataset"&lt;/li&gt;
&lt;li&gt;Search "Azure Table Storage" and click "Continue"&lt;/li&gt;
&lt;li&gt;Click "New" in the bottom pane and set the linked service (Table Storage)

&lt;ul&gt;
&lt;li&gt;Select the table storage from Azure subscription or Enter manually&lt;/li&gt;
&lt;li&gt;Click "Test connection"&lt;/li&gt;
&lt;li&gt;Click "Create"
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kSiNULQa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8kkzooya09lazxw44fz.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Select the table you want to copy from pulldown list and update the dataset name in the right pane
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yMe96gPx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mkuqczf1z9ui7gk7ttac.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Back to pipeline setting and select the dataset on the "Source" section in the bottom pane&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4-3: Set output data (Sink) to Data Explorer
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Click "Add new resource (plus icon)" again and select "Dataset"&lt;/li&gt;
&lt;li&gt;Search "Azure Data Explorer" and click "Continue"&lt;/li&gt;
&lt;li&gt;Click "New" in the bottom pane and set the linked service (Data Explorer)

&lt;ul&gt;
&lt;li&gt;Select the data explorer cluster from Azure subscription or Enter manually&lt;/li&gt;
&lt;li&gt;Put your Service principal Id (= e.g. Application (client) ID of "sp-adf-ayhara-loadtest") and the client secret which you copied earlier&lt;/li&gt;
&lt;li&gt;Select Data Explorer database&lt;/li&gt;
&lt;li&gt;Click "Test connection"&lt;/li&gt;
&lt;li&gt;Click "Create"
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AvpH4_ES--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yyocbwzuxu639nzzncp9.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Select the table as destination from pulldown list and update the dataset name in the right pane
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6J34nUti--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y2qu19y2tf86v3ru6ekt.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Back to pipeline setting and select the dataset, table, and ingestion mapping name on the "Sink" section in the bottom pane
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wfqvzzg---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/untb273v2btug5zai4xj.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4-4: Set mapping
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Click import schemas&lt;/li&gt;
&lt;li&gt;Check if the mapping is correct
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iywr7kRl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rd1tqyua3j5itqvp07s9.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Step 5: Ingest data from Table Storage into Data Explorer database
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Click "Debug"
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EtvzQGeO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2vbeaklzfnuini16uts7.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Click "Details (glasses icon)"if you want to see the progress&lt;/li&gt;
&lt;li&gt;Once successfully data is copied:
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tzUuHITv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn8dvtdhtuqff0iy5cn4.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Go to Data Explorer and try to query something
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--txDa67CD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gx5v1z8hm6av5udt4x7r.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Back to Data Factory and click "Validate All"&lt;/li&gt;
&lt;li&gt;Publish all if there is no error!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you're ready to query data ingested from Azure Table Storage with Kusto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/aykhara/query-table-data-in-azure-data-explorer-with-kusto-to-analyse-load-test-results-1b93"&gt;Next step - Query table data in Azure Data Explorer with Kusto to analyse load test results&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
    </item>
  </channel>
</rss>
