Adicione a pesquisa de vetores do Firestore aos seus apps para dispositivos móveis com as Extensões do Firebase

1. Visão geral

Neste codelab, você vai aprender a adicionar recursos de pesquisa avançados ao seu app usando a pesquisa por similaridade de vetor do Firestore. Você vai implementar um recurso de pesquisa semântica para um app de anotações escrito em Swift e SwiftUI.

Console do Cloud Firestore mostrando alguns documentos, que também estão visíveis no app iOS no lado direito.

Conteúdo do laboratório

O que é necessário

  • Xcode 15.3
  • O exemplo de código do codelab. Você vai fazer o download dele em uma etapa posterior do codelab.

2. Criar e configurar um projeto do Firebase

Para usar a extensão Pesquisa de vetor do Firebase, você precisa de um projeto do Firebase. Nesta parte do codelab, você criará um novo projeto do Firebase e ativará os serviços necessários, como o Cloud Firestore e o Firebase Authentication.

criar um projeto do Firebase

  1. Faça login no Firebase.
  2. No Console do Firebase, clique em Adicionar projeto e dê a ele o nome Laboratório de pesquisa de vetores do FirestoreCriar um projeto, etapa 1 de 3: escolher o nome do projeto
  3. Clique nas opções de criação de projeto. Aceite os termos do Firebase se solicitado.
  4. Na tela do Google Analytics, desmarque a caixa Ativar o Google Analytics para este projeto, já que você não usará o Analytics para este aplicativo.
  5. Por fim, clique em Criar projeto.

Para saber mais sobre os projetos do Firebase, consulte Noções básicas sobre os projetos do Firebase.

Ativar e configurar produtos do Firebase no console

O app que você está criando usa vários produtos do Firebase disponíveis para apps da Apple:

  • Firebase Authentication para permitir que os usuários façam login no seu app com facilidade.
  • Cloud Firestore: é usado para salvar dados estruturados na nuvem e receber notificações instantâneas quando os dados são alterados.
  • Regras de segurança do Firebase para proteger seu banco de dados.

Alguns desses produtos precisam de configuração especial ou precisam ser ativados usando o Console do Firebase.

Ativar a autenticação anônima para o Firebase Authentication

Este aplicativo usa a autenticação anônima para permitir que os usuários comecem a usar o app sem precisar criar uma conta. Isso resulta em um processo de integração de baixo atrito. Para saber mais sobre a autenticação anônima (e como fazer upgrade para uma conta nomeada), consulte Práticas recomendadas para autenticação anônima.

  1. No painel à esquerda do Console do Firebase, clique em Build > Authentication. Em seguida, clique em Começar.Como ativar a autenticação do Firebase
  2. Agora você está no painel de autenticação, onde pode ver os usuários inscritos, definir provedores de login e gerenciar configurações.
  3. Selecione a guia Método de login (ou clique aqui para acessar diretamente a guia).
  4. Clique em Anônimo nas opções de provedor, alterne a chave para Ativar e clique em Salvar.

Configurar o Cloud Firestore

Este aplicativo Swift usa o Cloud Firestore para salvar notas. Veja como configurar o Cloud Firestore:

  1. No painel à esquerda do Console do Firebase, clique em Build > Banco de dados do Firestore. Em seguida, clique em Criar banco de dados.Como ativar o Cloud Firestore
  2. Selecione um local para seu banco de dados em que o Gemini esteja disponível. Para isso, basta usar us-central1. No entanto, esse local não poderá ser alterado posteriormente. Clique em Próximo.
  3. Selecione a opção Iniciar no modo de teste. Leia a exoneração de responsabilidade sobre as regras de segurança. O modo de teste garante que você possa gravar livremente no banco de dados durante o desenvolvimento.Como configurar regras de segurança para o Firestore no modo de teste
  4. Clique em Criar para criar o banco de dados.

3. Conectar o app móvel

Nesta seção do codelab, você vai fazer o download do código-fonte de um app simples de anotações e conectá-lo ao projeto do Firebase que acabou de criar.

Baixar o aplicativo de exemplo

  1. Acesse https://github.com/FirebaseExtended/codelab-firestore-vectorsearch-ios e clone o repositório na sua máquina local
  2. Abra o projeto Notes.xcodeproj no Xcode

Conectar o app ao seu projeto do Firebase

Para que seu app possa acessar os serviços do Firebase, é necessário configurá-lo no console do Firebase. É possível conectar vários aplicativos cliente ao mesmo projeto do Firebase. Por exemplo, se você criar um app da Web ou para Android, será preciso conectá-los ao mesmo projeto do Firebase.

Para saber mais sobre os projetos do Firebase, consulte Noções básicas sobre os projetos do Firebase.

  1. No Console do Firebase, acesse a página de visão geral do seu projeto do Firebase.Página de visão geral do Console do Firebase
  2. Clique no ícone do iOS+ para adicionar seu aplicativo para iOS.
  3. Na tela Adicionar o Firebase ao app da Apple, insira o ID do pacote do projeto Xcode (com.google.firebase.codelab.Notes).
  4. Se quiser, insira o apelido do aplicativo (Notes para iOS).
  5. Clique em "Registrar aplicativo" para avançar para a próxima etapa.
  6. Faça o download do arquivo GoogleServices-Info.plist.
  7. Arraste GoogleServices-Info.plist para a pasta Notes do seu projeto Xcode. Uma boa maneira de fazer isso é soltá-lo abaixo do arquivo Assets.xcassets.Arrastar o arquivo plist para o Xcode
  8. Selecione Copy items if needed, confira se o destino Notes está selecionado em Add to targets e clique em Finish.Selecionar "Copiar se necessário" na caixa de diálogo "Escolher opções para adicionar arquivos"
  9. Agora, no Console do Firebase, você pode clicar no restante do processo de configuração: o exemplo do qual você fez o download no início desta seção já tem o SDK do Firebase para Apple instalado e a inicialização está configurada. Para concluir o processo, clique em Continuar no console.

Execute o aplicativo

Chegou a hora de testar o app.

  1. De volta ao Xcode, execute o app no iOS Simulator. No menu suspenso Run Destinations, selecione primeiro um dos iOS Simulators.Selecionar um simulador de iOS no menu suspenso Run Destinations
  2. Em seguida, clique no botão Executar ou pressione ⌘ + R
  3. Depois que o app for iniciado no simulador, adicione algumas observações.
  4. No console do Firebase, acesse o navegador de dados do Firestore para conferir os documentos sendo criados à medida que você adiciona novas notas no app.Console do Cloud Firestore mostrando alguns documentos, junto com o simulador de iOS, que mostra os mesmos documentos

4. Instalar a pesquisa de vetores com a extensão do Firestore

Nesta parte do codelab, você vai instalar a pesquisa de vetores com a extensão do Firestore e configurá-la de acordo com os requisitos do app de anotações em que está trabalhando.

Iniciar a instalação da extensão

  1. Ainda na seção do Firestore, clique na guia Extensões.Como selecionar a guia Extensões do Firebase no console do Firestore
  2. Clique em Conheça o Extensions Hub.Guia "Extensões do Firebase" no console do Firestore
  3. Digite "vetor".
  4. Clique em "Pesquisa de vetores com a extensão do Firestore".Página de destino do Firebase Extensios Hub Isso vai levar você à página de detalhes da extensão, onde é possível ler mais sobre ela, como ela funciona, quais serviços do Firebase são necessários e como configurá-la.
  5. Clique em Instalar no console do Firebase.O botão de instalação da pesquisa de vetores com a extensão do Firestore
  6. Uma lista de todos os seus projetos será exibida.
  7. Escolha o projeto que você criou na primeira etapa deste codelab.Tela do seletor de projetos do Firebase

Configurar a extensão

As Extensões do Firebase usam o Cloud Functions para Firebase, que exige que seu projeto esteja no plano Blaze de pagamento por utilização. Antes de usar a pesquisa de vetores com a extensão do Firestore, você precisa fazer upgrade do projeto.

  1. Clique em Fazer upgrade do projeto para continuar. Como fazer upgrade do projeto para o plano Blaze
  2. Selecione uma conta de faturamento ou crie uma. Clique em Continuar.Como selecionar uma conta de faturamento
  3. Defina um orçamento (por exemplo, 10 BRL), clique em Continuar e depois em Comprar.Como definir um orçamento
  4. Confira as APIs ativadas e os recursos criados.Analisar as APIs ativadas
  5. Ative os serviços necessários.Como ativar os serviços necessários
  6. Ao ativar o Cloud Storage, selecione o modo de teste para as regras de segurança.
  7. Confirme se o Cloud Storage usará o mesmo local que sua instância do Cloud Firestore.
  8. Depois de ativar todos os serviços, clique em Próxima.Clique em "Próximo" depois de ativar todos os serviços
  9. Revise o acesso concedido a essa extensão.
  10. Configure a extensão:
    • Selecione Vertex AI como o LLM
    • Caminho da coleção: notes
    • Limite de consulta padrão: 3
    • Nome do campo de entrada: text
    • Nome do campo de saída: embedding
    • Nome do campo de status:* *status*
    • Incorporar documentos existentes: Yes
    • Atualizar documentos existentes: Yes
    • Local da função do Cloud: us-central1
  11. Clique em Instalar extensão para concluir a instalação.

Isso pode levar alguns minutos. Enquanto aguarda a conclusão da instalação, fique à vontade para avançar para a próxima seção do tutorial e ler algumas informações básicas sobre embeddings de vetores.

5. Experiência

Enquanto você espera a instalação terminar, aqui estão algumas informações básicas sobre como funciona a pesquisa de vetores com a extensão Firestore.

O que são vetores, embeddings e bancos de dados vetoriais?

  • Vetores são objetos matemáticos que representam a magnitude e a direção de uma quantidade. Eles podem ser usados para representar dados de uma forma que facilite a comparação e a pesquisa.
  • Embeddings são vetores que representam o significado de uma palavra ou frase. Elas são criadas ao treinar uma rede neural em um grande corpus de texto e aprender as relações entre palavras.
  • Bancos de dados vetoriais são otimizados para armazenar e pesquisar dados vetoriais. Elas permitem uma pesquisa eficiente de vizinho mais próximo, que é o processo de encontrar os vetores mais semelhantes a um determinado vetor de consulta.

Como funciona a pesquisa de vetores?

A pesquisa de vetores funciona comparando o vetor de consulta a todos os vetores no banco de dados. Os vetores mais semelhantes ao vetor de consulta são retornados como resultados da pesquisa.

A semelhança entre dois vetores pode ser medida usando várias métricas de distância. A métrica de distância mais comum é a similaridade de cossenos, que mede o ângulo entre dois vetores.

6. Teste a pesquisa de vetores com a extensão Firestore

Antes de usar a pesquisa de vetores com a extensão do Firestore no app iOS do qual você fez o download anteriormente neste codelab, teste a extensão no Console do Firebase.

Leia a documentação

As Extensões do Firebase incluem documentação sobre como elas funcionam.

  1. Quando a instalação da extensão for concluída, clique no botão Começar. Página de visão geral da Extensão do Firebase no Console do Firebase
  2. Confira a guia "Como esta extensão funciona" e ela explica:
    • como calcular embeddings para documentos adicionando-os à coleção notes
    • a consultar o índice chamando a função chamável ext-firestore-vector-search-queryCallable;
    • ou como consultar o índice adicionando um documento de consulta à coleção _firestore-vector-search/index/queries.
    • Ele também explica como configurar uma função de incorporação personalizada, o que é útil se nenhum dos LLMs com suporte da extensão atender aos seus requisitos e você quiser usar um LLM diferente para computar embeddings. A documentação da pesquisa de vetores com a extensão Firestore
  3. Clique no link painel do Cloud Firestore para acessar sua instância do Firestore.
  4. Acesse o documento _firestore-vector-search/index. Ela vai mostrar que a extensão terminou de calcular os embeddings de todos os documentos de notas que você criou em uma etapa anterior deste codelab.A configuração do índice no console do Firestore
  5. Para verificar isso, abra um dos documentos de notas. Você verá um campo adicional chamado embedding do tipo vector<768>, bem como um campo status.Um campo de embedding de vetores dentro do console do Firestore

Criar um documento de amostra

Você pode criar um novo documento no Console do Firebase para ver a extensão em ação.

  1. Ainda no navegador de dados do Firestore, navegue até a coleção notes e clique em + Adicionar documento na coluna do meio.Como adicionar um novo documento
  2. Clique em ID automático para gerar um ID de documento novo e exclusivo.
  3. Adicione um campo chamado text do tipo string e cole um texto no campo value. É importante que ele não seja lorem ipsum ou algum outro texto aleatório. Escolha uma matéria, por exemplo.Adicionar um campo de texto
  4. Clique em Salvar.
    • Observe como a extensão adiciona um campo de status para indicar que está processando dados.
    • Depois de alguns instantes, você verá um novo campo embedding com um valor de vector<768>.
    Atualização do status de embeddings de vetores para o novo documento

Executar uma consulta

A pesquisa de vetores com a extensão Firestore tem um recurso útil que permite consultar o índice de documentos sem precisar conectar um app.

  1. Na seção Firestore do Console do Firebase, acesse o documento _firestore-vector-search/index
  2. Clique em + Iniciar coleçãoComo adicionar uma nova subcoleção
  3. Crie uma nova subcoleção chamada queries
  4. Crie um novo documento e defina o campo query como um texto que apareça em um dos seus documentos. Isso funciona melhor para consultas semânticas, por exemplo, "Como mapear documentos do Firestore com o Swift" (desde que pelo menos uma das observações adicionadas contenha texto que discute esse assunto).Adicionar um campo de consulta
  5. Talvez apareça um erro no statusOcorreu um erro
  6. Isso ocorre devido a um índice ausente. Para definir a configuração de índice ausente, acesse o console do Google Cloud do seu projeto neste link e selecione seu projeto na listaComo selecionar o projeto correto
  7. Na Análise de registros do Cloud, você verá a mensagem de erro "FAILED_PRECONDITION: configuração de índice de vetor ausente. Crie o índice necessário com o seguinte comando gcloud: ..."Mensagem de erro na análise de registros
  8. A mensagem de erro também contém um comando gcloud que você precisa executar para configurar o índice ausente.
  9. Execute o comando a seguir na linha de comando. Se você não tiver a CLI gcloud instalada na sua máquina, siga estas instruções para fazer a instalação.
    gcloud alpha firestore indexes composite create --project=INSERT-YOUR=PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding
    
    A criação do índice leva alguns minutos. Verifique o progresso na guia Índices na seção "Firestore" do Console do Firebase.Status do novo índice
  10. Após a configuração do índice, você pode criar um novo documento de consulta.
  11. Uma lista de IDs de documentos correspondentes vai aparecer no campo de resultados.Resultado de uma consulta semântica
  12. Copie um desses IDs e volte para a coleção notes.
  13. Use ⌘+F para pesquisar o ID do documento que você copiou. Esse é o documento que melhor corresponde à sua consulta.Como encontrar o ID do documento na lista de documentos

7. Implementar a pesquisa semântica

Chegou a hora de conectar seu app para dispositivos móveis à pesquisa de vetores com a extensão Firestore e implementar um recurso de pesquisa semântica que vai permitir que os usuários pesquisem anotações usando consultas em linguagem natural.

Conectar a função chamável para realizar consultas

A pesquisa de vetores com a extensão do Firestore inclui uma função do Cloud que pode ser chamada do seu app para dispositivos móveis para consultar o índice que você criou anteriormente neste codelab. Nesta etapa, você vai estabelecer uma conexão entre o app para dispositivos móveis e essa função chamável. O SDK Swift do Firebase inclui APIs que facilitam a chamada de funções remotas.

  1. Volte para o Xcode e verifique se você está no projeto clonado em uma etapa anterior deste codelab.
  2. Abra o arquivo NotesRepository.swift.
  3. Encontre a linha que contém private lazy var vectorSearchQueryCallable: Callable = functions.httpsCallable("")

Para invocar uma função chamável do Cloud, você precisa fornecer o nome da função que quer chamar.

  1. Acesse o console do Firebase do seu projeto e abra o item de menu Functions na seção Build.
  2. Você verá uma lista das funções que foram instaladas pela extensão.
  3. Pesquise o nome ext-firestore-vector-search-queryCallable e copie o nome.
  4. Cole o nome no código. Agora ele vai mostrar
    private lazy var vectorSearchQueryCallable: Callable<String, String> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
    

Chamar a função query

  1. Encontre o método performQuery.
  2. Chame sua função chamável invocando
    let result = try await vectorSearchQueryCallable(searchTerm)
    
    .

Como essa é uma chamada remota, ela pode falhar.

  1. Adicione processamentos básicos de erros para detectar e registrar erros no console do Xcode.
    private func performQuery(searchTerm: String) async -> [String] {
      do {
        let result = try await vectorSearchQueryCallable(searchTerm)
        return [result]
      }
      catch {
        print(error.localizedDescription)
        return []
      }
    }
    

Conectar a interface

Para permitir que os usuários pesquisem nas anotações, você vai implementar uma barra de pesquisa na tela da lista de anotações. Quando o usuário digita um termo de pesquisa, é necessário invocar o método performQuery implementado na etapa anterior. Graças aos modificadores de visualização searchable e task fornecidos pelo SwiftUI, isso requer apenas algumas linhas de código.

  1. Primeiro, abra o app NotesListScreen.swift
  2. Para adicionar uma caixa de pesquisa a ela, adicione o modificador de visualização .searchable(text: $searchTerm, prompt: "Search") logo acima da linha .navigationTitle("Notes").
  3. Em seguida, invoque a função de pesquisa adicionando o seguinte código logo abaixo:
.task(id: searchTerm, debounce: .milliseconds(800)) {
  await notesRepository.semanticSearch(searchTerm: searchTerm)
}

Este snippet de código chama o método semanticSearch de forma assíncrona. Ao fornecer um tempo limite de 800 milissegundos, você instrui o modificador da tarefa a fazer um rebote da entrada do usuário em 0,8 segundo. Isso significa que o semanticSearch só vai ser chamado quando o usuário parar de digitar por mais de 0,8 segundo.

O código vai ficar assim:

...
List(repository.notes) { note in
  NavigationLink(value: note) {
    NoteRowView(note: note)
  }
  .swipeActions {
    Button(role: .destructive, action: { deleteNote(note: note) }) {
      Label("Delete", systemImage: "trash")
    }
  }
}
.searchable(text: $searchTerm, prompt: "Search")
.task(id: searchTerm, debounce: .milliseconds(800)) {
  await notesRepository.semanticSearch(searchTerm: searchTerm)
}
.navigationTitle("Notes")
...

Execute o aplicativo

  1. Pressione ⌘ + R (ou clique no botão "Executar") para iniciar o app no iOS Simulator.
  2. Você vai encontrar as mesmas observações que adicionou ao app anteriormente neste codelab, assim como todas as observações adicionadas pelo Console do Firebase.
  3. Vai aparecer um campo de pesquisa no topo da lista Notes.
  4. Digite um termo que apareça em um dos documentos adicionados. Novamente, isso funciona melhor para consultas semânticas, como "Como posso chamar APIs assíncronas do Firebase pelo Swift" (desde que pelo menos uma das observações adicionadas contenha texto que fale sobre esse tópico).
  5. Você provavelmente espera ver o resultado da pesquisa, mas a visualização em lista está vazia e o console do Xcode mostra uma mensagem de erro: "A função foi chamada com um argumento inválido".

App Notas, com uma lista de resultados vazia

Isso significa que você enviou os dados no formato errado.

Analisar a mensagem de erro

  1. Para descobrir o que há de errado, acesse o Console do Firebase
  2. Acesse a seção Funções
  3. Encontre a função ext-firestore-vector-search-queryCallable e abra o menu flutuante clicando nos três pontos verticais.
  4. Selecione Ver registros para acessar a Análise de registros.
  5. Você verá um erro
Unhandled error ZodError: [
  {
    "code": "invalid_type",
    "expected": "object",
    "received": "string",
    "path": [],
    "message": "Expected object, received string"
  }
]

Isso significa que você enviou os dados no formato errado.

Use os tipos de dados corretos

Para descobrir em qual formato a extensão espera que os parâmetros estejam, consulte a documentação da extensão.

  1. Vá para a seção Extensões no Console do Firebase.
  2. Clique em Gerenciar ->Como gerenciar a pesquisa de vetores com a extensão do Firestore
  3. Na seção Como esta extensão funciona, você vai encontrar uma especificação dos parâmetros de entrada e saída.Documentação do parâmetro de entrada e do valor de resultado
  4. Volte para o Xcode e navegue até NotesRepository.swift
  5. Adicione o seguinte código no início do arquivo:
    private struct QueryRequest: Codable {
      var query: String
      var limit: Int?
      var prefilters: [QueryFilter]?
    }
    
    private struct QueryFilter: Codable {
      var field: String
      var `operator`: String
      var value: String
    
    }
    
    private struct QueryResponse: Codable {
      var ids: [String]
    }
    
    QueryRequest corresponde à estrutura do parâmetro de entrada que a extensão espera, de acordo com a documentação da extensão. Ela também contém um atributo prefilter aninhado que será necessário mais tarde.QueryResponse corresponde à estrutura da resposta da extensão.
  6. Encontre a especificação da função chamável e atualize os tipos de entrada e saída
    private lazy var vectorSearchQueryCallable: Callable<QueryRequest, QueryResponse> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
    
  7. Atualize a invocação da função chamável em performQuery
    private func performQuery(searchTerm: String) async -> [String] {
      do {
        let queryRequest = QueryRequest(query: searchTerm,
                                        limit: 2)
        let result = try await vectorSearchQueryCallable(queryRequest)
        print(result.ids)
        return result.ids
      }
      catch {
        print(error.localizedDescription)
        return []
      }
    }
    

Executar o app novamente

  1. Executar o app novamente
  2. Digite uma consulta de pesquisa que contenha os termos incluídos em uma das suas notas
  3. Uma lista filtrada de notas vai aparecer

Captura de tela do app com o resultado esperado

Pré-filtrar dados do usuário

Antes de começar a dançar para comemorar, há um problema com a versão atual do app: o conjunto de resultados contém dados de todos os usuários.

Para verificar isso, execute o app em outro simulador e adicione mais documentos. Os novos documentos só serão exibidos nesse simulador. Se você executar o app novamente no outro simulador, serão exibidos apenas os documentos criados na primeira vez.

Se você fizer uma pesquisa, vai perceber que a chamada para vectorSearchQueryCallable retorna IDs de documentos que podem pertencer ao outro usuário. Para evitar isso, precisamos usar um pré-filtro.

Em performQuery, atualize o código da seguinte maneira:

  let prefilters: [QueryFilter] = if let uid = user?.uid {
    [QueryFilter(field: "userId", operator: "==", value: uid)]
  }
  else {
    []
  }

  let queryRequest = QueryRequest(query: searchTerm,
                                  limit: 2,
                                  prefilters: prefilters)

Isso vai pré-filtrar os dados com base no ID do usuário conectado. Como esperado, isso exige que o índice do Firestore seja atualizado.

Execute o comando a seguir na linha de comando para definir um novo índice do Firestore que inclua o userId e os embeddings de vetor no campo embedding.

gcloud alpha firestore indexes composite create --project=INSERT-YOUR-PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=order=ASCENDING,field-path=userId --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding

Após a criação do índice, execute o app novamente para verificar se ele funciona como esperado.

Conjunto pré-filtrado de resultados

8. Parabéns

Parabéns! Você concluiu este codelab.

Neste codelab, você aprendeu a:

  • Configurar um banco de dados do Cloud Firestore com a pesquisa semântica ativada.
  • Criar um app SwiftUI simples para interagir com o banco de dados.
  • Implemente uma barra de pesquisa usando o modificador de visualização pesquisável do SwiftUI e o modificador de tarefa.
  • Chamar uma função do Cloud para realizar uma pesquisa semântica no banco de dados usando a interface chamável do SDK do Firestore.

Com o conhecimento que você adquiriu neste codelab, agora você pode criar aplicativos avançados que aproveitam os recursos de pesquisa semântica do Cloud Firestore para fornecer aos usuários uma experiência de pesquisa mais intuitiva e eficiente.

Para saber mais sobre o novo campo vetorial do Firestore e como calcular embeddings de vetores, consulte a documentação.