• Updated:

Embeddings y Vector Search

Un ordenador no puede entender texto ni relaciones semánticas o significados entre palabras. Solo puede entender números. Este problema lo resolvemos mediante el uso de embeddings.

Un embedding es la representación de texto (en forma de números) en un espacio vectorial. Esto permite a los modelos de IA comparar y operar sobre el significado de las palabras.

flowchart TD
    A["perro"] --> B{{Modelo de embedding}}
    B --> C["[-0.003, 0.043, ..., -0.01]"]
    
    N1["(texto que queremos convertir)"]:::note --> A
    N2["(vectores con contenido semántico)"]:::note --> C
    
    classDef note fill:none,stroke:none,color:#777;    

Los vectores de cada palabra o documento capturan el significado semántico del texto.

  • perro estará cerca de mascota
  • contrato estará lejos de playa

Vector vs SQL databases

El problema con las bases de datos típicas es que solo buscan matches exactos. Si yo busco por coche solo me sacará las entradas que contengan coche.

En cambio las BBDD vectoriales pueden interpretar la semántica de las palabras mediante vectores. Si busco por coche puede sacarme valores como sedán, SUV, Land Rover, etc.

Las BBDD vectoriales son muy buenas cuando necesitamos buscar items similares por proximidad uno respecto al otro.

Algunos ejemplos de uso son:

  • buscar películas parecidas (Netflix)
  • Recomendadores de items parecidos en tiendas online (Amazon)
  • buscar canciones parecidas (Spotify)

Como ejecutar una búsqueda (query) mediante vectores

(You can see the code here)

Necesitamos:

  • Una BBDD Vectorial (CosmosDB)
  • Un modelo para transformar los embeddings (text-embedding-3-large)

El flujo completo es el siguiente:

  1. Usar un embedding model para obtener los vectores del contenido que queremos indexar
  2. Insertar ambos en una BBDD vectorial: el texto original y los vectores del contenido
  3. Cuando queramos ejecutar una query usar el mismo embedding model de antes ahora con la query
  4. Con el embedding resultante buscamos vectores similares en la BBDD y sacamos el texto original

Introducir vectores en CosmosDB

Para poder buscar necesitamos rellenar antes la BBDD con contenido. Lo mantenemos simple. Metemos

  • un ID a mano
  • el texto original
  • los vectores resultado de hacer el embedding sobre el texto original

El pseudocódigo se ve así y se ejecuta de uno en uno

# this sends the text to the model text-embedding-3-large 
vectors = createEmbeddingsForText(text)
item = {
	"id": "x",
	"original_text": text,
	"vectors": vectors
}
uploadToCosmosDB(item)

ejemplos de los datos que guardo

{
	"id": "1",
	"original_text": "A shiba walks alone in the park",
	"vectors": [-0.003, 0.043, -0.001]
}
{
	"id": "2",
	"original_text": "A dog sleeps on the bed",
	"vectors": [0.011, 0.031]
}
{
	"id": "3",
	"original_text": "A wild bear hunts in the mountain",
	"vectors": [-0.021, 0.071]
}
{
	"id": "4",
	"original_text": "Two boats collide in the ocean",
	"vectors": [0.032, 0.011]
}
{
	"id": "5",
	"original_text": "A car travels during the night",
	"vectors": [0.089, -0.045]
}

Ejecutar una búsqueda

Ahora si realizo una búsqueda, puedo buscar por proximidad semántica y no solo por matches exactos como en una BBDD tradicional.

pseudocódigo

text_to_search = "inu"
# it needs to be the same exact model as before
vectors = createEmbeddingsForText(text)
# we search for the top 3 results
results = queryCosmosDB(vectors)

Aunque inu no se encuentra en la BBDD como tal, vemos que el hit más fuerte es el que contiene shiba. El segundo más fuerte (aunque bastante distanciado) es el que contiene dog.

text: 'A shiba walks alone in the park', cosine_distance: 0.57116
text: 'A dog sleeps on the bed', cosine_distance: 0.28378
text: 'A wild bear hunts in the mountain', cosine_distance: 0.21090

Si por el contrario busco vehicle ahora los hits más fuertes son los que contienen medios de transporte

text: 'A car travels during the night', cosine_distance: 0.37720
text: 'Two boats colide in the ocean', cosine_distance: 0.23041
text: 'A shiba walks alone in the park', cosine_distance: 0.15880

BM25 vs Vector Search

Best Matching 25 es uno de los algoritmos de búsqueda más usados. Se usa para hacer búsquedas basadas en keywords y se puede usar junto a búsquedas vectoriales para hacer búsquedas híbridas. Ayuda a encontrar búsquedas exactas por keywords que una búsqueda vectorial puede no encontrar.

Reference(s)

BM25 for Developers: A Guide to Smarter Keyword Search | by Doil Kim | Medium