Ao construir data warehouses, empresas de e-commerce frequentemente precisam calcular métricas de janela deslizante, como visitantes únicos (UV), contagem de compradores e compradores recorrentes nos últimos 30 dias. Como esses indicadores são calculados sobre dados acumulados por um longo período, consultas ingênuas de janela deslizante tornam-se excessivamente lentas ou falham completamente em grande escala.
A causa raiz é sempre a mesma: volume excessivo de dados reprocessado do zero a cada execução. As duas abordagens de otimização apresentadas neste tópico compartilham um princípio comum — evitar o recálculo completo por meio de pré-agregação ou acumulação incremental de dados — e diferem apenas na profundidade com que aplicam esse conceito.
Todos os exemplos de código utilizam variáveis de agendamento do DataWorks (por exemplo, ${bdp.system.bizdate} ). Os exemplos se aplicam exclusivamente a nós de agendamento no DataWorks.
O problema das consultas de janela deslizante
Uma consulta típica de UV de 30 dias tem a seguinte estrutura:
SELECT item_id,
COUNT(DISTINCT visitor_id) AS ipv_uv_1d_001
FROM vistor_item_detail_log
WHERE ds <= ${bdp.system.bizdate}
AND ds >= TO_CHAR(DATEADD(TO_DATE(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')
GROUP BY item_id;
Essa consulta varre 30 partições de dados de log brutos em cada execução. Se o volume de logs for elevado, o MaxCompute pode precisar gerar mais de 99.999 tarefas map, ponto em que o job falha. Mesmo abaixo desse limite, varrer 30 dias de logs brutos diariamente gera desperdício, pois a maior parte dos dados não sofreu alterações desde a execução anterior.
Escolha uma abordagem
Dois padrões de otimização resolvem esse problema. Selecione aquele mais adequado à estrutura dos seus dados e consultas:
|
Abordagem |
Funcionamento |
Cenário recomendado |
|
Tabela intermediária |
Deduplica e agrega logs brutos diariamente em uma tabela de resumo; consulta a tabela de resumo em vez dos logs brutos |
Volume diário de logs elevado; dados por partição mudam significativamente entre execuções |
|
Acumulação incremental |
Mescla todas as partições históricas em uma única partição e anexa novos dados diariamente |
Consultas repetidas da mesma janela deslizante; redução de varreduras multipartição é mais crítica que a deduplicação diária |
Para a maioria das cargas de trabalho de e-commerce, comece pela abordagem de tabela intermediária. Migre para acumulação incremental caso as varreduras multipartição continuem sendo o gargalo após a implementação da tabela intermediária.
Abordagem 1: Tabela intermediária
Funcionamento
Em vez de consultar 30 partições de logs brutos, pré-agregue os logs de cada dia em uma tabela de resumo. Cada linha nessa tabela representa um par único (item_id, visitor_id) para aquele dia. Consultar 30 partições de dados pré-agregados custa muito menos do que consultar 30 partições de logs brutos, pois a etapa de pré-agregação elimina linhas duplicadas de alta cardinalidade antes da execução da consulta de janela deslizante.
Etapa 1: Crie o resumo diário
Execute este script como um nó agendado diariamente no DataWorks, antes dos nós de métricas:
INSERT OVERWRITE TABLE mds_itm_vsr_xx (ds='${bdp.system.bizdate} ')
SELECT item_id,
visitor_id,
COUNT(1) AS pv
FROM (
SELECT item_id,
visitor_id
FROM vistor_item_detail_log
WHERE ds = ${bdp.system.bizdate}
GROUP BY item_id, visitor_id
) a;
Esse comando grava uma linha deduplicada por par (item_id, visitor_id) na tabela mds_itm_vsr_xx referente à partição de data atual.
Etapa 2: Consulte a tabela de resumo
Com a tabela de resumo disponível, sua consulta de janela deslizante processa um volume de dados muito menor:
SELECT item_id,
COUNT(DISTINCT visitor_id) AS uv,
SUM(pv) AS pv
FROM mds_itm_vsr_xx
WHERE ds <= '${bdp.system.bizdate} '
AND ds >= TO_CHAR(DATEADD(TO_DATE('${bdp.system.bizdate} ','yyyymmdd'),-29,'dd'),'yyyymmdd')
GROUP BY item_id;
Esta abordagem exige um nó diário dedicado para popular a tabela mds_itm_vsr_xx. Configure esse nó como dependência upstream dos seus nós de métricas no DataWorks para garantir que a tabela de resumo esteja sempre atualizada antes da execução das consultas downstream.
Abordagem 2: Acumulação incremental
Funcionamento
A abordagem de tabela intermediária ainda varre 30 partições a cada execução. A acumulação incremental vai além: mescla todos os dados históricos em uma única partição de acumulação e anexa apenas os novos dados diariamente. Assim, as consultas de janela deslizante leem apenas uma partição.
Essa estratégia é mais eficaz quando o percentual de dados alterados diariamente é pequeno em relação ao conjunto histórico total, ou seja, quando a maior parte dos dados na partição de acumulação permanece estável entre as execuções.
Implementação: tabela de dimensão de compradores recorrentes
O caso de uso de compradores recorrentes (clientes que compraram nos últimos 30 dias) ilustra bem essa abordagem. Uma solução ingênua varre 30 partições de logs de faturamento em cada execução:
SELECT item_id,
buyer_id AS old_buyer_id
FROM buyer_item_detail_log
WHERE ds < ${bdp.system.bizdate}
AND ds >= TO_CHAR(DATEADD(TO_DATE(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')
GROUP BY item_id,
buyer_id;
Alternativamente, mantenha uma tabela de dimensões onde cada linha representa o relacionamento entre um comprador e um item, registrando campos como hora da primeira compra, hora da última compra, total de itens comprados e gasto total. Atualize-a diariamente com os logs de faturamento do dia anterior.
Para determinar se um comprador é recorrente, verifique se o campo last_purchase_time está dentro dos últimos 30 dias. Isso substitui a varredura de 30 partições de logs de faturamento por uma consulta em partição única na tabela de dimensões, eliminando a deduplicação por varredura completa a cada execução.
Considerações de desempenho
|
Fator |
Tabela intermediária |
Acumulação incremental |
|
Partições varridas por execução |
30 (com linhas menores) |
1 |
|
Complexidade de implementação |
Baixa: um nó diário adicional |
Mais alta: lógica de mesclagem e gerenciamento de dependências |
|
Atualização dos dados |
Diária |
Diária |
|
Melhor adequação |
Grande volume diário de logs com chaves de alta cardinalidade |
Consultas repetidas de janela deslizante sobre dados históricos estáveis |
Ambas as abordagens transferem o processamento custoso do momento da consulta para o momento da ingestão. A tabela intermediária faz isso diariamente; a acumulação incremental aplica esse princípio a todos os dias históricos.