Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
C#chevron-right

Adicionando o MongoDB Atlas Vector Search a um aplicativo .NET Blazor C#

Luce Carter10 min read • Published Feb 29, 2024 • Updated Feb 29, 2024
.NETC#
APLICATIVO COMPLETO
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Quando foi a última vez que você conseguiu se lembrar dos detalhes aproximados de algo, mas não conseguiu se lembrar do nome? Isso acontece com muitas pessoas, portanto, é muito importante poder pesquisar semanticamente em vez de usar pesquisas de texto exato.
É aqui que o MongoDB Atlas Vector Search se torna útil. Ele permite que você realize pesquisas semânticas em incorporações vetoriais em seus documentos armazenados no MongoDB Atlas. Como as incorporações são armazenadas dentro do Atlas, você pode criar as incorporações em qualquer tipo de dados, estruturados e não estruturados.
Neste tutorial, você aprenderá como adicionar pesquisa vetorial com o Atlas Vector Search, usando o driver C# do MongoDB, a um aplicativo .NET Blaszor. O aplicativo Blozor usa o banco de dados sample_mflix, disponível no conjunto de dados de amostra que qualquer um pode carregar em seu Atlas cluster. Você adicionará suporte para pesquisar semanticamente no campo de trama, para encontrar quaisquer filmes que possam se encaixar na trama inserida na caixa de pesquisa.

Pré-requisitos

Para acompanhar este tutorial, você precisará de algumas coisas antes de começar:
  1. .NET 8 SDK instalado em seu computador
  2. Um IDE ou editor de texto que pode dar suporte a C# e Blazor para a experiência de desenvolvimento mais perfeita, como Visual Studio, Visual Studio Code com a Extensão C# DevKit instalada ou JetBrains Rider
  3. Um cluster Atlas M0 , nosso nível gratuito para sempre, ideal para desenvolvimento
  4. Uma bifurcação e clone do repositório See Sharp Movies do GitHub ao qual adicionaremos a pesquisa
  5. Uma conta OpenAI e uma chave de APIgratuita gerada — você usará a API OpenAI para criar uma incorporação de vetor para nosso termo de pesquisa
Depois de bifurcar e clonar o repositório e usá-lo localmente, você precisará adicionar sua connection string a appsettings.Development.json e appsettings.json na seção de espaço reservado para se conectar ao seu cluster ao executar o projeto.
Se você não quiser acompanhar, o repositório tem uma ramificação chamada “vector-search” que tem o resultado final implementado. No entanto, você precisará garantir que tenha os dados incorporados no Atlas cluster.

Colocando nossos dados incorporados no Atlas

A primeira coisa que você precisa é de alguns dados armazenados em seu cluster que tenham incorporações de vetores disponíveis como um campo em seus documentos. O MongoDB já forneceu uma versão da coleção de filmes do sample_mflix, chamada incorporado_movies, que possui 1500 documentos, usando um subconjunto da coleção principal de filmes que foi carregado como um conjunto de dados para o Hugging Face que será usado neste tutorial.
É aqui que entra o Hugging Face Dataset Uploader baixado como parte dos pré-requisitos. Ao executar essa ferramenta usando dotnet run na raiz do projeto e passando sua connection string para o console quando solicitado, ele Go e fará o download do conjunto de dados de Abraçando a face e, em seguida, carregue-o em uma coleçãoembedded_movies dentro do banco de dadossample_mflix. Se você não tiver o mesmo conjunto de dados carregado, esse banco de dados estará ausente, ele apenas o criará para você graças ao C#!
Você pode gerar incorporações vetoriais para seus próprios dados usando ferramentas como Hugging Face, OpenAI, LlamaIndex e outras. Você pode ler mais sobre como gerar embeddings usando modelos de código aberto lendo um tutorial de Prakul Agarwal sobre IA generativa, pesquisa vetorial e modelos de código aberto aqui no Developer Center.

Criando o índice de pesquisa vetorial

Agora que você tem uma coleção de documentos de filmes com um campoplot_embeddingde embeddings vetoriais para cada documento, é hora de criar o índice Atlas Vector Search. Isso serve para habilitar os recursos de pesquisa vetorial no cluster e para permitir que o MongoDB saiba onde encontrar os embeddings vetoriais.
  1. Dentro do Atlas, clique em “Browse Collections” para abrir o explorador de dados e visualizar seu banco de dados sample_mflix recém-carregado.
  2. Selecione a aba “Atlas Search” na parte superior.
  3. Clique no botão verde “Create Search Index” para carregar o assistente de criação de índice.
  4. Selecione Editor JSON no título Vector Search e clique em "Next. "
  5. Selecione a collection embedded_movies em sample_mflix à esquerda.
  6. O nome não importa muito aqui, desde que você se lembre dele para mais tarde, mas, por enquanto, deixe-o como o valor padrão de 'vector_index'.
  7. Copie e cole o seguinte JSON, substituindo o conteúdo atual da caixa no assistente:
1{
2 "fields": [
3 {
4 "type": "vector",
5 "path": "plot_embedding",
6 "numDimensions": 1536,
7 "similarity": "dotProduct"
8 }
9 ]
10}
Ele contém alguns campos que você talvez não tenha visto antes.
  • caminho é o nome do campo que contém as incorporações. No caso do conjunto de dados da Hugging Face, isso é plot_embedding.
  • numDimensions refere-se às dimensões do modelo utilizado.
  • similaridade refere-se ao tipo de função usada para encontrar resultados semelhantes.
Confira a documentação do Atlas Vector Search para saber mais sobre esses campos de configuração.
Clique em "Next " e, na próxima página, clique em "Create Search Index. "
Após alguns minutos, o índice de pesquisa vetorial será configurado, você será notificado por e-mail e o aplicativo estará pronto para adicionar a pesquisa vetorial.

Adicionando a funcionalidade de backend

Você tem os dados com plot embeddings e um índice de pesquisa vetorial criado nesse campo, portanto, é hora de começar a trabalhar no aplicativo para adicionar a pesquisa, começando pela funcionalidade de backend.

Adicionando chave API OpenAI a appsettings

A chave de API OpenAI será usada para solicitar incorporações da API para o termo de pesquisa inserido, pois a pesquisa vetorial entende números e não texto. Por esse motivo, o aplicativo precisa que sua chave API OpenAI seja armazenada para uso posterior.
  1. Adicione o seguinte na raiz do seu appsettings.Development.json e appsettings.json, após a seção MongoDB, substituindo o texto do espaço reservado por sua própria chave:
1"OpenAPIKey": "<YOUR OPENAI API KEY>"
  1. Dentro program.cs, após a criação do construtor var, adicione a seguinte linha de código para extrair o valor da configuração do aplicativo:
1var openAPIKey = builder.Configuration.GetValue<string>("OpenAPIKey");
  1. Altere o código que cria a instância do MongoDBService para também passar o openAPIKey variable. Você alterará o construtor da classe posteriormente para fazer uso disso.
1builder.Services.AddScoped(service => new MongoDBService(mongoDBSettings, openAPIKey));

Adicionando um novo método ao IMongoDBService.cs

Você precisará adicionar um novo método à interface que suporte pesquisa, incluindo o termo a ser pesquisado e retornando uma lista de filmes encontrados na pesquisa.
Abra IMongoDBService.cs e adicione o seguinte código:
1public IEnumerable<Movie> MovieSearch(string textToSearch);

Implementando o método no MongoDBService.cs

Agora, faça as alterações na classe de implementação para dar suporte à pesquisa.
  1. Abra MongoDBService.cs e adicione as seguintes instruções using na parte superior do arquivo:
1using System.Text;
2using System.Text.Json;
  1. Adicione as seguintes novas variáveis locais abaixo das existentes no topo da classe:
1 private readonly string _openAPIKey;
2 private readonly HttpClient _httpClient = new HttpClient();
  1. Atualize o construtor para usar o novo parâmetro de string openAPIKey, bem como o parâmetro MongoDBSettings. Deve ficar assim:
1public MongoDBService(MongoDBSettings settings, string openAPIKey)
  1. Dentro do construtor, adicione uma nova linha para atribuir o valor de openAPIKey a _openAPIKey.
  2. Também dentro do construtor, atualize o nome da collection de "movies " para "embedded_movies ", onde chama .GetCollection.
A seguir está a aparência do construtor concluído:
1public MongoDBService(MongoDBSettings settings, string openAPIKey)
2{
3 _client = new MongoClient(settings.AtlasURI);
4 _mongoDatabase = _client.GetDatabase(settings.DatabaseName);
5 _movies = _mongoDatabase.GetCollection<Movie>("embedded_movies");
6 _openAPIKey = openAPIKey;
7}

Atualizando o modelo de filme

O driver C# atua como um mapeador de documentos de objetos (ODM), tratando do mapeamento entre um objeto C# antigo e simples (POCO) que é usado em C# e os documentos em sua coleção.
No entanto, os campos do modelo de filme existentes precisam ser atualizados para corresponder aos documentos dentro da sua collection embedded_movies.
Substitua o conteúdo de Models/Movie.cs pelo seguinte código:
1using MongoDB.Bson;
2using MongoDB.Bson.Serialization.Attributes;
3
4namespace SeeSharpMovies.Models;
5
6
7public class Movie
8{
9 [BsonId]
10 [BsonElement("_id")]
11 public ObjectId Id { get; set; }
12
13 [BsonElement("plot")]
14 public string Plot { get; set; }
15
16 [BsonElement("genres")]
17 public string[] Genres { get; set; }
18
19 [BsonElement("runtime")]
20 public int Runtime { get; set; }
21
22 [BsonElement("cast")]
23 public string[] Cast { get; set; }
24
25 [BsonElement("num_mflix_comments")]
26 public int NumMflixComments { get; set; }
27
28 [BsonElement("poster")]
29 public string Poster { get; set; }
30
31 [BsonElement("title")]
32 public string Title { get; set; }
33
34 [BsonElement("fullplot")]
35 public string FullPlot { get; set; }
36
37 [BsonElement("languages")]
38 public string[] Languages { get; set; }
39
40 [BsonElement("directors")]
41 public string[] Directors { get; set; }
42
43 [BsonElement("writers")]
44 public string[] Writers { get; set; }
45
46 [BsonElement("awards")]
47 public Awards Awards { get; set; }
48
49 [BsonElement("year")]
50 public string Year { get; set; }
51
52 [BsonElement("imdb")]
53 public Imdb Imdb { get; set; }
54
55 [BsonElement("countries")]
56 public string[] Countries { get; set; }
57
58 [BsonElement("type")]
59 public string Type { get; set; }
60
61 [BsonElement("plot_embedding")]
62 public float[] PlotEmbedding { get; set; }
63
64}
65
66public class Awards
67{
68 [BsonElement("wins")]
69 public int Wins { get; set; }
70
71 [BsonElement("nominations")]
72 public int Nominations { get; set; }
73
74 [BsonElement("text")]
75 public string Text { get; set; }
76}
77
78public class Imdb
79{
80 [BsonElement("rating")]
81 public float Rating { get; set; }
82
83 [BsonElement("votes")]
84 public int Votes { get; set; }
85
86 [BsonElement("id")]
87 public int Id { get; set; }
88}
Ele contém propriedades para todos os campos no documento, bem como classes e propriedades que representam subdocumentos encontrados dentro do documento do filme, como “critic.”. Você também observará o uso do atributo BSONElement, que informa ao motorista como mapear entre os nomes dos campos e os nomes das propriedades devido às suas diferentes convenções de nomenclatura.

Adicionando um modelo EmbeddingResponse

Está quase na hora de começar a implementar a pesquisa no back-end. Ao chamar o endpoint de incorporação da API OpenAI, você receberá muitos dados, incluindo as incorporações. A maneira mais fácil de lidar com isso é criar uma classe EmbeddingResponse.cs que modela essa resposta para uso posterior.
Adicione uma nova classe chamada EmbeddingResponse dentro da pasta Modelo e substitua o conteúdo do arquivo pelo seguinte:
1namespace SeeSharpMovies.Models
2{
3 public class EmbeddingResponse
4 {
5 public string @object { get; set; }
6 public List<Data> data { get; set; }
7 public string model { get; set; }
8 public Usage usage { get; set; }
9 }
10
11 public class Data
12 {
13 public string @object { get; set; }
14 public int index { get; set; }
15 public List<double> embedding { get; set; }
16 }
17
18 public class Usage
19 {
20 public int prompt_tokens { get; set; }
21 public int total_tokens { get; set; }
22 }
23}

Adicionar um método para solicitar incorporações para o termo de pesquisa

É hora de usar a chave da API do OpenAI e escrever a funcionalidade para criar embeddings de vetor para o termo pesquisado, chamando o endpointEmbeddings da API do OpenAI.
Dentro de MongoDBService.cs, adicione o seguinte código:
1private async Task<List<double>> GetEmbeddingsFromText(string text)
2{
3 Dictionary<string, object> body = new Dictionary<string, object>
4 {
5 { "model", "text-embedding-ada-002" },
6 { "input", text }
7 };
8
9 _httpClient.BaseAddress = new Uri("https://api.openai.com");
10 _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAPIKey}");
11
12 string requestBody = JsonSerializer.Serialize(body);
13 StringContent requestContent =
14 new StringContent(requestBody, Encoding.UTF8, "application/json");
15
16 var response = await _httpClient.PostAsync("/v1/embeddings", requestContent)
17 .ConfigureAwait(false);
18
19 if (response.IsSuccessStatusCode)
20 {
21 string responseBody = await response.Content.ReadAsStringAsync();
22 EmbeddingResponse embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseBody);
23 return embeddingResponse.data[0].embedding;
24 }
25
26 return new List<double>();
27}
O dicionário corporal é necessário pela API para saber o modelo usado e qual é a entrada. O modelo text-embedding-ada-002 é o modelo padrão de incorporação de texto.

Implementando a função SearchMovie

O método GetEmbeddingsFromText retornou as incorporações para o termo de pesquisa, então agora ele está disponível para ser utilizado pelo Atlas Vector Search e pelo driver C#.
Cole o código a seguir para implementar a pesquisa:
1public IEnumerable<Movie> MovieSearch(string textToSearch)
2{
3
4 var vector = GetEmbeddingsFromText(textToSearch).Result.ToArray();
5
6 var vectorOptions = new VectorSearchOptions<Movie>()
7 {
8 IndexName = "vector_index",
9 NumberOfCandidates = 150
10 };
11
12 var movies = _movies.Aggregate()
13 .VectorSearch(movie => movie.PlotEmbedding, vector, 150, vectorOptions)
14 .Project<Movie>(Builders<Movie>.Projection
15 .Include(m => m.Title)
16 .Include(m => m.Plot)
17 .Include(m => m.Poster))
18 .ToList();
19
20
21 return movies;
22}
Se você escolheu um nome diferente ao criar o índice de pesquisa vetorial anteriormente, certifique-se de atualizar esta linha dentro de vectorOptions.
A pesquisa de vetores está disponível dentro do driver C# como parte do pipeline de agregação. Ele recebe quatro argumentos: o nome do campo com as incorporações, as incorporações de vetor do termo pesquisado, o número de resultados a serem retornados e as opções de vetor.
Em seguida, métodos adicionais são encadeados para especificar quais campos devem ser retornados dos documentos resultantes.
Como o documento do filme mudou ligeiramente, o código atual dentro do métodoGetMovieById não está mais correto.
Substitua a linha atual que chama .Find pelo seguinte:
1 var movie = _movies.Find(movie => movie.Id.ToString() == id).FirstOrDefault();
O back-end agora está completo e é hora de passar para o front-end, adicionando a capacidade de pesquisar na interface do usuário e enviando essa pesquisa de volta ao código que acabamos de escrever.

Adicionando a funcionalidade de frontend

A funcionalidade de front-end será dividida em duas partes: o código no front-end para falar com o back-end e a barra de pesquisa em HTML para digitar.
Como este é um aplicativo existente, já há código disponível para extrair os filmes e até mesmo a paginação. É aqui que você adicionará a funcionalidade de pesquisa e ela pode ser encontrada dentro Home.razor na pastaComponents/Pages .
  1. Dentro do bloco@code, adicione uma nova variável de string para searchTerm:
1 string searchTerm;
  1. Cole o novo método a seguir no bloco de código:
1private void SearchMovies()
2{
3 if (string.IsNullOrWhiteSpace(searchTerm))
4 {
5 movies = MongoDBService.GetAllMovies();
6 }
7 else
8 {
9 movies = MongoDBService.MovieSearch(searchTerm);
10 }
11}
Isso é bastante simples. Se a string search Term estiver vazia, mostre tudo. Caso contrário, pesquise sobre isso.
Adicionar a barra de pesquisa é muito simples. Ele será adicionado ao componente de cabeçalho já presente na página inicial.
Substitua a marcação de cabeçalho existente pelo seguinte HTML:
1<header class="top-bar">
2 <a href="/">See Sharp Movies</a>
3 <div class="form-inline search-bar">
4 <input class="form-control mr-sm-2"
5 type="search" placeholder="Search"
6 aria-label="Search"
7 @bind="searchTerm">
8 <button class="btn btn-outline-success my-2 my-sm-0" @onclick="SearchMovies">Search</button>
9 </div>
10 </header>
Isso cria uma entrada de pesquisa com o valor vinculado à string searchterm e a um botão que, quando clicado, chama o método SearchMovies que você acabou de chamar.

Tornando a barra de pesquisa mais bonita

Neste ponto, a funcionalidade está implementada. Mas se você o executasse agora, a barra de pesquisa estaria em um lugar estranho no cabeçalho, então vamos consertar isso, apenas por beleza.
Dentro de wwwroot/app.css, adicione o seguinte código:
1.search-bar {
2 padding: 5%;
3}
4
5.search-bar button {
6 padding: 4px;
7}
Isso apenas dá à barra de pesquisa e ao botão um pouco de preenchimento para posiciona-lo mais bem dentro do cabeçalho. Embora não seja perfeita, CSS definitivamente não é o meu ponto forte. C# é a minha linguagem favorita!
Eba! Implementamos a funcionalidade de backend e frontend, então agora é hora de executar o aplicativo e vê-lo em ação!
Execute o aplicativo, insira um termo de pesquisa na caixa, clique no botão “Search” e veja quais filmes têm gráficos semanticamente próximos ao seu termo de pesquisa.
Mostrando resultados de filmes com enredo semelhante a Três jovens e uma espada

Resumo

Incrível! Agora você tem um aplicativo Blazor funcional com a capacidade de pesquisar o enredo por significado em vez de texto exato. Esse também é um ótimo ponto de partida para implementar mais recursos de pesquisa vetorial em seu aplicativo.
Se você quiser saber mais sobre o Atlas Vector Search, leia nossa documentação. O MongoDB também tem um espaço no Abraçando o Face onde você pode ver mais alguns exemplos do que pode ser feito e até mesmo jogar com ele. Go!
Há também um artigo surpreendente sobre o uso do Vector Search para áudio, co-escrito por Cloud Developer Advocate no MongoDB Pavel Duchovny.
Se tiver dúvidas ou feedback, acesse os fóruns da comunidade.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.
Iniciar a conversa

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Fundamentos do pipeline de agregação do MongoDB C#


Oct 11, 2024 | 5 min read
Tutorial

Envio e solicitação de dados do MongoDB em um jogo Unity


Sep 09, 2024 | 8 min read
Artigo

A versão 3.0 do driver C# está aqui! O que você precisa saber?


Nov 04, 2024 | 5 min read
Tutorial

Interaja com o MongoDB Atlas em uma função do AWS Lambda usando C#


Jan 23, 2024 | 5 min read
Sumário