1. Descripción general
En este codelab, aprenderás a agregar funciones de búsqueda potentes a tu app con la búsqueda de similitud vectorial de Firestore. Implementarás una función de búsqueda semántica en una app para tomar notas escritas con Swift y SwiftUI.
Qué aprenderás
- Cómo instalar la extensión de Búsqueda vectorial con Firestore para calcular incorporaciones de vectores
- Cómo llamar a Firebase Cloud Functions desde una aplicación de Swift.
- Cómo filtrar previamente los datos según el usuario que accedió
Lo que necesitarás
- Xcode 15.3
- El código de muestra del codelab La descargarás en un paso posterior del codelab.
2. Crea y configura un proyecto de Firebase
Para usar la extensión de Búsqueda de vectores de Firebase, necesitas un proyecto de Firebase. En esta parte del codelab, crearás un nuevo proyecto de Firebase y activarás los servicios necesarios, como Cloud Firestore y Firebase Authentication.
Crea un proyecto de Firebase
- Accede a Firebase.
- En Firebase console, haz clic en Agregar proyecto y, luego, asígnale el nombre Firestore Vector Search Lab.
- Haz clic en las opciones de creación del proyecto. Si se te solicita, acepta las condiciones de Firebase.
- En la pantalla de Google Analytics, desmarca la casilla Habilitar Google Analytics para este proyecto, ya que no usarás Analytics para esta app.
- Por último, haz clic en Crear proyecto.
Para obtener más información sobre los proyectos de Firebase, consulta Información sobre los proyectos de Firebase.
Actualiza tu plan de precios de Firebase
Para usar las Extensiones de Firebase y sus servicios en la nube subyacentes, tu proyecto de Firebase debe tener el plan de precios de pago por uso (Blaze), lo que significa que está vinculado a una cuenta de Facturación de Cloud.
- Una cuenta de Facturación de Cloud requiere una forma de pago, como una tarjeta de crédito.
- Si es la primera vez que usas Firebase y Google Cloud, verifica si cumples con los requisitos para obtener un crédito de USD 300 y una cuenta de Facturación de Cloud de prueba gratuita.
- Si realizas este codelab como parte de un evento, pregúntale al organizador si hay créditos de Cloud disponibles.
Para actualizar tu proyecto al plan Blaze, sigue estos pasos:
- En Firebase console, selecciona la opción para actualizar tu plan.
- Selecciona el plan Blaze. Sigue las instrucciones en pantalla para vincular una cuenta de Facturación de Cloud a tu proyecto.
Si necesitas crear una cuenta de Facturación de Cloud como parte de esta actualización, es posible que debas volver al flujo de actualización en Firebase console para completarla.
Habilita y configura los productos de Firebase en la consola
La app que estás compilando usa varios productos de Firebase que están disponibles para apps para Apple:
- Firebase Authentication, a fin de permitir que los usuarios accedan a tu app con facilidad
- Cloud Firestore, a fin de guardar datos estructurados en la nube y recibir notificaciones al instante cuando se modifiquen los datos
- Reglas de seguridad de Firebase para proteger tu base de datos.
Algunos de estos productos necesitan una configuración especial o deben habilitarse mediante Firebase console.
Habilita la autenticación anónima para Firebase Authentication
Esta aplicación usa la autenticación anónima para permitir que los usuarios comiencen a usarla sin tener que crear una cuenta primero. Esto genera un proceso de integración sin fricciones. Para obtener más información sobre la autenticación anónima (y cómo actualizar a una cuenta con nombre), consulta Prácticas recomendadas para la autenticación anónima.
- En el panel izquierdo de Firebase console, haz clic en Build > Authentication. Luego, haz clic en Comenzar.
- Ahora estás en el panel de autenticación, donde puedes ver a los usuarios registrados, configurar proveedores de acceso y administrar la configuración.
- Selecciona la pestaña Método de acceso (o haz clic aquí para ir directamente a la pestaña).
- En las opciones del proveedor, haz clic en Anonymous, activa el interruptor Enable y, luego, haz clic en Save.
Configura Cloud Firestore
Esta aplicación de Swift usa Cloud Firestore para guardar notas.
Sigue estos pasos para configurar Cloud Firestore en tu proyecto de Firebase:
- En el panel izquierdo de Firebase console, expande Compilación y, luego, selecciona Base de datos de Firestore.
- Haz clic en Crear base de datos.
- Deja el ID de base de datos establecido en
(default)
. - Selecciona una ubicación para tu base de datos y, luego, haz clic en Siguiente.
Para una app real, debes elegir una ubicación que esté cerca de tus usuarios. - Haz clic en Iniciar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad.
Más adelante en este codelab, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app públicamente sin agregar reglas de seguridad para tu base de datos. - Haz clic en Crear.
Configura Cloud Storage para Firebase
La app web usa Cloud Storage para Firebase para almacenar, subir y compartir fotos.
A continuación, te mostramos cómo configurar Cloud Storage para Firebase en tu proyecto de Firebase:
- En el panel izquierdo de Firebase console, expande Compilación y, luego, selecciona Almacenamiento.
- Haz clic en Comenzar.
- Selecciona una ubicación para tu bucket de Storage predeterminado.
Los buckets deUS-WEST1
,US-CENTRAL1
yUS-EAST1
pueden aprovechar el nivel “Siempre gratis” de Google Cloud Storage. Los buckets de todas las demás ubicaciones siguen los precios y el uso de Google Cloud Storage. - Haz clic en Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad.
Más adelante en este codelab, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app de forma pública sin agregar reglas de seguridad para tu bucket de Storage. - Haz clic en Crear.
3. Cómo conectar la aplicación para dispositivos móviles
En esta sección del codelab, descargarás el código fuente de una app simple para tomar notas y la conectarás al proyecto de Firebase que acabas de crear.
Descarga la app de ejemplo:
- Ve a https://github.com/FirebaseExtended/codelab-firestore-vectorsearch-ios y clona el repositorio en tu máquina local.
- Abre el proyecto Notes.xcodeproj en Xcode.
Conecta la app a tu proyecto de Firebase
Para que tu app pueda acceder a los servicios de Firebase, deberás configurarla en Firebase console. Puedes conectar múltiples aplicaciones cliente al mismo proyecto de Firebase. Por ejemplo, si creas una aplicación web o para Android, debes conectarlas al mismo proyecto de Firebase.
Para obtener más información sobre los proyectos de Firebase, consulta la Información sobre los proyectos de Firebase.
- En Firebase console, ve a la página de descripción general de tu proyecto de Firebase.
- Haz clic en el ícono de iOS+ para agregar tu app para iOS.
- En la pantalla Agrega Firebase a tu app para Apple, inserta el ID del paquete del proyecto de Xcode (com.google.firebase.codelab.Notes).
- Si lo deseas, puedes ingresar un sobrenombre para la app (Notas para iOS).
- Haz clic en Registrar app para avanzar al siguiente paso.
- Descarga el archivo GoogleServices-Info.plist.
- Arrastra GoogleServices-Info.plist a la carpeta Notes de tu proyecto de Xcode. Una buena manera de hacerlo es colocarlo debajo del archivo Assets.xcassets.
- Selecciona Copiar elementos si es necesario, asegúrate de que el objetivo Notas esté seleccionado en Agregar a destinos y haz clic en Finalizar.
- En Firebase console, ahora puedes hacer clic para completar el resto del proceso de configuración: la muestra que descargaste al comienzo de esta sección ya tiene instalado el SDK de Firebase para Apple y la configuración de inicialización. Para finalizar el proceso, haz clic en Ir a la consola.
Ejecuta la app
Ahora es momento de probar la app.
- En Xcode, ejecuta la app en el simulador de iOS. En el menú desplegable Run Destinations, primero selecciona uno de los simuladores de iOS.
- Luego, haz clic en el botón Ejecutar o presiona ⌘ + R.
- Una vez que la app se haya iniciado correctamente en el simulador, agrega algunas notas.
- En Firebase console, ve al navegador de datos de Firestore para ver los documentos nuevos que se crean a medida que agregas notas nuevas en la app.
4. Instala la extensión de Búsqueda vectorial con Firestore
En esta parte del codelab, instalarás la búsqueda de vectores con la extensión de Firestore y la configurarás según los requisitos de la app para tomar notas en la que estás trabajando.
Inicia la instalación de la extensión
- En la sección Firestore, haz clic en la pestaña Extensiones.
- Haz clic en Explorar el Centro de extensiones.
- Escribe "vector".
- Haz clic en "Búsqueda de vectores con extensión de Firestore". Esto te llevará a la página de detalles de la extensión, en la que puedes obtener más información sobre ella, cómo funciona, qué servicios de Firebase requiere y cómo puedes configurarla.
- Haz clic en Instalar en Firebase console.
- Verás una lista de todos tus proyectos.
- Elige el proyecto que creaste en el primer paso de este codelab.
Configura la extensión
- Revisa las APIs habilitadas y los recursos creados.
- Habilita los servicios obligatorios.
- Cuando todos los servicios estén habilitados, haz clic en Siguiente.
- Revisa el acceso otorgado a esta extensión.
- Configura la extensión:
- Selecciona Vertex AI como el LLM.
- Ruta de recopilación: notas
- Límite de consultas predeterminado: 3
- Nombre del campo de entrada: text
- Nombre del campo de salida: embedding
- Nombre del campo de estado:* *status*
- Incorpora documentos existentes: Sí
- Actualizar documentos existentes: Sí
- Ubicación de Cloud Function: us-central1
- Haz clic en Install extension para finalizar la instalación.
Esto podría tardar unos minutos. Mientras esperas a que se complete la instalación, no dudes en avanzar a la siguiente sección del instructivo y leer información de referencia sobre las incorporaciones vectoriales.
5. Segundo plano
Mientras esperas a que finalice la instalación, aquí tienes información general sobre cómo funciona la extensión de búsqueda de vectores con Firestore.
¿Qué son los vectores, las incorporaciones y las bases de datos de vectores?
- Los vectores son objetos matemáticos que representan la magnitud y la dirección de una cantidad. Se pueden usar para representar datos de una manera que facilite la comparación y la búsqueda.
- Las incorporaciones son vectores que representan el significado de una palabra o frase. Para crearlos, se entrena una red neuronal con un gran corpus de texto y se aprenden las relaciones entre las palabras.
- Las bases de datos vectoriales son bases de datos optimizadas para almacenar y buscar datos vectoriales. Permiten una búsqueda eficiente de vecino más cercano, que es el proceso de encontrar los vectores más similares a un vector de consulta determinado.
¿Cómo funciona la búsqueda de vectores?
La búsqueda de vectores funciona comparando el vector de consulta con todos los vectores de la base de datos. Los vectores más similares al vector de consulta se devuelven como resultados de la búsqueda.
La similitud entre dos vectores se puede medir con una variedad de métricas de distancia. La métrica de distancia más común es la similitud coseno, que mide el ángulo entre dos vectores.
6. Prueba la extensión de Búsqueda vectorial con Firestore
Antes de usar la extensión de Búsqueda vectorial con Firestore en la app para iOS que descargaste antes en este codelab, puedes probarla en Firebase console.
Leer la documentación
Las Extensiones de Firebase incluyen documentación sobre su funcionamiento.
- Cuando se termine de instalar la extensión, haz clic en el botón Comenzar.
- Consulta la pestaña "Cómo funciona esta extensión", en la que se explica lo siguiente:
- cómo calcular las incorporaciones de documentos agregándolos a la colección
notes
- Cómo consultar el índice llamando a la función que admite llamadas
ext-firestore-vector-search-queryCallable
- o cómo consultar el índice agregando un documento de consulta a la colección
_firestore-vector-search/index/queries
. - También se explica cómo configurar una función de incorporación personalizada. Esto es útil si ninguno de los LLM compatibles con la extensión cumple con tus requisitos y deseas usar un LLM diferente para calcular las incorporaciones.
- cómo calcular las incorporaciones de documentos agregándolos a la colección
- Haz clic en el vínculo Panel de Cloud Firestore para ir a tu instancia de Firestore.
- Navega al documento
_firestore-vector-search/index
. Debería mostrar que la extensión terminó de calcular las incorporaciones de todos los documentos de notas que creaste en un paso anterior de este codelab. - Para verificarlo, abre uno de los documentos de notas. Deberías ver un campo adicional llamado
embedding
de tipovector<768>
, así como un campostatus
.
Crea un documento de muestra
Puedes crear un documento nuevo en Firebase console para ver la extensión en acción.
- En el navegador de datos de Firestore, navega a la colección
notes
y haz clic en + Agregar documento, en la columna del medio. - Haz clic en ID automático para generar un nuevo ID de documento único.
- Agrega un campo llamado
text
de tipo cadena y pega texto en el campo value. Es importante que no sea lorem ipsum ni ningún otro texto aleatorio. Elige un artículo de noticias, por ejemplo. - Haz clic en Guardar.
- Observa cómo la extensión agrega un campo de estado para indicar que está procesando datos.
- Después de un momento, deberías ver un nuevo campo
embedding
con un valor devector<768>
.
Cómo realizar una consulta
La extensión de Búsqueda de vectores con Firestore tiene una función ingeniosa que te permite consultar el índice de documentos sin tener que conectar una app.
- En la sección Firestore de Firebase console, ve al documento
_firestore-vector-search/index
. - Haz clic en + Iniciar colección.
- Crea una subcolección nueva llamada
queries
. - Crea un documento nuevo y establece el campo
query
en un texto que aparezca en uno de tus documentos. Esto funciona mejor para las consultas semánticas, como "¿Cómo puedo asignar documentos de Firestore con Swift?" (siempre que al menos una de las notas que agregaste contenga texto que analice este tema). - Es posible que veas un error en el estado
- Esto se debe a que falta un índice. Para configurar el índice faltante, ve a la consola de Google Cloud de tu proyecto. Para ello, sigue este vínculo y, luego, selecciona tu proyecto en la lista.
- En el Explorador de registros de Cloud, ahora deberías ver un mensaje de error que dice "FAILED_PRECONDITION: Missing vector index configuration. Crea el índice requerido con el siguiente comando de gcloud: …"
- El mensaje de error también contiene un comando
gcloud
que debes ejecutar para configurar el índice faltante. - Ejecuta el siguiente comando desde la línea de comandos. Si no tienes la CLI de
gcloud
instalada en tu máquina, sigue las instrucciones que se indican aquí para instalarla. La creación del índice tarda unos minutos. Puedes verificar el progreso en la pestaña Índices de la sección Firestore de Firebase console.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
- Una vez que se configure el índice, podrás crear un nuevo documento de consulta.
- Ahora deberías ver una lista de los IDs de documento que coinciden en el campo de resultados.
- Copia uno de esos IDs y regresa a la colección
notes
. - Usa ⌘ + F para buscar el ID de documento que copiaste. Este es el documento que mejor coincide con tu búsqueda.
7. Implementa la búsqueda semántica
Ya es hora de conectar tu app para dispositivos móviles a la extensión de Búsqueda vectorial con Firestore y de implementar una función de búsqueda semántica que permita a los usuarios buscar sus notas con consultas en lenguaje natural.
Cómo conectar la función que admite llamadas para realizar consultas
La extensión de búsqueda vectorial con Firestore incluye una Cloud Function a la que puedes llamar desde tu app para dispositivos móviles para consultar el índice que creaste antes en este codelab. En este paso, establecerás una conexión entre tu app para dispositivos móviles y esta función que admite llamadas. El SDK de Swift de Firebase incluye APIs que permiten realizar llamadas a funciones remotas sin problemas.
- Regresa a Xcode y asegúrate de estar en el proyecto que clonaste en un paso anterior de este codelab.
- Abre el archivo
NotesRepository.swift
. - Busca la línea que contiene
private lazy var vectorSearchQueryCallable: Callable
= functions.httpsCallable("")
Para invocar una Cloud Function que admite llamadas, debes proporcionar el nombre de la función a la que quieres llamar.
- Ve a Firebase console de tu proyecto y abre el elemento de menú Funciones en la sección Compilación.
- Verás una lista de las funciones que instaló la extensión.
- Busca el que se llama
ext-firestore-vector-search-queryCallable
y copia su nombre. - Pega el nombre en el código. Ahora debería decir lo siguiente:
private lazy var vectorSearchQueryCallable: Callable<String, String> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
Llama a la función de consulta
- Busca el método
performQuery
. - Invoca tu función que admite llamadas.
let result = try await vectorSearchQueryCallable(searchTerm)
Como se trata de una llamada remota, es posible que falle.
- Agrega algunas medidas básicas de control de errores para detectarlos y registrarlos en la consola de Xcode.
private func performQuery(searchTerm: String) async -> [String] { do { let result = try await vectorSearchQueryCallable(searchTerm) return [result] } catch { print(error.localizedDescription) return [] } }
Conecta la IU
Para permitir que los usuarios busquen sus notas, implementarás una barra de búsqueda en la pantalla de la lista de notas. Cuando el usuario escribe un término de búsqueda, debes invocar el método performQuery
que implementaste en el paso anterior. Gracias a los modificadores de vista searchable
y task
que proporciona SwiftUI, esto solo requiere un par de líneas de código.
- Primero, abre
NotesListScreen.swift
. - Para agregar un cuadro de búsqueda a la vista de lista, agrega el modificador de vista
.searchable(text: $searchTerm, prompt: "Search")
justo encima de la línea.navigationTitle("Notes")
. - Luego, invoca la función de búsqueda agregando el siguiente código debajo:
.task(id: searchTerm, debounce: .milliseconds(800)) {
await notesRepository.semanticSearch(searchTerm: searchTerm)
}
Este fragmento de código llama a tu método semanticSearch
de forma asíncrona. Si proporcionas un tiempo de espera de 800 milisegundos, le indicas al modificador de tareas que anule el rebote en la entrada del usuario en 0.8 segundos. Esto significa que solo se llamará a semanticSearch
una vez que el usuario detenga la escritura por más de 0.8 segundos.
Tu código debería verse de la siguiente manera:
...
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")
...
Ejecuta la app
- Presiona ⌘ + R (o haz clic en el botón Ejecutar) para iniciar la app en el simulador de iOS.
- Deberías ver las mismas notas que agregaste en la app antes en este codelab, así como las que agregaste a través de Firebase console.
- Deberías ver un campo de búsqueda en la parte superior de la lista Notas.
- Escribe un término que aparezca en uno de los documentos que agregaste. Una vez más, esto funciona mejor para las consultas semánticas, como "¿Cómo puedo llamar a las APIs asíncronas de Firebase desde Swift?" (siempre que al menos una de las notas que agregaste contenga texto que analice este tema).
- Es probable que esperes ver el resultado de la búsqueda, pero, en su lugar, la vista de lista está vacía y la consola de Xcode muestra un mensaje de error: "Se llamó a la función con un argumento no válido".
Esto significa que enviaste los datos con el formato incorrecto.
Analiza el mensaje de error
- Para averiguar cuál es el problema, ve a Firebase console
- Ve a la sección Funciones.
- Busca la función
ext-firestore-vector-search-queryCallable
y abre el menú ampliado haciendo clic en los tres puntos verticales. - Selecciona Ver registros para ir al explorador de registros.
- Deberías ver un error
Unhandled error ZodError: [
{
"code": "invalid_type",
"expected": "object",
"received": "string",
"path": [],
"message": "Expected object, received string"
}
]
Esto significa que enviaste los datos en el formato incorrecto.
Usa los tipos de datos correctos
Para saber en qué formato espera la extensión que estén los parámetros, consulta la documentación de la extensión.
- Ve a la sección Extensiones en Firebase console.
- Haz clic en Administrar ->.
- En la sección Cómo funciona esta extensión, encontrarás una especificación de los parámetros de entrada y salida.
- Regresa a Xcode y navega a
NotesRepository.swift
. - Agrega el siguiente código al comienzo del archivo:
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
coincide con la estructura del parámetro de entrada que espera la extensión, según la documentación de la extensión. También contiene un atributoprefilter
anidado que necesitarás más adelante.QueryResponse
coincide con la estructura de la respuesta de la extensión. - Cómo buscar la especificación de la función que admite llamadas y actualizar los tipos de entrada y salida
private lazy var vectorSearchQueryCallable: Callable<QueryRequest, QueryResponse> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
- Actualiza la invocación de la función que admite llamadas en
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 [] } }
Vuelve a ejecutar la app
- Vuelve a ejecutar la app
- Escribe una búsqueda que contenga términos incluidos en una de tus notas.
- Ahora deberías ver una lista filtrada de notas.
Cómo aplicar un filtro previo a los datos del usuario
Antes de comenzar a bailar para celebrar, hay un problema con la versión actual de la app: el conjunto de resultados contiene datos de todos los usuarios.
Para verificarlo, ejecuta la app en otro simulador y agrega más documentos. Los documentos nuevos solo aparecerán en ese simulador. Si vuelves a ejecutar la app en el otro simulador, solo verás los documentos que creaste la primera vez.
Si realizas una búsqueda, notarás que la llamada a vectorSearchQueryCallable
muestra IDs de documentos que podrían pertenecer al otro usuario. Para evitar esto, debemos usar un prefiltro.
En performQuery
, actualiza el código de la siguiente manera:
let prefilters: [QueryFilter] = if let uid = user?.uid {
[QueryFilter(field: "userId", operator: "==", value: uid)]
}
else {
[]
}
let queryRequest = QueryRequest(query: searchTerm,
limit: 2,
prefilters: prefilters)
Esto filtrará previamente los datos según el ID del usuario que accedió. Como es de esperar, esto requiere que se actualice el índice de Firestore.
Ejecuta el siguiente comando desde la línea de comandos para definir un nuevo índice de Firestore que incluya userId
y las incorporaciones vectoriales en el 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
Una vez que se termine de compilar el índice, vuelve a ejecutar la app para verificar que funcione como se espera.
8. Felicitaciones
¡Felicitaciones por completar correctamente este codelab!
En este codelab, aprendiste a hacer lo siguiente:
- Configura una base de datos de Cloud Firestore con la búsqueda semántica habilitada.
- Crea una app de SwiftUI simple para interactuar con la base de datos.
- Implementa una barra de búsqueda con el modificador de vista de búsqueda y el modificador de tarea de SwiftUI.
- Llama a una Cloud Function para realizar una búsqueda semántica en la base de datos con la interfaz de llamada del SDK de Firestore.
Con los conocimientos que adquiriste en este codelab, ahora puedes compilar aplicaciones potentes que aprovechen las funciones de búsqueda semántica de Cloud Firestore para brindar a los usuarios una experiencia de búsqueda más intuitiva y eficiente.
Para obtener más información sobre el nuevo campo vectorial de Firestore y cómo calcular las incorporaciones vectoriales, consulta la documentación.