LangChain4j con Elasticsearch como almacén de incrustaciones

LangChain4j (LangChain para Java) tiene Elasticsearch como almacén de incrustación. Descubre cómo usarlo para construir tu aplicación RAG en Java puro.

Experimenta con Elasticsearch: Sumérgete en nuestros cuadernos de muestra, inicia una prueba gratuita del cloud o prueba Elastic en tu máquina local ahora.


En la publicación anterior, descubrimos qué es LangChain4j y cómo:

  • Habla con los LLMs implementando un ChatLanguageModel y un ChatMemory
  • Conserva el historial de chats en memoria para recordar el contexto de una conversación previa con un LLM

Esta entrada del blog trata sobre cómo:

  • Crear incrustaciones vectoriales a partir de ejemplos de texto
  • Almacenar incrustaciones vectoriales en el almacenamiento de incrustaciones de Elasticsearch
  • Búsqueda de vectores similares

Crear incrustaciones

Para crear embeddings, necesitamos definir un EmbeddingModel a emplear. Por ejemplo, podemos usar el mismo modelo de mistral que usamos en la publicación anterior. Estaba corriendo con ollama:

Un modelo es capaz de generar vectores a partir de texto. Aquí podemos comprobar el número de dimensiones generadas por el modelo:

Para generar vectores a partir de un texto, podemos usar:

O si también queremos proporcionar metadatos para filtrar cosas como texto, precio, fecha de lanzamiento o lo que sea, podemos usar Metadata.from(). Por ejemplo, aquí agregamos el nombre del juego como campo de metadatos:

Si quieres ejecutar este código, por favor echa un vistazo a la clase Step5EmbedddingsTest.java .

Agregar Elasticsearch para almacenar nuestros vectores

LangChain4j proporciona un almacén de incrustación en memoria. Esto es útil para realizar pruebas sencillas:

Pero obviamente, esto no podría funcionar con un conjunto de datos mucho mayor porque este almacén almacena todo en memoria y no tenemos memoria infinita en nuestros servidores. Así que, en su lugar, podríamos almacenar nuestras incrustaciones en Elasticsearch, que por definición es "elástico" y puede escalar hacia arriba y hacia fuera con tus datos. Para ello, agregamos Elasticsearch a nuestro proyecto:

Como notasteis, también agregamos el módulo Elasticsearch TestContainers al proyecto, para poder iniciar una instancia de Elasticsearch a partir de nuestras pruebas:

Para usar Elasticsearch como almacén de embebed, "solo" tienes que cambiar del almacén de datos en memoria de LangChain4j al de Elasticsearch:

Esto almacenará tus vectores en Elasticsearch en un índice default . También puedes cambiar el nombre del índice por algo más significativo:

Si quieres ejecutar este código, por favor echa un vistazo a la clase Step6ElasticsearchEmbedddingsTest.java .

Búsqueda de vectores similares

Para buscar vectores similares, primero necesitamos transformar nuestra pregunta en una representación vectorial usando el mismo modelo que usamos anteriormente. Ya lo hicimos, así que no es difícil hacerlo de nuevo. Ten en cuenta que en este caso no necesitamos los metadatos:

Podemos construir una solicitud de búsqueda con esta representación de nuestra pregunta y pedir al almacén de incrustaciones que encuentre los primeros vectores principales:

Podemos iterar sobre los resultados ahora e imprimir algo de información, como el nombre del juego que proviene de los metadatos y el puntaje:

Como era de esperar, esto nos da "Out Run" como primer éxito:

Si quieres ejecutar este código, por favor echa un vistazo a la clase Step7SearchForVectorsTest.java .

Tras bambalinas

La configuración predeterminada para la tienda de incrustación de Elasticsearch emplea la consulta aproximada kNN detrás de escena.

Pero esto podría cambiar proporcionando otra configuración (ElasticsearchConfigurationScript) distinta a la predeterminada (ElasticsearchConfigurationKnn) en la tienda de incrustación:

La implementación ElasticsearchConfigurationScript ejecuta entre bastidores una consulta script_score usando una función cosineSimilarity.

Básicamente, al llamar:

Esto ahora llama:

En ese caso, el resultado no cambia en términos de "orden", sino que solo se ajusta el puntaje porque la llamada cosineSimilarity no emplea ninguna aproximación, sino que calcula el coseno para cada uno de los vectores emparejados:

Si quieres ejecutar este código, por favor echa un vistazo a la clase Step7SearchForVectorsTest.java .

Conclusión

Explicamos lo fácil que es generar incrustaciones a partir de tu texto y cómo puedes almacenar y buscar los vecinos más cercanos en Elasticsearch usando dos enfoques diferentes:

  • Usando la consulta de knn aproximada y rápida con la opción de ElasticsearchConfigurationKnn por defecto
  • Usando la consulta de script_score exacta pero más lenta con la opción ElasticsearchConfigurationScript

El siguiente paso será construir una aplicación completa de RAG, basada en lo que aprendimos aquí.

Contenido relacionado

¿Estás listo para crear experiencias de búsqueda de última generación?

No se logra una búsqueda suficientemente avanzada con los esfuerzos de uno. Elasticsearch está impulsado por científicos de datos, operaciones de ML, ingenieros y muchos más que son tan apasionados por la búsqueda como tú. Conectemos y trabajemos juntos para crear la experiencia mágica de búsqueda que te dará los resultados que deseas.

Pruébalo tú mismo