Consulta SQL++ / N1QL

Procesamiento recursivo de consultas en SQL++ (N1QL)

Es muy probable que se haya encontrado con problemas con búsquedas jerárquicas o navegación por grafos en tu aplicación como desarrollador que maneja casos de uso del mundo real. Y, por razones obvias, prefieres resolverlos en el base de datos y no en el cliente.

¿Qué son las búsquedas jerárquicas?

La búsqueda jerárquica hace referencia al proceso de búsqueda y recuperación de datos de una estructura jerárquica, como una árbol o una relación padre-hijo. Implica navegar por los niveles o capas de la jerarquía para localizar elementos de datos específicos o información relacionada, por ejemplo, organigramas, sistemas de archivos y árboles de categorías.

Los grafos son básicamente árboles que pueden tener ciclos, por lo que, además, también podríamos cubrir casos de uso como la búsqueda de rutas, etc. siempre que dispongamos de configuraciones adicionales para tratar los ciclos.

hierachical lookups

Considere un ejemplo en el que se utiliza una colección de empleados con una estructura jerárquica. Los empleados están organizados en una relación gerente-subordinado. Vamos a realizar operaciones en esta jerarquía de empleados usando Couchbase y JavaScript UDFs para demostrar la solución.

Pasando de la Recogida de empleados que podemos recuperar:

i) nivel genérico de empleado:

ii) jerarquía para cada empleado:

De qué trata este blog

Realmente te gusta el flexibilidad de bases de datos NoSQL, y su modelo de datos subyacente es JSON, por eso ha elegido Couchbase para sus necesidades de base de datos (gran elección, por cierto :-) ).

Ahora que tienes Couchbase como base de datos, quieres resolver el problema mencionado. Después de investigar un poco en SQL Documentos de referencia lingüística ha llegado a la conclusión de que no hay Declaración o Función en SQL++ para resolver nuestro problema, como el graphLookup API en MongoDB o CTE recursivo en bases de datos SQL.

Pero con la infraestructura existente, los usuarios pueden emular CTE recursivos utilizando UDF de JavaScript. En las secciones siguientes se explica cómo hacerlo y mucho más.

Solución a las consultas recursivas

Para implementar esta solución, necesitamos crear un UDF de JavaScript que utilice un algoritmo de búsqueda breadth-first para recorrer la jerarquía de empleados. La UDF toma un consulta de anclaje, a consulta recursivay opciones de configuración como parámetros. La consulta de anclaje recupera el conjunto inicial de empleados, mientras que la consulta recursiva hace referencia a los resultados de la iteración anterior utilizando la función $1 parámetro. Las opciones de configuración permiten la personalización, incluidos los criterios de salida anticipada, los argumentos para las consultas internas, la detección de ciclos, el modo de explicación para la planificación de consultas y las opciones de registro.

Cómo utilizar las consultas internas

La consulta de anclaje obtiene el documentos de nivel raíz de la colección de destino.

La consulta recursiva puede utilizar un ÚNASE A con un lado como $1 y la otra como colección de destino, para explotar la relación padre-hijo y realizar el recorrido de un nivel a otro.

En nuestra función, $1 hace lo mismo que el alias CTE en CTE recursivo.

Para comprender mejor cómo utilizamos SQL++ (N1QL) en las UDF de JavaScript, eche un vistazo a De N1QL a JavaScript y viceversa.

Veamos ahora el proceso paso a paso. En primer lugar, ¿es realmente necesario que el procesamiento recursivo de consultas sea una función recursiva?

No, esta sería una mala elección teniendo en cuenta la complejidad temporal (la misma funcionalidad en recursivo podría ser exponencial, pero lineal en un enfoque iterativo) y todas las demás cuestiones como marcos, etc., que vienen junto con la recursividad. Si estás interesado, echa un vistazo a esto artículo sobre la conversión de funciones de recursividad de cola a iterativas. Además, las UDF de JS tienen un preajuste profundidad de recursión máxima de 128; esto no es preferible para lo que intentamos hacer.

En pocas palabras, cualquier tarea iterativa hace lo siguiente:

Nos gustaría agradecer este artículo por su planteamiento.

Puntos de reflexión

¿Cómo mantenemos la expresión de estado y pasarlo como parámetro a la consulta (parte recursiva aquí)?

    • Utilizamos la capacidad de SQL++ para pasar parámetros de consulta dinámicos y utilizar consultas parametrizadas para mantener el valor del estado en todos los niveles.
    • Utilizamos $1 en la cláusula recursiva para referirse a los resultados de iteraciones anteriores, es decir, la expresión de estado

¿Cómo podemos optimizar?

    • Preparar inicialmente tanto las consultas ancla como las recursivas para poder reutilizar los planes de consulta en el momento de la ejecución.
    • Encontrar una manera de mirar el plan de consulta( similar a un EXPLICAR ) para que podamos generar índices apropiados para las sentencias internas (ancla y recursivas).

El resumen de alto nivel de la aplicación es el siguiente:

Código para CTE recursivo utilizando JS UDFs 

Se trata de una implementación muy ingenua para empezar a funcionar. Configuramos el Búsqueda exhaustiva estableciendo el flujo de órdenes según el resumen anterior. Aquí está el código, de este Gist enlace:

Cómo añadir la función

He aquí una enlace para añadirlo a una biblioteca JavaScript (por ejemplo "mi biblioteca") dentro de su servicio de consulta, y un enlace para crear la UDF a partir de la biblioteca añadida.

Cree la UDF desde la biblioteca utilizando SQL++:

Utilización

Argumento 1: Ancla consulta, cadena
Argumento 2: Recursivo consulta, cadena (usos $1(expresión del estado) para referirse a los resultados de la iteración anterior )
Argumento 3: Config opcionesobjeto

Todos son obligatoriopero puede pasar un objeto vacíoes decir, {} si no está utilizando ninguna opción de configuración.


Opciones de configuración

Salida anticipada

levelLimit(1 a N) - Especifica el nivel en el que podemos parar. El recuento de niveles comienza en 0 para obtener resultados de anclaje, 1 para la primera iteración/nivel, 2 para el segundo, etc.

Argumentos de la consulta interna

anchorArgs - como se nombra, por ejemplo,{"arg:1} o argumentos posicionales, por ejemplo [1] para utilizar en la consulta de anclaje.

recursiveArgs - sólo pueden ser argumentos posicionales, y 0 debe reservarse para la expresión de estado. Por ejemplo: [0, 1] - fijar siempre el índice 0 ($1 arg) a 0por lo que podemos utilizarla en la cláusula recursiva como expresión de estado.

Detección de ciclo

cycleFields - Matriz de nombres de campo, por ejemplo, ["_de", "_a"]

Explique

explique - Comprobar el plan de consulta en los registros (conjuntos registro por defecto)

Registros

registro - Visualizar registros que ayudan cuando se quiere registrar mientras se desarrolla

 

Ejemplos de consultas


1. Contar números del 1 al N - ejemplo más sencillo de una consulta que muestra cómo funciona la CTE recursiva.
    
Haz una breve pausa para pensar cómo podrías hacer esto en N1QL sin la función utilidad que desarrollamos ahora. ¿Es posible? (¿O acabamos de hacer N1QL ¡Turing completo!)

2. Ejemplo de empleados - se refieren a la colección de empleados que vimos antes.

A. Encontrar el nivel organizativo de un empleado

B. Por empleado depende de la jerarquía

Consulta de anclaje:

Esto puede parecer demasiado verboso cuando se añade un DONDE predicado de la consulta externa. We puede utilizar el anchorArgs opción ¡para mitigarlo!

Argumentos (anchorArgs/recursiveArgs)

Explique

Proporcione {"explain": true} - puede ver el plan de consulta en el campo de registro 

Salida anticipada

Establecer levelLimit como {"levelLimit":2} - si sólo desea 2 niveles de recursividad

 

Detección del ciclo

Sin detección de ciclo la consulta para encontrar la jerarquía de nivel de empleado irá a un bucle infinito y se bloquean al agotarse el tiempo de espera de la función, desperdiciando recursos de la CPU.

Teniendo en cuenta que cuando trabajamos con datos gráficos es muy probable que tengamos ciclos presentes y es el responsabilidad de la persona que llama a la función para establecer la detección de ciclo de los campos apropiados.

Aquí, el "employee_id", "manager_id"  es suficiente para salir en ciclo.

Gracias por seguirnos en este desafiante tema, ¡esperamos que te revele más opciones para algunos de tus retos de consulta recursiva!

Referencias

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por Gaurav Jayaraj - Ingeniero de software

Gaurav Jayaraj es becario en el equipo de consultas de Couchbase R&D. Gaurav es licenciado en Informática por la Universidad PES de Bangalore.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.