Cuando necesitas almacenar listas de objetos dentro de un documento y luego buscar sobre ellos con precisión, las consultas anidadas en Elasticsearch son la herramienta indicada. Permiten establecer una relación de pertenencia entre objetos y su documento padre, de modo que al encontrar una coincidencia en un objeto anidado, se devuelve el documento completo que lo contiene.
¿Qué es la anidación y cómo establece relaciones de pertenencia?
La anidación consiste en guardar una lista de objetos dentro de un documento. Esto genera una relación de pertenencia: cada objeto almacenado pertenece al documento que lo contiene [0:08]. Al realizar una búsqueda que coincida con un objeto anidado, Elasticsearch no devuelve solo ese objeto, sino todo el documento padre que lo alberga [0:30].
Este comportamiento es fundamental para modelar datos jerárquicos. Por ejemplo, un restaurante puede tener varias categorías asociadas, y al buscar por una categoría específica, se obtiene toda la información del restaurante.
¿Cómo crear un índice con campos nested en Elasticsearch?
Para trabajar con objetos anidados, primero se define un mapeo (mapping) que especifique el tipo nested en el campo correspondiente [1:07]. El ejemplo práctico utiliza un índice de restaurantes con la siguiente estructura:
- nombre: campo de tipo text que almacena el nombre del restaurante.
- categorías: campo de tipo nested que contiene una lista de objetos [1:27].
Dentro de cada objeto anidado de categorías se definen dos propiedades:
- nombre: de tipo keyword, porque interesa buscar por el nombre exacto de la categoría, no por coincidencias parciales [1:48].
- principal: de tipo boolean, que indica si esa categoría es la principal del restaurante [1:58].
Una vez definido el mapeo, se envía mediante un PUT y Elasticsearch confirma la creación del índice con un acknowledged en true [2:18].
¿Cómo se insertan documentos con objetos anidados?
Se crean documentos enviando un PUT a la ruta del índice con el identificador del documento. Cada restaurante incluye un arreglo de categorías como lista de objetos [2:40]. Los tres restaurantes de ejemplo son:
- McDonald's: categorías comida rápida (principal: true), desayunos y hamburguesas.
- Burger King: categorías hamburguesas (principal: true) y comida rápida.
- Subway: categorías sándwiches (principal: true) y comida saludable.
Cada restaurante puede tener varias categorías, pero solo una es la principal [2:10]. Esto permite filtrar con mayor granularidad en las búsquedas.
¿Cómo ejecutar consultas nested sobre campos anidados?
La consulta anidada utiliza el tipo nested dentro del bloque query [4:36]. Este tipo de query requiere dos elementos esenciales:
- path: el nombre del campo anidado sobre el cual se busca, en este caso
categorías [4:55].
- query: la consulta que se aplica sobre los objetos anidados.
¿Cómo combinar condiciones con consultas booleanas nested?
Dentro de la query anidada se puede usar una consulta booleana con cláusula must y un term para buscar valores exactos [5:08]. La notación categorías.nombre indica que se busca el campo nombre dentro del objeto anidado categorías [5:18].
Al buscar comida saludable, Elasticsearch devuelve únicamente Subway [5:38]. Al cambiar a comida rápida, se obtienen McDonald's y Burger King [5:48], ya que ambos contienen esa categoría.
Para refinar la búsqueda, se añade una segunda condición en el must: que categorías.principal sea true [6:15]. Esto filtra restaurantes donde la categoría buscada sea además la principal. Al buscar comida rápida con principal en true, solo aparece McDonald's [6:35], porque Burger King tiene comida rápida pero con principal en false.
Esta capacidad de combinar múltiples condiciones sobre objetos anidados dentro de una sola consulta booleana es lo que hace a las nested queries tan potentes para filtrar datos complejos.
Si has trabajado con estructuras similares o tienes dudas sobre cómo aplicar consultas anidadas en tu proyecto, comparte tu experiencia en los comentarios.