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 de vectores con Firestore para calcular las 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 asígnale el nombre Firestore Vector Search Lab.
- Haz clic para avanzar por las opciones de creación de proyectos. 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 la Información sobre los proyectos de Firebase.
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 las 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 utiliza la autenticación anónima para permitir que los usuarios comiencen a usar la app sin tener que crear primero una cuenta. Esto da como resultado un proceso de integración sin inconvenientes. 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 del lado izquierdo de Firebase console, haz clic en Compilación > Autenticación. Luego, haz clic en Comenzar.
- Ahora te encuentras en el panel de Authentication. Allí puedes ver los usuarios que se registraron, configurar los 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 Anónimo, cambia la opción a Habilitar y, luego, haz clic en Guardar.
Configura Cloud Firestore
Esta aplicación de Swift usa Cloud Firestore para guardar notas. A continuación, te mostramos cómo configurar Cloud Firestore:
- En el panel del lado izquierdo de Firebase console, haz clic en Compilación > Base de datos de Firestore. Luego, haz clic en Crear base de datos.
- Selecciona la ubicación de tu base de datos y asegúrate de elegir una ubicación en la que Gemini esté disponible (puedes usar us-central1). Sin embargo, ten en cuenta que esta ubicación no se puede cambiar más adelante. Haz clic en Siguiente.
- Selecciona la opción Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad. El modo de prueba garantiza que puedas escribir con libertad en la base de datos durante el desarrollo.
- Haz clic en Crear para crear la base de datos.
3. Conectar la app 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 aplicación 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 quieres, 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 forma de hacerlo es colocarla 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. Puedes finalizar el proceso haciendo clic en Ir a la consola.
Ejecuta la app
Es momento de que pruebes 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 un par de 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 de vectores 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 la extensión de Firestore".
Esta acción te llevará a la página de detalles de la extensión, donde podrás obtener más información sobre la extensión, 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
Las Extensiones de Firebase usan Cloud Functions para Firebase, que requiere que tu proyecto esté en el plan Blaze (pago por uso). Para poder usar la búsqueda de vectores con la extensión de Firestore, debes actualizar tu proyecto.
- Haz clic en Actualizar proyecto para continuar.
- Selecciona una cuenta de facturación existente o crea una nueva. Haz clic en Continuar.
- Establece un presupuesto (p.ej., USD 10), haz clic en Continuar y, luego, en Comprar.
- Revisa las APIs habilitadas y los recursos creados.
- Habilita los servicios requeridos.
- Cuando habilites Cloud Storage, selecciona el modo de prueba para las reglas de seguridad.
- Confirma que Cloud Storage usará la misma ubicación que tu instancia de Cloud Firestore.
- 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 LLM.
- Ruta de recopilación: notas
- Límite predeterminado de consultas: 3
- Nombre del campo de entrada: text
- Nombre del campo de salida: embedding
- Nombre del campo de estado:* *status*
- Incorporar documentos existentes: Sí
- Actualizar documentos existentes: Sí
- Ubicación de Cloud Function: us-central1
- Haz clic en Instalar extensión para finalizar la instalación.
Esto podría tardar unos minutos. Mientras esperas a que se complete la instalación, puedes avanzar a la siguiente sección del instructivo y leer información general sobre las incorporaciones vectoriales.
5. Formación
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 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. Se crean entrenando una red neuronal en un gran corpus de texto y aprendiendo las relaciones entre palabras.
- Las bases de datos vectoriales son bases de datos optimizadas para almacenar y buscar datos vectoriales. Permiten una búsqueda eficiente de vecinos más cercanos, 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 consiste en comparar 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 usando diversas 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 de vectores con Firestore
Antes de usar la extensión de Búsqueda de vectores con Firestore en la app para iOS que descargaste antes en este codelab, puedes probar la extensión en Firebase console.
Leer documentación
Las Extensiones de Firebase incluyen documentación sobre cómo funcionan.
- Una vez que se termine de instalar la extensión, haz clic en el botón Get started.
- Consulte la pestaña "Cómo funciona esta extensión", donde se explica:
- cómo calcular 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, lo que es útil si ninguno de los LLM compatibles con la extensión cumple con tus requisitos, y si deseas usar un LLM diferente para procesar las incorporaciones.
- cómo calcular incorporaciones de documentos agregándolos a la colección
- Haz clic en el vínculo del 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 se trate de lorem ipsum ni de otro texto aleatorio. Por ejemplo, elige un artículo de noticias. - Haz clic en Guardar.
- Observa cómo la extensión agrega un campo de estado para indicar que está procesando datos.
- Después de unos breves momentos, deberías ver un nuevo campo
embedding
con un valor devector<768>
.
Realiza una consulta
La extensión de Búsqueda de vectores con Firestore tiene una función muy útil que te permite consultar el índice del documento 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 (+ Start collection).
- Crea una nueva subcolección con el nombre
queries
. - Crea un documento nuevo y establece el campo
query
en un texto que aparezca en uno de tus documentos. Esta opción funciona mejor para consultas semánticas, como “¿Cómo puedo asignar documentos de Firestore con Swift” (siempre que al menos una de las notas que agregaste tenga texto en el que se aborde este tema). - Es posible que veas un error en el estado
- Esto se debe a que falta un índice. Si quieres establecer la configuración de índices faltantes, ve a la consola de Google Cloud de tu proyecto. Para ello, sigue este vínculo y selecciona tu proyecto de la lista
- En el Explorador de registros de Cloud, ahora deberías ver un mensaje de error que dice "FAILED_PRECONDITION: Missing vector 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 tu línea de comandos. Si no tienes instalada la CLI de
gcloud
en tu máquina, sigue estas instrucciones 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 el índice está configurado, puedes 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 del documento que copiaste (este documento es el que mejor coincide con tu consulta).
7. Implementa la búsqueda semántica
Por último, debes conectar tu app para dispositivos móviles a la extensión de búsqueda de vectores con Firestore y, luego, implementar una función de búsqueda semántica que permitirá a tus usuarios buscar en sus notas con consultas en lenguaje natural.
Conecta la función que admite llamadas para realizar consultas
La extensión de búsqueda de vectores con Firestore incluye una Cloud Function a la que puedes llamar desde tu app para dispositivos móviles a fin de 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 facilitan la llamada a funciones remotas.
- Vuelve 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
.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
. - Llama a la función que admite llamadas invocando a
let result = try await vectorSearchQueryCallable(searchTerm)
Como esta es una llamada remota, es posible que falle.
- Agrega la administración de errores básicos 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 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 a continuación:
.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
cuando el usuario deje de escribir durante 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 mediante Firebase console
- Deberías ver un campo de búsqueda en la parte superior de la lista Notes.
- Escribe un término que aparezca en uno de los documentos que agregaste. Una vez más, esto funciona mejor para 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 trate 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: “The function was called with an invalid argumento” (Se llamó a la función con un argumento no válido).
Esto significa que enviaste los datos en el formato incorrecto.
Analiza el mensaje de error
- Para averiguar cuál es el problema, ve a Firebase console
- Ir 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 su documentación.
- Ve a la sección Extensiones de 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. - Encuentra la especificación de la función que admite llamadas y actualiza 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
- Escribir una búsqueda que contenga términos incluidos en una de tus notas
- Ahora deberías ver una lista filtrada de notas.
Filtra previamente 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 los IDs de documento que podrían pertenecer al otro usuario. Para evitar esto, debemos usar un filtro previo.
En performQuery
, actualiza tu 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
Cuando 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.
- Crear una app simple de SwiftUI para interactuar con la base de datos
- Implementa una barra de búsqueda con el modificador de vistas de búsqueda de SwiftUI y el modificador de tareas.
- Llama a una Cloud Function para realizar una búsqueda semántica en la base de datos con la interfaz que admite llamadas del SDK de Firestore.
Con el conocimiento que adquiriste en este codelab, ahora puedes compilar aplicaciones potentes que aprovechan las capacidades de búsqueda semántica de Cloud Firestore para brindarles a los usuarios una experiencia de búsqueda más intuitiva y eficiente.
Para obtener más información sobre el nuevo campo de vectores de Firestore y cómo calcular las incorporaciones de vectores, consulta la documentación.