{"id":54901,"date":"2024-12-16T10:05:00","date_gmt":"2024-12-16T18:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=54901"},"modified":"2024-12-16T10:05:00","modified_gmt":"2024-12-16T18:05:00","slug":"vector-data-qdrant-ai-search-dotnet","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/vector-data-qdrant-ai-search-dotnet\/","title":{"rendered":"Exploring Microsoft.Extensions.VectorData with Qdrant and Azure AI Search"},"content":{"rendered":"<p>Discover how to use Microsoft.Extensions.VectorData to implement semantic search using Qdrant and Azure AI Search.<\/p>\n<h2>Dive into Semantic Search with Microsoft.Extensions.VectorData: Qdrant and Azure AI Search<\/h2>\n<p>Semantic search is transforming how applications find and interpret data by focusing on meaning rather than mere keyword matching. With the release of <strong>Microsoft.Extensions.VectorData<\/strong>, .NET developers have a new set of building blocks to integrate vector-based search capabilities into their applications. In this post, we\u2019ll explore two practical implementations of semantic search using <strong>Qdrant<\/strong> locally and <strong>Azure AI Search<\/strong>.<\/p>\n<h2>Quick Introduction to Microsoft.Extensions.VectorData<\/h2>\n<p><strong>Microsoft.Extensions.VectorData<\/strong> is a set of code .NET libraries designed for managing vector-based data in .NET applications. These libraries provide a unified layer of C# abstractions for interacting with vector stores, enabling developers to handle embeddings and perform vector similarity queries efficiently.<\/p>\n<p>To get a detailed overview of the library\u2019s architecture and capabilities, I recommend reading <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-microsoft-extensions-vector-data\/\">Luis\u2019s excellent blog post<\/a>.<\/p>\n<p>In this blog post, we\u2019ll showcase two real-world use cases:<\/p>\n<ol>\n<li>\n<p>Using <strong>Qdrant<\/strong> locally for semantic search.<\/p>\n<\/li>\n<li>\n<p>Leveraging <strong>Azure AI Search<\/strong> for enterprise-scale vector search.<\/p>\n<\/li>\n<\/ol>\n<p>To run the demos, you need to use one of the models provided by Ollama for the embeddings generations. In this sample, the model used is all-minilm.<\/p>\n<ul>\n<li>\n<p>Install <a href=\"https:\/\/ollama.com\/download\">Ollama<\/a>.<\/p>\n<\/li>\n<li>\n<p>Download the <a href=\"https:\/\/ollama.com\/library\/all-minilm\">all-minilm model<\/a>.<\/p>\n<\/li>\n<li>\n<p>An OCI compliant container runtime, such as:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\">Docker Desktop<\/a> or <a href=\"https:\/\/podman.io\/\">Podman<\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Semantic Search with Qdrant<\/h2>\n<h3>What is Qdrant?<\/h3>\n<p><strong>Qdrant<\/strong> is a vector similarity search engine that provides a production-ready service with a convenient API to store, search, and manage points (i.e. vectors) with an additional payload. It\u2019s perfect for applications that require efficient similarity searches. You can easily run Qdrant locally in a Docker container, making it a developer-friendly choice.<\/p>\n<p>For setup instructions, refer to the <a href=\"https:\/\/qdrant.tech\/documentation\/quickstart\/\">Qdrant Quickstart Guide<\/a>. And, as for reference, this is a sample command to run a local container instance:<\/p>\n<pre><code class=\"language-bash\">docker run -p 6333:6333 -p 6334:6334 -v $(pwd)\/qdrant_storage:\/qdrant\/storage:z qdrant\/qdrant<\/code><\/pre>\n<p>Once the container is created, you can check it in Docker.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/12\/05Qdrantrunningindocker.png\" alt=\"qdrant container running in docker\" \/><\/p>\n<h3>Qdrant and Semantic Kernel<\/h3>\n<p><strong>Semantic Kernel<\/strong> provides a built-in connector for Qdrant, enabling .NET developers to store embeddings and execute vector-based queries seamlessly. This connector is built on top of <code>Microsoft.Extensions.VectorData<\/code> and the official <a href=\"https:\/\/github.com\/qdrant\/qdrant-dotnet\">.NET Qdrant Client<\/a>.<\/p>\n<p>This integration combines Qdrant\u2019s high performance with Semantic Kernel\u2019s ease of use.<\/p>\n<p>To learn more about the connector, visit the <a href=\"https:\/\/learn.microsoft.com\/semantic-kernel\/concepts\/vector-store-connectors\/out-of-the-box-connectors\/qdrant-connector?pivots=programming-language-csharp\">official documentation for Semantic Kernel Vector Store Qdrant connector<\/a>.<\/p>\n<h3>Scenario Overview &#8211; Qdrant<\/h3>\n<ul>\n<li><strong>Setup<\/strong>: A Qdrant instance runs locally in a Docker container.<\/li>\n<li><strong>Functionality<\/strong>: A .NET console application uses the Semantic Kernel\u2019s Qdrant connector to:\n<ul>\n<li>Store movie embeddings.<\/li>\n<li>Perform semantic search queries.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Let&#8217;s see a sample class that implements and runs this demo.<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.Extensions.AI;\nusing Microsoft.Extensions.VectorData;\nusing Microsoft.SemanticKernel.Connectors.Qdrant;\nusing Qdrant.Client;\n\nvar vectorStore = new QdrantVectorStore(new QdrantClient(\"localhost\"));\n\n\/\/ get movie list\nvar movies = vectorStore.GetCollection&lt;ulong, MovieVector&lt;ulong&gt;&gt;(\"movies\");\nawait movies.CreateCollectionIfNotExistsAsync();\nvar movieData = MovieFactory&lt;ulong&gt;.GetMovieVectorList();\n\n\/\/ get embeddings generator and generate embeddings for movies\nIEmbeddingGenerator&lt;string, Embedding&lt;float&gt;&gt; generator =\n    new OllamaEmbeddingGenerator(new Uri(\"http:\/\/localhost:11434\/\"), \"all-minilm\");\nforeach (var movie in movieData)\n{\n    movie.Vector = await generator.GenerateEmbeddingVectorAsync(movie.Description);\n    await movies.UpsertAsync(movie);\n}\n\n\/\/ perform the search\nvar query = \"A family friendly movie that includes ogres and dragons\";\nvar queryEmbedding = await generator.GenerateEmbeddingVectorAsync(query);\n\nvar searchOptions = new VectorSearchOptions()\n{\n    Top = 2,\n    VectorPropertyName = \"Vector\"\n};\n\nvar results = await movies.VectorizedSearchAsync(queryEmbedding, searchOptions);\nawait foreach (var result in results.Results)\n{\n    Console.WriteLine($\"Title: {result.Record.Title}\");\n    Console.WriteLine($\"Description: {result.Record.Description}\");\n    Console.WriteLine($\"Score: {result.Score}\");\n    Console.WriteLine();\n}<\/code><\/pre>\n<p>Once the demo is run, this is the sample output:<\/p>\n<pre><code class=\"language-bash\">Title: Shrek\nDescription: Shrek is an animated film that tells the story of an ogre named Shrek who embarks on a quest to rescue Princess Fiona from a dragon and bring her back to the kingdom of Duloc.\nScore: 0.5013245344161987\n\nTitle: Lion King\nDescription: The Lion King is a classic Disney animated film that tells the story of a young lion named Simba who embarks on a journey to reclaim his throne as the king of the Pride Lands after the tragic death of his father.\nScore: 0.3225690722465515<\/code><\/pre>\n<h3>Why Qdrant?<\/h3>\n<p>Using Qdrant for semantic search offers the advantage of <strong>scalable, high-speed similarity search<\/strong>, making it an excellent choice for applications requiring large-scale vector data management. Additionally, you have the option to run <a href=\"https:\/\/qdrant.tech\/blog\/qdrant-cloud-on-microsoft-azure\/\">Qdrant Cloud on Microsoft Azure<\/a>.<\/p>\n<h2>Semantic Search with Azure AI Search<\/h2>\n<h3>What is Azure AI Search?<\/h3>\n<p><strong>Azure AI Search<\/strong> is Microsoft\u2019s search-as-a-service offering. It integrates traditional search capabilities with AI-powered features like semantic and vector search. Built for scalability and reliability, it is an <strong>ideal solution for enterprise applications requiring advanced search functionality<\/strong>. You can <a href=\"https:\/\/learn.microsoft.com\/azure\/search\/search-what-is-azure-search\">learn more about Azure AI Search<\/a>.<\/p>\n<p>For this sample, we will use the <a href=\"https:\/\/learn.microsoft.com\/azure\/search\/vector-search-integrated-vectorization\">integrated vectorization in Azure AI Search<\/a>, which improves indexing and querying by converting documents and queries into vectors. <\/p>\n<h3>Azure AI Search and Semantic Kernel<\/h3>\n<p>This connector is built on top of <code>Microsoft.Extensions.VectorData<\/code> and the official <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/overview\/azure\/search?view=azure-dotnet\">Azure AI Search libraries for .NET<\/a>.<\/p>\n<p>For more information, refer to the <a href=\"https:\/\/learn.microsoft.com\/semantic-kernel\/concepts\/vector-store-connectors\/out-of-the-box-connectors\/azure-ai-search-connector?pivots=programming-language-csharp\">Azure AI Search connector documentation<\/a>.<\/p>\n<h3>Scenario Overview &#8211; Azure AI Search<\/h3>\n<ul>\n<li><strong>Setup<\/strong>: An Azure AI Search service is created in your Azure subscription.<\/li>\n<li><strong>Functionality<\/strong>: The console application:\n<ul>\n<li>Stores vector embeddings of movies.<\/li>\n<li>Executes vector-based semantic search queries.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Requirements<\/strong>: The Azure AI Search endpoint must be added as a User Secrets in the application. With the endpoint only, the app will create an Azure Default Credential to connect to the service. If you want to use the secret to access the Azure AI Search, you need to add the value also as a User Secret.<\/li>\n<\/ul>\n<p>Here is a console command sample on how to add the User Secrets:<\/p>\n<pre><code class=\"language-bash\">dotnet user-secrets init\ndotnet user-secrets set \"AZURE_AISEARCH_URI\" \"https:\/\/&lt;AI Search Name&gt;.search.windows.net\"\ndotnet user-secrets set \"AZURE_AISEARCH_SECRET\" \"AI Search Secret\"<\/code><\/pre>\n<p>Let&#8217;s see a sample class that implements and runs this demo.<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.Extensions.AI;\nusing Microsoft.Extensions.VectorData;\nusing Azure;\nusing Azure.Search.Documents.Indexes;\nusing Microsoft.SemanticKernel.Connectors.AzureAISearch;\nusing Microsoft.Extensions.Configuration;\nusing Azure.Identity;\nusing Azure.Core;\n\n\/\/ get the search index client using Azure Default Credentials or Azure Key Credential with the service secret\nvar client = GetSearchIndexClient();\nvar vectorStore = new AzureAISearchVectorStore(searchIndexClient: client);\n\n\/\/ get movie list\nvar movies = vectorStore.GetCollection&lt;string, MovieVector&lt;string&gt;&gt;(\"movies\");\nawait movies.CreateCollectionIfNotExistsAsync();\nvar movieData = MovieFactory&lt;string&gt;.GetMovieVectorList();\n\n\/\/ get embeddings generator and generate embeddings for movies\nIEmbeddingGenerator&lt;string, Embedding&lt;float&gt;&gt; generator =\n    new OllamaEmbeddingGenerator(new Uri(\"http:\/\/localhost:11434\/\"), \"all-minilm\");\nforeach (var movie in movieData)\n{\n    movie.Vector = await generator.GenerateEmbeddingVectorAsync(movie.Description);\n    await movies.UpsertAsync(movie);\n}\n\n\/\/ perform the search\nvar query = \"A family friendly movie that includes ogres and dragons\";\nvar queryEmbedding = await generator.GenerateEmbeddingVectorAsync(query);\n\n\/\/ show the results...<\/code><\/pre>\n<p>Once the demo is run, this is the sample output:<\/p>\n<pre><code class=\"language-bash\">Title: Shrek\nDescription: Shrek is an animated film that tells the story of an ogre named Shrek who embarks on a quest to rescue Princess Fiona from a dragon and bring her back to the kingdom of Duloc.\nScore: 0.6672559<\/code><\/pre>\n<p>And we can see the new index with the Movie fields in the Azure Portal in the Azure AI Search service.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/12\/10AzureAISearchIndexFields.png\" alt=\"index with the Movie fields in the Azure Portal in the Azure AI Search service\" \/><\/p>\n<h3>Why Azure AI Search?<\/h3>\n<p><a href=\"https:\/\/azure.microsoft.com\/products\/ai-services\/ai-search\/\">Azure AI Search<\/a> provides <strong>enterprise-grade scalability and integration<\/strong>, making it a robust solution for production-ready applications requiring advanced semantic search. Additionally, <strong>AI Search includes built-in security features<\/strong>, such as encryption and secure authentication, to protect your data. It also adheres to compliance standards, ensuring that your search solutions meet regulatory requirements.<\/p>\n<h2>Explaining the Code<\/h2>\n<h3>Console Applications for Demonstrations<\/h3>\n<p>Each semantic search demo is implemented as a <strong>.NET 9 Console Application<\/strong>. The codebase for the samples can be traced back to the original <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-microsoft-extensions-vector-data\/\">demo provided by Luis<\/a>, with extensions for both Azure AI Search and Qdrant scenarios.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/12\/20SolutionWithAllTheSamples.png\" alt=\"Visual Studio Solution Explorer including all the sample projects\" \/><\/p>\n<h3>Shared Class for Data Representation<\/h3>\n<p>A shared class represents a <strong>Movie<\/strong> entity, which includes:<\/p>\n<ul>\n<li><strong>Fields for Vector Embeddings<\/strong>: These embeddings are used to perform semantic search.<\/li>\n<li><strong>List of Movies<\/strong>: A static list of movies is generated to serve as sample data.<\/li>\n<li><strong>Type Factory for Keys<\/strong>: The class implements a factory pattern to handle differences in key data types.<\/li>\n<\/ul>\n<h3>Handling Different Data Types for Keys<\/h3>\n<ul>\n<li><strong>Qdrant<\/strong>: Uses <code>ulong<\/code> as the data type for its key field.<\/li>\n<li><strong>Azure AI Search<\/strong>: Uses <code>string<\/code> as the key field\u2019s data type.<\/li>\n<li><strong>MovieFactory<\/strong>: Ensures that the application generates the correct data type for each scenario, maintaining flexibility across implementations.<\/li>\n<\/ul>\n<h4>Movie Factory Implementation<\/h4>\n<pre><code class=\"language-csharp\">public class MovieFactory&lt;T&gt;\n{\n    public static List&lt;Movie&lt;T&gt;&gt; GetMovieList()\n    {\n        var movieData = new List&lt;Movie&lt;T&gt;&gt;()\n        {\n            \/\/ all movie sample collection is defined here\n        };\n        return movieData;\n    }\n\n    public static List&lt;MovieVector&lt;T&gt;&gt; GetMovieVectorList()\n    {\n        var movieData = GetMovieList();\n        var movieVectorData = new List&lt;MovieVector&lt;T&gt;&gt;();\n        foreach (var movie in movieData)\n        {\n            movieVectorData.Add(new MovieVector&lt;T&gt;\n            {\n                Key = movie.Key,\n                Title = movie.Title,\n                Description = movie.Description\n            });\n        }\n        return movieVectorData;\n    }\n<\/code><\/pre>\n<p>You can browse the <a href=\"https:\/\/aka.ms\/netaivectorstoreqdrantazureaisearchrepo\">github repository with the complete code samples<\/a>.<\/p>\n<h2>What\u2019s Coming Next?<\/h2>\n<p>The journey with <strong>Microsoft.Extensions.VectorData<\/strong> doesn\u2019t stop here. You can choose other connectors like <strong>SQLite in memory<\/strong>, <strong>Pinecone<\/strong> or <strong>Redis<\/strong>; enabling developers to run lightweight semantic search solutions locally. This feature will be perfect for scenarios where performance and simplicity are essential.<\/p>\n<p>And we are also working with partners like Elasticsearch are already building on top of Microsoft.Extensions.VectorData. You can learn more about this use case on <a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/customer-case-study-announcing-the-microsoft-semantic-kernel-elasticsearch-connector\/\">Customer Case Study: Announcing the Microsoft Semantic Kernel Elasticsearch Connector<\/a>.<\/p>\n<h2>Conclusion and Learn More<\/h2>\n<p>The combination of <strong>Microsoft.Extensions.VectorData<\/strong> and <strong>Semantic Kernel<\/strong>, allows .NET developers to build intelligent, scalable, and context-aware applications. Whether you\u2019re working on a small-scale project or a large enterprise system, these tools provide the foundation for delivering cutting-edge semantic search experiences.<\/p>\n<h3>Learn More<\/h3>\n<ul>\n<li><a href=\"https:\/\/learn.microsoft.com\/semantic-kernel\/concepts\/vector-store-connectors\/code-samples?pivots=programming-language-csharp\">Semantic Kernel Vector Store code samples (Preview)<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/semantic-kernel\/overview\">Semantic Kernel Overview<\/a><\/li>\n<li><a href=\"https:\/\/qdrant.tech\/documentation\/\">Qdrant Documentation<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/search\/\">Azure AI Search Documentation<\/a><\/li>\n<\/ul>\n<h2>Summary<\/h2>\n<p>Stay tuned for more tutorials and resources, and feel free to connect with us on social media for questions or feedback.\nHappy Coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discover how to use Microsoft.Extensions.VectorData to implement semantic search using Qdrant and Azure AI Search<\/p>\n","protected":false},"author":120281,"featured_media":54902,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7781,756],"tags":[7797,568,7891,7885,7806],"class_list":["post-54901","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-ai","category-csharp","tag-dotnet-9","tag-ai","tag-azure-ai-search","tag-microsoft-extensions-ai","tag-vectordb"],"acf":[],"blog_post_summary":"<p>Discover how to use Microsoft.Extensions.VectorData to implement semantic search using Qdrant and Azure AI Search<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/54901","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/120281"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=54901"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/54901\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/54902"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=54901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=54901"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=54901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}