Mejores prácticas de temas de conjuntos de datos múltiples para Amazon Quick Chat

Nota: Los temas a los que se hace referencia en este documento se refieren a la nueva experiencia de Temas (no a los Temas heredados). Para obtener detalles sobre las diferencias, consulte Creación de una capa semántica unificada en conjuntos de datos con temas de múltiples conjuntos de datos en Amazon Quick.

La mayoría de las preguntas comerciales del mundo real abarcan varias tablas. Un minorista que quiera comprender los ingresos netos por categoría de producto debe recurrir a una tabla de datos de ventas, una tabla de datos de devoluciones y una dimensión del producto. Cada uno de estos vive en un conjunto de datos separado. Hasta hace poco, unir esos conjuntos de datos requería que un ingeniero de datos se uniera previamente a ellos y entregara un único conjunto de datos a Amazon Quick Sight antes de que cualquier analista pudiera hacer una pregunta.

Los temas de conjuntos de datos múltiples de Amazon Quick Sight cambian esa ecuación al permitir que los equipos de análisis reúnan múltiples conjuntos de datos en un solo tema de dos maneras. Puede definir claves de relación explícitas (que se tratan en la publicación complementaria, Mejores prácticas de modelado de datos para relaciones entre conjuntos de datos múltiples de Amazon Quick Sight, o puede equipar el motor de IA generativa con suficiente contexto semántico para escribir SQL en sí. Esta publicación se centra en la segunda ruta: SQL generado por IA y impulsado por chat.

Cuando configura un tema para chat, no necesita definir relaciones por adelantado. En su lugar, crea una capa semántica que incluye instrucciones personalizadas a nivel de conjunto de datos, instrucciones a nivel de tema, sinónimos de campo y descripciones de campo. La IA utiliza ese contexto para generar SQL sensible al contexto en el momento de la consulta. Esto pone a su alcance uniones externas, uniones, subconsultas, autouniones, comparaciones entre granos y lógica de unión condicional, sin restricciones estructurales en el gráfico de relaciones.

Esta publicación está dirigida a arquitectos de datos, ingenieros de inteligencia empresarial (BI) e ingenieros de análisis que crean u optimizan temas Quick Sight para la exploración basada en chat en lenguaje natural. Saldrás con:

Una comprensión clara de en qué se diferencia la generación de SQL basada en chat de los temas de relaciones definidas. Un marco en capas, Semantic Guidance Stack, para estructurar todos los metadatos que guían la IA. Ocho mejores prácticas concretas, cada una con ejemplos, antipatrones e instrucciones de muestra. Técnicas para manejar patrones complejos: uniones externas, muchos a muchos, jerarquías recursivas, dimensiones de juego de roles y comparaciones entre grano. Un marco de decisión para elegir entre relaciones definidas, orientación únicamente semántica y enfoques híbridos. Un recorrido completo de principio a fin utilizando un tema de análisis minorista con cinco conjuntos de datos.

En qué se diferencia el chat de las relaciones definidas

Antes de profundizar en las mejores prácticas, es útil comprender la distinción arquitectónica fundamental entre los dos modos de conjuntos de datos múltiples de Quick Sight.

Cuando define relaciones explícitas en un tema, Quick Sight crea un gráfico de unión lógica y ejecuta uniones internas en el momento de la consulta. El gráfico debe ser un gráfico acíclico dirigido (DAG), admite hasta 12 conjuntos de datos y produce resultados deterministas porque cada ruta de unión está preespecificada. Esto se adapta a escenarios de informes gobernados en los que es necesario aplicar exactamente cómo se combinan las tablas.

Cuando un usuario hace una pregunta a través del Chat, la IA generativa de Quick Sight lee las relaciones definidas o la capa semántica de su tema (instrucciones, descripciones y sinónimos) y genera SQL para responder esa pregunta. La IA determina qué conjuntos de datos consultar, qué columnas usar, qué tipo de combinación es apropiado y cómo agregar el resultado. No hay ningún gráfico de unión precableado. La IA opera según la intención, no según la estructura.

Relaciones definidas por dimensión SQL generado por IA Definición de unión Explícito, predefinido en el tema Inferido por IA generativa en el momento de la consulta Tipos de unión admitidos Unión interna solo para tableros Interior, izquierda, derecha, exterior completo, unión, subconsulta Restricción del gráfico de relaciones Debe ser un gráfico acíclico dirigido (DAG): sin relación circular Sin restricción estructural Manejo de múltiples hechos Requiere claves de dimensión conformadas Puentes de IA a través de instrucciones Mecanismo de guía Claves de relación + metadatos del conjunto de datos Instrucciones personalizadas + sinónimos + Descripciones Flexibilidad Ligada al esquema Ligada a la intención Ideal para paneles gobernados, entornos regulados Análisis exploratorios, preguntas ad hoc, usuarios avanzados

Las relaciones definidas son barreras de seguridad: evitan que se intenten uniones incorrectas. Los metadatos semánticos son una guía: dirigen la IA hacia SQL correcto y contextualmente apropiado. Ambos tienen valor. La elección correcta depende de su escenario. Consulte la sección Marco de decisión más adelante en esta publicación.

Las relaciones definidas y la orientación semántica no son mutuamente excluyentes. Un tema híbrido puede definir relaciones para las uniones principales de hecho a dimensión y, al mismo tiempo, depende de instrucciones personalizadas para patrones exploratorios que quedan fuera del gráfico predefinido. La sección Marco de decisión explora esto más a fondo.

Para conocer las mejores prácticas de relación definida, consulte Mejores prácticas de modelado de datos para relaciones con múltiples conjuntos de datos de Amazon Quick Sight y Patrones de modelado de datos para relaciones con múltiples conjuntos de datos de Amazon Quick Sight.

La pila de orientación semántica

El motor de inteligencia artificial que impulsa Quick Chat se basa en siete capas de metadatos al generar SQL, formando colectivamente la pila de guía semántica. Comprender cada capa es la base para escribir metadatos eficaces.

Capa Fuente Definición Propósito Ejemplo 1 Salida del conjunto de datos; Conjunto de datos Instrucciones a nivel de conjunto de datos Defina el detalle, el propósito, las claves y las reglas comerciales de cada conjunto de datos individual. "Cada fila en SALES_FACT representa un artículo de línea en un pedido". 2 Tema Instrucciones a nivel de tema Defina la lógica entre conjuntos de datos, las reglas de desambiguación y los comportamientos de unión predeterminados "Cuando el usuario diga 'ventas', use SALES_FACT, no RETURNS_FACT". 3 salidas de conjuntos de datos; Sinónimos de campo Asigne vocabulario empresarial a nombres de campos técnicos “Ingresos”, “Línea superior”, “Ingresos” → monto_total 4 Salida del conjunto de datos; Campo Descripciones de campos Explicar la semántica de las columnas, las unidades, la posibilidad de nulos y los rangos válidos “order_date: fecha UTC en que el cliente realizó el pedido, nunca nulo, formato AAAA-MM-DD” 6 Exclusiones de columnas de transformación del conjunto de datos Elimine ruidos como claves internas, marcas de tiempo ETL y campos obsoletos Ocultar etl_load_timestamp, surrogate_key, is_deleted_flag 7 Transformación del conjunto de datos Campos calculados y filtros con nombre Cree previamente métricas comerciales comunes y definiciones de segmentos a las que la IA puede hacer referencia directamente Campo: “Ingresos netos” = ventas.monto – devoluciones.reembolso_monto

Cada capa reduce la incertidumbre de la IA sobre sus datos. Cuanto más precisamente complete cada capa, más estrecho será el espacio de interpretaciones SQL plausibles y más precisos serán los resultados generados. Un tema escasamente descrito con muchos conjuntos de datos producirá resultados poco fiables. Esto no se debe a que la IA sea incapaz, sino a que falta la información que necesita para tomar decisiones correctas.

Mejor práctica 1: escribir instrucciones a nivel de conjunto de datos como un diccionario de datos

Las instrucciones personalizadas a nivel de conjunto de datos son el primer punto de contacto de la IA con cada tabla y establecen el contexto para cada pregunta que toca ese conjunto de datos.

Que incluir

Propósito y grano de la tabla: Indique claramente lo que representa la tabla y lo que significa una fila. Esto evita que la IA cuente dos veces o agregue en el nivel incorrecto. Clave principal: identifique las columnas que identifican de forma única cada fila. Sugerencias de clave externa: dígale a la IA qué columna de este conjunto de datos coincide con qué columna de conjuntos de datos relacionados. Utilice frases en lenguaje natural: "Este conjunto de datos se une a PRODUCT_DIM en product_id". Reglas de negocio: Expresar cálculos derivados en inglés sencillo. "Los ingresos son iguales a la cantidad multiplicada por el precio unitario menos el importe_descuento". Esto reduce la posibilidad de que la IA inventa una fórmula incorrecta. Casos extremos conocidos: marcar columnas que aceptan valores NULL, valores centinela o códigos especiales. "Los registros order_status = 'VOID' deben excluirse de los cálculos de ingresos". Reglas de agregación: especifique la función de agregación correcta para cada medida. "Siempre SUMA los ingresos. No utilices PROMEDIO ni CONTAR".

Instrucciones buenas y malas: ejemplos

Considere el siguiente contraste para un conjunto de datos SALES_FACT:

Mala instrucción (demasiado genérica):

"Esta es la tabla de datos de ventas. Contiene información de ventas".

Buena instrucción (precisa y completa):

"SALES_FACT contiene una fila por artículo de línea de pedido. Clave principal: order_line_id (entero, nunca nulo). Grano: un artículo de línea = un producto en un pedido. Columnas clave: – order_id: enlaces a ORDER_HEADER_DIM.order_id – product_id: enlaces a PRODUCT_DIM.product_id – customer_id: enlaces a CUSTOMER_DIM.customer_id – order_date_key: enlaces a DATE_DIM.date_key (entero, formato AAAAMMDD) Ingresos = cantidad * precio_unitario – monto_descuento. Excluye siempre las filas donde order_status="VOID" de todos los cálculos de ingresos. La tabla se actualiza todas las noches a las 02:00 UTC.

Antipatrones a evitar

Instrucciones demasiado genéricas: "Esta tabla tiene datos de ventas". no le da a la IA ningún contexto procesable. Fragmentos de SQL demasiado prescriptivos: incrustar fragmentos de SQL sin formato en las instrucciones (por ejemplo, "siempre agregue WHERE is_deleted = 0") puede entrar en conflicto con la construcción de consultas de la IA. En su lugar, utilice reglas de lenguaje empresarial y aplique filtros permanentes a nivel de conjunto de datos en el editor de transformación de conjuntos de datos de Quick Sight. Reglas contradictorias: si establece que los ingresos deben ser SUMA a nivel de conjunto de datos y luego define una agregación PROMEDIO a nivel de campo, la IA recibirá señales contradictorias. Sea consistente en todas las capas.

Mejor práctica 2: escribir instrucciones a nivel de tema para lógica entre conjuntos de datos

Las instrucciones a nivel de conjunto de datos describen tablas individuales. Las instrucciones a nivel de tema le dicen a la IA cómo se relacionan las tablas entre sí, qué conjunto de datos tiene prioridad cuando los términos son ambiguos y cómo manejar los cálculos entre conjuntos de datos. Juntos le dan a la IA una imagen completa de su dominio.

Qué incluir en las instrucciones a nivel de tema

Relaciones conceptuales: describa cómo se conectan los conjuntos de datos incluso cuando no haya definido claves de relación formales. "SALES_FACT y RETURNS_FACT se vinculan a CUSTOMER_DIM en customer_id y a PRODUCT_DIM en product_id". Reglas de desambiguación: cuando el mismo término comercial pueda asignarse a múltiples conjuntos de datos o campos, indique a la IA cuál preferir. "Cuando el usuario pregunte sobre 'ventas', utilice SALES_FACT. Cuando el usuario pregunte sobre 'devoluciones' o 'reembolsos', utilice RETURNS_FACT. Para 'ventas netas', una ambas". Comportamiento de unión predeterminado: especifique la dirección de unión que preserve la semántica prevista. "Prefiera LEFT JOIN de las tablas de hechos a las tablas de dimensiones para que los hechos sin registros de dimensiones coincidentes no se eliminen silenciosamente". Resolución de múltiples hechos: explique cómo combinar múltiples tablas de hechos. "Para comparar los datos reales con los previstos, une DAILY_SALES a MONTHLY_FORECAST acumulando DAILY_SALES al nivel del mes primero, luego únete a Month_key y store_id". Abarcando definiciones de negocios: "Ingresos netos = SALES_FACT.total_amount menos RETURNS_FACT.refund_amount. Únase siempre en order_id para evitar el doble conteo". Navegación por jerarquía: "Jerarquía de productos: PRODUCT_DIM.product_id → PRODUCT_DIM.subcategory_id → PRODUCT_DIM.category_id. Avance en este orden para realizar un análisis detallado".

Ejemplo: bloque completo de instrucciones a nivel de tema (análisis minorista)

El siguiente ejemplo muestra un bloque de instrucciones a nivel de tema listo para producción para un tema de análisis minorista que contiene cinco conjuntos de datos:

Tema: Análisis minorista Conjuntos de datos en este tema: – SALES_FACT: artículos en línea de pedidos diarios (grano: un artículo en línea por pedido) – RETURNS_FACT: artículos en línea de pedidos devueltos (grano: una devolución por línea de pedido) – CUSTOMER_DIM: maestro de clientes (grano: una fila por cliente) – PRODUCT_DIM: catálogo de productos (grano: una fila por SKU de producto) – DATE_DIM: atributos de fecha (grano: una fila por día calendario) Desambiguación reglas: – "ventas", "ingresos", "pedidos" -> SALES_FACT – "devoluciones", "reembolsos", "créditos" -> RETURNS_FACT – "ventas netas", "ingresos netos" -> unirse a SALES_FACT LEFT JOIN RETURNS_FACT en order_line_id – "cliente", "comprador", "comprador" -> CUSTOMER_DIM – "producto", "artículo", "SKU", "categoría" -> PRODUCT_DIM Direcciones de unión predeterminadas: – SALES_FACT LEFT JOIN CUSTOMER_DIM en customer_id – SALES_FACT LEFT JOIN PRODUCT_DIM en product_id – SALES_FACT LEFT JOIN DATE_DIM en order_date_key = date_key Definiciones de conjuntos de datos cruzados: – Ingresos netos = SUM(SALES_FACT.total_amount) – SUM(RETURNS_FACT.refund_amount) – Tasa de retorno = COUNT(RETURNS_FACT.order_line_id) / COUNT(SALES_FACT.order_line_id) Nota de alineación de grano: – SALES_FACT y RETURNS_FACT son granos diarios. – Para agregaciones mensuales, GROUP BY DATE_DIM.year_month_key. Nota de seguridad a nivel de fila: – Cada conjunto de datos aplica su propio RLS. No intente eludir los filtros RLS.

Antipatrón: instrucciones contradictorias a nivel de conjunto de datos

Si su instrucción a nivel de conjunto de datos SALES_FACT dice "ingresos = cantidad * precio unitario – monto_descuento" y su instrucción a nivel de tema dice "ingresos netos = monto_total", la IA recibirá definiciones contradictorias. Asegúrese siempre de que las instrucciones a nivel de conjunto de datos y de tema sean coherentes. Las instrucciones a nivel de tema deben AGREGAR contexto entre conjuntos de datos, no redefinir la semántica de un solo conjunto de datos.

Mejor práctica 3: Diseñar sinónimos de cómo hablan realmente los usuarios

Los sinónimos cierran la brecha entre cómo los usuarios expresan preguntas y cómo su esquema técnico llama cosas. Un analista de negocios dice "ingresos", pero la columna de su base de datos es monto_total. Un gerente de marketing dice "abandono", pero su esquema lo marca como customer_status="abandonado". Sin sinónimos, la IA debe adivinar el mapeo y las conjeturas producen resultados inconsistentes.

Estrategia de cobertura de sinónimos

Organice sus sinónimos en cuatro niveles de vocabulario:

Lenguaje ejecutivo (nombres de KPI): los términos que utiliza el liderazgo en las juntas directivas. “Ingresos”, “EBITDA”, “Participación de Mercado”, “NPS”. Lenguaje del analista (definiciones de métricas): los términos que utiliza su equipo de BI. “Margen bruto”, “AOV” (valor promedio del pedido), “CAC” (coste de adquisición de clientes). Jerga de dominio: terminología específica de la industria. Para venta minorista: “SKU”, “planograma”, “contracción”. Para SaaS: “MRR”, “ARR”, “asientos”. Abreviaturas y siglas: “YTD”, “QTD”, “MTD”, “LTM”, “TTM”.

Tabla de mapeo de sinónimos de muestra

Expresión de usuario Campo técnico/Notas de filtro Ingresos, Ventas, Ingresos, Línea superior SALES_FACT.total_amount Asigne los cuatro términos a la misma columna Abandono, Desgaste, Clientes perdidos CUSTOMER_DIM.status = 'abandonado' El sinónimo se asigna a la condición filtrada, no solo a la columna AOV, Valor promedio del pedido, Canasta promedio SUM(total_amount)/COUNT(DISTINCT order_id) Documente la fórmula en la descripción del campo también Categoría, Departamento, Pasillo PRODUCT_DIM.category_name Asignación de jerga de dominio minorista Tienda, Ubicación, Sucursal, Tienda STORE_DIM.store_name Múltiples términos comerciales para el mismo concepto YTD, Año hasta la fecha Filtro DATE_DIM: año = año actual Y fecha <= hoy Sinónimo de inteligencia de tiempo

Directrices para la cantidad de sinónimos

Apunte a incluir de 3 a 7 sinónimos por columna consultada con frecuencia. Menos de 3 dejan lagunas en el vocabulario común. Más de 10 corren el riesgo de introducir términos ambiguos que coinciden con demasiados campos. Para campos técnicos internos o que rara vez se consultan, es apropiado utilizar sinónimos 0-1 o excluir el campo por completo.

Mejor práctica 4: enriquecer las descripciones de campos y los tipos semánticos

Las descripciones de los campos brindan a la IA una comprensión precisa del significado, la unidad, las limitaciones y el uso previsto de cada columna. Mientras que los sinónimos manejan el vocabulario y las instrucciones manejan la lógica, las descripciones manejan la semántica de los datos: lo que realmente representa el valor.

Escribir descripciones de campo efectivas

Escriba descripciones para un consumidor de IA, no para un lector humano. La IA se beneficia de información estructurada e inequívoca en lugar de depender del contexto. Cada descripción debe incluir:

Definición: Una frase precisa que indique lo que contiene la columna. Unidad o formato: USD, porcentaje (escala 0-1), AAAA-MM-DD o número entero. Capacidad de nulidad: "Nunca nulo" versus "Nulable; nulo indica que el cliente no ha realizado un pedido". Rango válido o valores enumerados: “Valores: PENDIENTE, PROCESANDO, ENVIADO, ENTREGADO, CANCELADO, ANULADO”. Comportamiento de agregación: "SUMA para totales; no PROMEDIE este campo".

Ejemplos de descripción de campos

Campo Descripción efectiva fecha_pedido La fecha del calendario en la que el cliente realizó el pedido. Zona horaria UTC. Formato: AAAA-MM-DD. Nunca nulo. Utilice este campo para todos los análisis de series temporales. Enlace a DATE_DIM.date_value para los atributos del calendario. unit_price El precio de venta por unidad del producto en el momento del pedido, en USD. Anulable antes de 2020 (datos heredados). Para los ingresos, multiplique por la cantidad y reste el monto_descuento. No SUME precio_unidad directamente. segmento_cliente Clasificación de clientes. Valores enumerados: 'ENTERPRISE', 'MID_MARKET', 'SMB', 'CONSUMER'. Nunca nulo. Úselo para filtros de segmentación. 'ENTERPRISE' representa cuentas con > 1 millón de dólares de gasto anual. return_reason_code Motivo codificado para la devolución del producto de RETURNS_FACT. Valores: 'DEFECTIVE', 'WRONG_ITEM', 'CHANGED_MIND', 'LATE_DELIVERY', 'OTHER'. Se puede anular cuando la devolución se procesó antes de que se introdujeran los códigos de motivo (anteriores a 2019).

Mejor práctica 5: guiar el comportamiento de unión sin definir relaciones

Los temas basados ​​en chat le permiten especificar la semántica de unión completamente a través de instrucciones en lenguaje natural. No necesita claves de relación formales ni restricciones sobre los tipos de unión. Hay cinco técnicas disponibles:

Técnica 1: sugerencias de unión implícitas

Indique la condición de unión y el tipo de unión como una regla en inglés simple en su conjunto de datos o en las instrucciones a nivel de tema. La IA seguirá esta regla al generar SQL.

— Instrucción del conjunto de datos para PEDIDOS: "Para responder preguntas sobre el valor de vida del cliente, una PEDIDOS con CLIENTES en customer_id usando IZQUIERDA, de modo que los clientes con cero pedidos aún aparezcan en el resultado". — SQL generado (aproximado): SELECCIONAR c.customer_id, c.customer_name, COALESCE(SUM(o.total_amount), 0) AS life_value FROM CLIENTES c LEFT JOIN ORDERS o ON c.customer_id = o.customer_id GROUP BY c.customer_id, c.customer_name

Técnica 2: Instrucciones de alineación de granos

Cuando dos tablas de hechos operan con diferentes granularidades, indique a la IA que las reúna antes de unirse. Esta es la fuente más común de medidas infladas en el análisis de conjuntos de datos múltiples.

— Instrucción del tema: "VENTAS_FACT es en grano diario (fecha_pedido). MONTHLY_FORECAST es en grano mensual (año_mes). Al comparar los datos reales con el pronóstico, primero agregue SALES_FACT por año_mes, luego únase a MONTHLY_FORECAST en año_mes y store_id". — SQL generado (aproximado): SELECT f.year_month, f.store_id, f.forecast_amount, COALESCE(a.actual_amount, 0) AS actual_amount, f.forecast_amount – COALESCE(a.actual_amount, 0) AS varianza FROM MONTHLY_FORECAST f LEFT JOIN ( SELECT DATE_TRUNC('month', order_date) AS año_mes, store_id, SUM(monto_total) AS monto_actual DEL GRUPO DE HECHO_VENTAS POR 1, 2) a ON f.año_mes = a.año_mes AND f.store_id = a.store_id

Técnica 3: Instrucciones de unión

Cuando dos tablas comparten el mismo esquema y representan el mismo tipo de entidad de diferentes fuentes, indique a la IA que las una.

— Instrucción de conjunto de datos compartida entre ONLINE_ORDERS e IN_STORE_ORDERS: "ONLINE_ORDERS e IN_STORE_ORDERS tienen esquemas idénticos. Cuando el usuario pregunta sobre 'todos los pedidos', 'pedidos totales' o 'ventas combinadas', use UNION ALL de ambas tablas antes de aplicar cualquier filtro o agregación. Incluya siempre una columna de tipo de canal: 'ONLINE' para ONLINE_ORDERS, 'IN_STORE' para EN_TIENDA_ORDERS." – SQL generado (aproximado): SELECCIONE tipo_canal, SUM(monto_total) COMO ingresos DESDE (SELECCIONE 'EN LÍNEA' COMO tipo_canal, monto_total FROM ONLINE_ORDERS UNION ALL SELECT 'IN_STORE' COMO tipo_canal, monto_total FROM IN_STORE_ORDERS ) GRUPO combinado POR tipo_canal

Técnica 4: instrucciones de subconsulta

Para preguntas sobre patrones de negación, como "muéstreme clientes que nunca han realizado pedidos" o "productos sin ventas este trimestre", indique a la IA que utilice los patrones NOT EXISTS o LEFT JOIN / IS NULL.

— Instrucción del tema: "Para encontrar clientes que no hayan realizado un pedido, use una subconsulta NOT EXISTS contra PEDIDOS, o equivalentemente una UNIÓN IZQUIERDA de CLIENTES a PEDIDOS filtrados en PEDIDOS.order_id ES NULO". — SQL generado (aproximado): SELECCIONE c.customer_id, c.customer_name, c.customer_segment FROM CLIENTES c DONDE NO EXISTE ( SELECCIONE 1 DE PEDIDOS o DONDE o.customer_id = c.customer_id )

Técnica 5: instrucciones de unión condicional

Algunos conjuntos de datos sólo son relevantes cuando el usuario pregunta sobre temas específicos. Indique a la IA que los incluya condicionalmente.

— Instrucción del tema: "Incluya el conjunto de datos PROMOCIONES solo cuando la pregunta del usuario involucre descuentos, campañas, códigos promocionales o precios promocionales. Únase en order_id cuando se necesiten PROMOCIONES".

Mejor práctica 6: Manejar patrones complejos mediante instrucciones semánticas

Los temas basados ​​en chat desbloquean varios patrones analíticos que no son compatibles o requieren soluciones complejas con relaciones definidas. Las siguientes subsecciones muestran cómo manejar cada patrón únicamente mediante instrucciones semánticas.

Uniones externas: preservación de registros inigualables

Las uniones externas son la característica más comúnmente necesaria de la que carecen los temas de relación definida.

— Instrucción del conjunto de datos para PRODUCTOS: "Siempre IZQUIERDA UNIRSE desde PRODUCTOS a SALES_FACT en product_id, para que los productos con cero ventas aún aparezcan en el conjunto de resultados. Use COALESCE(SUM(total_amount), 0) para mostrar 0 ingresos por productos no vendidos". — Pregunta de ejemplo: "Muéstrame todos los productos, incluidos aquellos sin ventas este mes" — SQL generado: SELECCIONAR p.nombre_producto, p.nombre_categoría, COALESCE(SUM(s.total_amount), 0) AS ingresos_mensuales FROM PRODUCT_DIM p LEFT JOIN SALES_FACT s ON p.product_id = s.product_id AND s.order_date >= DATE_TRUNC('month', CURRENT_DATE) AND s.order_date < DATE_ADD('mes', 1, DATE_TRUNC('mes', CURRENT_DATE)) GROUP BY p.nombre_producto, p.nombre_categoría ORDENAR POR ingresos_mensuales DESC

Relaciones de muchos a muchos: tablas puente

Las relaciones clásicas de muchos a muchos (estudiantes↔︎cursos, pedidos↔︎promociones, empleados↔︎proyectos) requieren una tabla puente, por la que la IA puede navegar cuando se le indica.

— Instrucción del tema: "LOS ESTUDIANTES y CURSOS tienen una relación de muchos a muchos a través de la tabla puente INSCRIPCIONES. Para responder preguntas sobre la inscripción en cursos: 1. Comience desde INSCRIPCIONES 2. ÚNASE a ESTUDIANTES en Student_id 3. ÚNASE a CURSOS en Course_id Nunca te unas a ESTUDIANTES directamente en CURSOS". — Ejemplo de pregunta: "¿Cuántos estudiantes están matriculados en cada departamento del curso?" — SQL generado: SELECCIONAR c.department_name, COUNT(DISTINCT e.student_id) COMO estudiantes_inscritos DE INSCRIPCIONES e UNIRSE A CURSOS c ON e.course_id = c.course_id GRUPO POR c.department_name ORDENAR POR estudiantes_inscritos DESC

Jerarquías recursivas y autorreferenciadas

Los temas de relaciones definidas no pueden representar autouniones. Los temas de chat no tienen tal restricción. Le indicas a la IA que se una por sí misma.

— Instrucción del conjunto de datos para EMPLEADOS: "EMPLOYEES.manager_id hace referencia a EMPLOYEES.employee_id. Para encontrar el nombre de un gerente para cada empleado, únase a EMPLEADOS: JOIN EMPLOYEES manager ON emp.manager_id = manager.employee_id Use LEFT JOIN para que se incluya al CEO (manager_id IS NULL). Alias la fila de empleado como 'emp' y el gerente fila como 'director'". — Pregunta de ejemplo: "Muéstrame cada empleado y el nombre de su gerente" — SQL generado: SELECT emp.employee_id, emp.first_name || ' ' || emp.apellido AS nombre_empleado, mgr.nombre_primer || ' ' || mgr.last_name AS manager_name, emp.department DE EMPLEADOS emp IZQUIERDA UNIRSE A EMPLEADOS mgr ON emp.manager_id = mgr.employee_id ORDENAR POR emp.department, emp.last_name

Dimensiones del juego de roles

Una dimensión de juego de roles es una tabla de una sola dimensión que cumple múltiples roles contextuales en una tabla de hechos (por ejemplo, un DATE_DIM usado para la fecha del pedido, la fecha de envío y la fecha de entrega simultáneamente). En los temas de relaciones definidas, cada rol requiere una definición de unión independiente. En Chat Topics, la IA maneja esto mediante instrucciones.

— Instrucción del conjunto de datos para PEDIDOS: "DATE_DIM se utiliza en tres funciones distintas para la tabla PEDIDOS: – Fecha del pedido: unirse en order_date_key = DATE_DIM.date_key – Fecha de envío: unirse en ship_date_key = DATE_DIM.date_key (alias: SHIP_DATE) – Fecha de entrega: unirse en delivery_date_key = DATE_DIM.date_key (alias: DELIVERY_DATE) Cuando el usuario menciona 'pedido fecha', 'colocado', 'comprado': use la combinación order_date_key Cuando el usuario mencione 'enviado', 'despachado': use la combinación ship_date_key Cuando el usuario mencione 'entregado', 'recibido': use la combinación delivery_date_key. — Ejemplo de pregunta: "¿Cuál es el retraso promedio en las entregas por región este trimestre?" – SQL generado: SELECCIONE s.region_name, AVG(DATEDIFF('day', o.order_date, o.delivery_date)) COMO avg_delivery_days FROM PEDIDOS o ÚNASE A STORE_DIM s ON o.store_id = s.store_id DONDE o.order_date >= DATE_TRUNC('trimestre', CURRENT_DATE) Y o.delivery_date NO ES GRUPO NULO POR s.nombre_región ORDENAR POR días_promedio de entrega DESC

Comparaciones entre granos

Las comparaciones cruzadas surgen cuando dos tablas de hechos miden el mismo concepto con diferentes granularidades (datos reales diarios frente a objetivos mensuales, envíos semanales frente a compromisos trimestrales). La IA necesita instrucciones explícitas sobre la dirección de acumulación.

— Instrucción del tema: "DAILY_SALES es de grano diario; STORE_TARGETS es de grano mensual. Para calcular el logro (real/objetivo), siempre agregue DAILY_SALES hasta el mes antes de dividir. Utilice DATE_TRUNC('mes', fecha_venta) como clave de agrupación y únase a STORE_TARGETS en el inicio del mes y en el ID de la tienda". — Pregunta de ejemplo: "¿Qué tiendas están por debajo del 80% de su objetivo mensual?" – SQL generado: CON mensuales_actuales AS (SELECT store_id, DATE_TRUNC('mes', sale_date) AS mes_inicio, SUM(ingresos) AS actual_ingresos FROM DAILY_SALES GROUP BY store_id, DATE_TRUNC('mes', sale_date) ) SELECCIONE st.store_name, ma.month_start, ma.actual_revenue, tg.target_revenue, ROUND(ma.actual_revenue / tg.target_revenue * 100, 1) AS logro_pct FROM mensual_actuals ma JOIN STORE_TARGETS tg ON ma.store_id = tg.store_id AND ma.month_start = tg.month_start ÚNETE A STORE_DIM st ON ma.store_id = st.store_id DONDE ma.actual_revenue / tg.target_revenue < 0.80 ORDENAR POR logro_pct ASC

Relaciones circulares

Los temas de relaciones definidas rechazan los gráficos de relaciones circulares (no DAG). Los temas de chat no tienen tal restricción. La IA navega por patrones cíclicos cuando la pregunta y las instrucciones son claras sobre qué camino recorrer. Si PEDIDOS hace referencia a CLIENTES, CLIENTES hace referencia a CUENTAS y CUENTAS hace referencia a PEDIDOS, la IA puede seguir el camino que sea más apropiado para la pregunta en cuestión.

Mejor práctica 7: reducir el ruido y mejorar la precisión de las respuestas

Un hallazgo contradictorio al ajustar los temas basados ​​en chat: menos campos visibles producen respuestas más precisas. La IA procesa cada columna dentro del alcance al formular SQL. Las columnas técnicas, las claves sustitutas, las marcas de tiempo ETL y los campos obsoletos añaden ruido, aumentando la posibilidad de una selección de columnas irrelevantes o una inferencia incorrecta.

Estrategia de exclusión de columnas

Excluir claves sustitutas: las claves sustitutas enteras (por ejemplo, customer_sk, product_sk) se utilizan para uniones, pero no tienen sentido como valores analíticos. Exclúyalos a menos que los usuarios los filtren de manera realista. Excluir metadatos ETL: etl_load_timestamp, is_deleted, batch_id, source_system_code. Estos campos existen para respaldar la ingeniería de datos, no el análisis. Excluir campos obsoletos: si tiene tanto el código_región_heredado como el nombre_región, oculte el que está obsoleto. Ofrecer ambos invita a la IA a elegir el equivocado. Excluya campos de bajo valor muy cardinales: los comentarios de texto libre, las notas internas y las cadenas UUID rara vez contribuyen a análisis significativos. Excluirlos.

Mejor práctica 8: Pruebe, valide e itere su modelo semántico

Un modelo semántico nunca está terminado en el primer borrador. Los ciclos iterativos de prueba y refinamiento lo llevan de "mayormente correcto" a "confiablemente preciso". En el desarrollo de BI tradicional, las consultas SQL se prueban directamente. Aquí se prueba la capacidad de la IA para traducir la intención empresarial en SQL correcto, lo que requiere un enfoque estructurado.

Construyendo un banco de preguntas

Antes de publicar un tema, cree un banco de preguntas de 15 a 25 preguntas por conjunto de datos principal, organizadas de lo básico a lo complejo:

Nivel 1: conjunto de datos único, métrica única: "¿Cuáles fueron los ingresos totales el mes pasado?" Prueba la agregación SUM básica y el filtrado de fechas. Nivel 2: conjunto de datos único, multidimensional: "Muéstrame los ingresos por categoría de producto y región para el tercer trimestre". Prueba GROUP BY con múltiples dimensiones. Nivel 3: conjunto de datos cruzados, grano coincidente: "¿Cuál es la tasa de retorno por categoría de producto?" Prueba el cálculo de unión y división entre conjuntos de datos. Nivel 4: conjuntos de datos cruzados, granos no coincidentes: "¿Qué tiendas están por encima de su objetivo de ventas mensual?" Prueba la alineación granular, la acumulación y la lógica de unión. Nivel 5: Patrones complejos: "Muéstrame todos los clientes, incluidos aquellos que no tienen pedidos, y su gasto de por vida". Prueba LEFT JOIN y la agregación segura para NULL.

Que validar

Corrección de la unión: ¿La IA eligió el tipo de unión correcto (IZQUIERDA o INTERIOR)? ¿Se unió a la clave correcta? Corrección de la agregación: ¿La IA se agregó en el grano correcto? ¿Las medidas se suman en lugar de promediarse cuando se especifica? Selección del conjunto de datos: cuando los términos son ambiguos, ¿la IA eligió el conjunto de datos deseado? Lógica de filtro: ¿Se están aplicando correctamente los filtros? ¿El intervalo de fechas es el que pretendía el usuario? Manejo de NULL: ¿Se manejan adecuadamente los valores NULL (verificaciones COALESCE, IS NULL)?

Modos de falla comunes y soluciones

Modo de falla Solución de síntomas Clave de unión incorrecta Los resultados están inflados o faltan filas Agregue una sugerencia de unión explícita en la instrucción del conjunto de datos: "unirse en id_cliente, no nombre_cliente" Agregación incorrecta Los ingresos muestran el precio unitario promedio en lugar de la suma Agregue una regla de agregación en la descripción del campo: "Siempre SUMA cantidad_total; nunca PROMEDIO" La consulta de "ventas" elegida en el conjunto de datos incorrecto alcanza RETURNS_FACT en lugar de SALES_FACT Agregue una regla de desambiguación en el tema instrucción Término de usuario desconocido La IA no puede interpretar “contracción” Agregue “contracción” como sinónimo de la columna relevante Inflación de granos Unir datos diarios a mensuales duplica los valores métricos Agregar instrucción de alineación de granos a las instrucciones del tema Faltan filas NULL Los productos sin ventas no aparecen en los resultados Agregar instrucción de unión externa: “LEFT JOIN from PRODUCTS to SALES_FACT”

Marco de decisión: elegir su enfoque

Amazon Quick Sight ofrece tres enfoques para temas de conjuntos de datos múltiples: relaciones definidas, orientación de Chat solo semántica y un híbrido de ambos. La elección correcta depende de su caso de uso, perfil de usuario y requisitos de gobernanza.

Escenario Enfoque recomendado Justificación Esquema en estrella estable, entorno regulado Relaciones definidas Se aplica la semántica de unión interna; determinista; rutas de unión auditables Análisis exploratorios, preguntas ad hoc Sólo semántica (chat) Máxima flexibilidad; La IA se adapta a diversos tipos de preguntas sin cambios de esquema. Se requieren uniones externas, uniones o subconsultas. Las relaciones definidas solo semánticamente (chat) solo admiten uniones internas; El chat no tiene restricciones de tipo de unión. Las jerarquías recursivas o autouniones. Las relaciones definidas solo semánticamente (chat) no pueden autorreferenciarse; El chat maneja las autouniones a través de instrucciones Usuarios no técnicos que necesitan barreras de seguridad Relaciones definidas + metadatos El gráfico de unión explícito evita combinaciones incorrectas entre conjuntos de datos; Los metadatos mejoran a los usuarios avanzados de NLQ, máxima flexibilidad Solo semántica (Chat) Las instrucciones enriquecidas + sinónimos brindan a los usuarios avanzados una expresividad SQL completa a través del lenguaje natural.

Poniéndolo todo junto: tutorial de un extremo a otro

Esta sección explica cómo configurar un tema listo para chatear para un escenario de análisis minorista con cinco conjuntos de datos.

Escenario: Tema de análisis minorista

Columnas clave de grano del conjunto de datos SALES_FACT Una fila por artículo de línea de pedido order_line_id (PK), order_id, product_id, customer_id, store_id, order_date_key, cantidad, precio unitario, monto_descuento, monto_total, estado_pedido RETURNS_FACT Una fila por artículo devuelto return_id (PK), order_line_id (FK), customer_id, product_id, return_date, refund_amount, return_reason_code CUSTOMER_DIM Una fila por cliente customer_id (PK), nombre_cliente, segmento_cliente, ciudad, estado, país, fecha_primer_pedido, valor_vida útil PRODUCT_DIM Una fila por producto SKU product_id (PK), nombre_producto, subcategoría, categoría, marca, costo unitario, is_active DATE_DIM Una fila por día calendario date_key (PK, AAAAMMDD int), date_value, día_de_semana, nombre_mes, trimestre, año, es_vacaciones

Paso 1: instrucciones a nivel de conjunto de datos (SALES_FACT)

"SALES_FACT contiene una fila por artículo de línea de pedido. Clave principal: order_line_id. Grano: un artículo de línea = un producto en un pedido. Ingresos = cantidad * precio unitario – monto_descuento. Siempre SUMA ingresos. Excluye filas donde estado_pedido = VOID. Se une: id_producto -> PRODUCT_DIM, id_cliente -> CLIENTE_DIM, id_tienda -> TIENDA_DIM, clave_fecha_pedido -> DATE_DIM.fecha_clave."

Paso 2: instrucciones a nivel de conjunto de datos (RETURNS_FACT)

"RETURNS_FACT: una fila por línea de pedido devuelta. Clave principal: return_id. order_line_id es una clave externa para SALES_FACT. Utilice este conjunto de datos cuando el usuario pregunte sobre devoluciones, reembolsos o créditos. refund_amount es siempre un número negativo (crédito al cliente). IZQUIERDA UNIRSE desde SALES_FACT a RETURNS_FACT para preservar ventas inigualables".

Paso 3: instrucciones a nivel de tema

Tema: Análisis minorista: desambiguación y reglas entre conjuntos de datos Desambiguación: "ventas", "ingresos", "pedidos" -> usar SALES_FACT "devoluciones", "reembolsos" -> usar RETURNS_FACT "ventas netas", "ingresos netos" -> unirse a SALES_FACT LEFT JOIN RETURNS_FACT en order_line_id Métricas de conjuntos de datos cruzados: Ingresos netos = SUM(SALES_FACT.total_amount) + SUM(RETURNS_FACT.refund_amount) Tasa de retorno = COUNT(RETURNS_FACT.return_id) / COUNT(SALES_FACT.order_line_id) Uniones predeterminadas: SALES_FACT LEFT JOIN CUSTOMER_DIM en customer_id SALES_FACT LEFT JOIN PRODUCT_DIM en product_id SALES_FACT LEFT JOIN DATE_DIM en order_date_key = date_key Manejo de fechas: YTD: año actual hasta hoy inclusive Este trimestre: DATE_TRUNC('trimestre', hoy()) hasta hoy

Paso 4: sinónimos clave

Sinónimos de campos técnicos para agregar SALES_FACT.total_amount Ingresos, Ventas, Ingresos, Línea superior, Ventas brutas, Ventas totales RETURNS_FACT.refund_amount Reembolso, Crédito, Monto devuelto, Contracargo CUSTOMER_DIM.customer_segment Segmento, Nivel, Tipo de cliente, Tipo de cuenta PRODUCT_DIM.categoría Categoría, Departamento, Grupo de productos, Pasillo DATE_DIM.trimestre, T1, T2, T3, Cuarto trimestre, trimestre fiscal

Pasos 5 a 7: enriquecimiento, exclusiones y validación

Enriquezca las descripciones de los campos: agregue descripciones a las 15 a 20 columnas más consultadas en los cinco conjuntos de datos utilizando el formato: definición + unidad + nulabilidad + regla de agregación. Tipos semánticos de etiquetas: etiquete todos los campos de fecha como Fecha, los campos monetarios como Moneda, los campos de porcentaje como Porcentaje y los campos geográficos con sus respectivos tipos geográficos. Excluir ruido: oculte las columnas etl_load_ts, batch_id, is_deleted, source_system y clave sustituta que no se utilizan en las preguntas dirigidas al usuario.

Paso 8: Preguntas de muestra y SQL esperado

P1: "¿Cuáles fueron los ingresos netos totales por categoría de producto el último trimestre?"

SELECCIONE p.categoría, SUM(s.total_amount) + COALESCE(SUM(r.refund_amount), 0) AS net_revenue FROM SALES_FACT s LEFT JOIN RETURNS_FACT r ON s.order_line_id = r.order_line_id ÚNETE A PRODUCT_DIM p ON s.product_id = p.product_id ÚNETE DATE_DIM d ON s.order_date_key = d.date_key DONDE d. quarter="Q2" AND d.year = 2024 AND s.order_status != 'VOID' GRUPO POR p.categoría ORDEN POR ingresos_netos DESC

P2: "Muéstrame todos los productos, incluidos aquellos con cero ventas este mes"

SELECCIONE p.nombre_producto, p.categoría, COALESCE(SUM(s.total_amount), 0) COMO ingresos_mensuales DESDE PRODUCT_DIM p LEFT JOIN SALES_FACT s ON p.product_id = s.product_id AND s.order_date_key ENTRE 20240601 Y 20240630 Y s.order_status!= GRUPO 'VOID' POR p.nombre_producto, p.categoría ORDENAR POR ingresos_mensuales DESC

P3: "¿Qué segmentos de clientes tienen las tasas de devolución más altas?"

SELECCIONE c.segmento_cliente, COUNT(DISTINCT s.order_line_id) AS total_orders, COUNT(DISTINCT r.return_id) AS total_returns, ROUND(COUNT(DISTINCT r.return_id) * 100.0 / NULLIF(COUNT(DISTINCT s.order_line_id), 0), 2) AS return_rate_pct FROM SALES_FACT s LEFT JOIN RETURNS_FACT r ON s.order_line_id = r.order_line_id JOIN CUSTOMER_DIM c ON s.customer_id = c.customer_id DONDE s.order_status != 'VOID' GRUPO POR c.customer_segment ORDENAR POR return_rate_pct DESC

P4: "¿Qué tiendas están por debajo del 80% de su objetivo mensual?"

CON datos_actuales mensuales AS (SELECT store_id, DATE_TRUNC('mes', fecha_pedido) AS inicio_mes, SUM(ingresos) AS ingresos_actuales FROM SALES_FACT GROUP BY store_id, DATE_TRUNC('mes', fecha_pedido) ) SELECCIONE st.store_name, ma.month_start, ma.actual_revenue, tg.target_revenue, ROUND(ma.actual_revenue / tg.target_revenue * 100, 1) AS attainment_pct FROM mensual_actuals ma ÚNASE A STORE_TARGETS tg ON ma.store_id = tg.store_id AND ma.month_start = tg.month_start ÚNASE A STORE_DIM st ON ma.store_id = st.store_id DONDE ma.actual_revenue / tg.target_revenue < 0,80 ORDENAR POR logro_pct ASC

Consideraciones actuales y consejos prácticos.

Extensión y concisión de las instrucciones

Las instrucciones personalizadas de Quick Sight tienen límites de caracteres, pero la concisión es una virtud de todos modos. Prefiera listas de reglas con viñetas a párrafos en prosa. Cada regla debe ser una declaración única y analizable de forma independiente. Por ejemplo, "unir pedidos a clientes en customer_id usando LEFT JOIN para conservar clientes sin pedidos" es más efectivo que un ensayo de dos párrafos que cubra el mismo punto.

Orden de precedencia

Cuando las instrucciones a nivel de tema y a nivel de conjunto de datos entran en conflicto, el nivel de tema tiene prioridad. Utilice esto de manera predecible: las instrucciones a nivel de conjunto de datos deben definir hechos de un solo conjunto de datos (grano, claves, reglas de agregación), mientras que las instrucciones a nivel de tema deben definir la lógica de múltiples conjuntos de datos. Nunca utilice instrucciones a nivel de tema para redefinir la semántica de un solo conjunto de datos ya especificada en el nivel del conjunto de datos.

Consideraciones de rendimiento

Más conjuntos de datos en un tema significan más contexto para que la IA los procese en el momento de la consulta. Para mantener la latencia de respuesta aceptable:

Mantenga los temas centrados en un dominio: análisis minorista, análisis de recursos humanos, informes financieros. Evite crear un tema para todo un almacén de datos empresarial. Divida los temas cuando los conjuntos de datos sirvan a diferentes comunidades de usuarios. Un único tema basado exclusivamente en datos es más difícil de ajustar y de gobernar que tres temas específicos. Los conjuntos de datos respaldados por SPICE generalmente producen respuestas de consulta más rápidas que las fuentes de consulta directa para cargas de trabajo de Chat.

Seguridad a nivel de fila

La seguridad a nivel de fila (RLS) se aplica en el nivel del conjunto de datos, independientemente de cómo la IA une o une los conjuntos de datos. Incluso si la IA genera SQL combinando cinco conjuntos de datos, los filtros RLS de cada conjunto de datos se aplican antes de que los datos ingresen a la combinación. Un administrador regional restringido a los datos de su región en SALES_FACT nunca verá los datos de otras regiones, independientemente de la pregunta del Chat.

Cuándo dividir en varios temas

Dividir en varios temas cuando… Combinar en un solo tema Cuando… Diferentes comunidades de usuarios con diferentes vocabularios La misma comunidad de usuarios con preguntas superpuestas en conjuntos de datos Los conjuntos de datos sirven a diferentes dominios empresariales (RRHH + Finanzas) Todos los conjuntos de datos sirven a un único dominio analítico La gobernanza requiere diferentes controles de acceso por tema RLS maneja el control de acceso de manera uniforme a nivel de conjunto de datos La complejidad de las instrucciones de los temas está creciendo (>30 reglas) Las instrucciones de los temas siguen siendo manejables (<20 reglas)

Conclusión

Pasar de gráficos de relaciones explícitas a orientación semántica es un enfoque fundamentalmente diferente al análisis de conjuntos de datos múltiples: en lugar de definir cada ruta de unión por adelantado, usted describe el grano, el vocabulario, las reglas comerciales y los casos extremos de sus datos, y la IA traduce la intención del usuario en SQL correcto en el momento de la consulta.

Esto desbloquea capacidades que las relaciones predefinidas no pueden admitir: uniones externas que conservan registros no coincidentes, uniones que combinan tablas paralelas, autouniones que atraviesan jerarquías recursivas y comparaciones entre niveles que requieren acumulaciones en tiempo de ejecución. La restricción es semántica, no estructural: cuanto más precisamente describas tus datos, más confiablemente la IA entregará resultados correctos.

Sobre los autores

Ying Wang

Ying es un arquitecto senior de soluciones especializado a nivel mundial en la organización de IA generativa de AWS. Aporta 17 años de experiencia en análisis y ciencia de datos, con una sólida formación como arquitecta de datos y gerente de ingeniería de desarrollo de software.

Emily Zhu

Emily Zhu

Emily es gerente senior de productos en Amazon Quick, responsable de toda la pila de datos estructurados, que abarca la arquitectura de datos gobernados y de escala empresarial, motores de consulta analíticos y conversacionales de alto rendimiento, y la capa semántica y ontológica que brinda a los datos un significado real a escala. Le apasiona cómo una estrategia de datos sólida desbloquea la estrategia de IA y tiene la misión de hacer que la pila de datos estructurados sea la base para experiencias conversacionales y analíticas en Quick Suite.

amy marvin

amy marvin

Amy es gerente técnica sénior de productos de Amazon Quick y se centra en las capacidades de análisis de chat basadas en inteligencia artificial. Le apasiona eliminar las barreras entre las personas y sus datos, haciendo posible que cualquiera pueda hacer una pregunta y obtener una respuesta confiable en segundos. Fuera del trabajo, le gusta explorar la escena de restaurantes de DC y andar en bicicleta por senderos naturales.