Ao desenvolver recursos para aplicativos de AI/ML em tempo real, é crucial compreender os padrões baseados em tempo em seus dados, pois eles podem revelar informações valiosas. No entanto, expressar consultas temporais pode representar desafios. Imagine a capacidade de analisar sem esforço o comportamento de seus usuários ao longo do tempo, realizar junções temporais precisas e examinar padrões de atividade entre vários eventos - tudo isso enquanto mantém um gerenciamento de tempo intuitivo e contínuo. É aqui que as linhas do tempo, uma abstração de alto nível para trabalhar com dados temporais, podem ser inestimáveis
Neste artigo, vamos mergulhar fundo no mundo das linhas do tempo. Demonstraremos como eles tornam a expressão de consultas temporais em eventos e, principalmente, entre eventos, não apenas fácil, mas também intuitiva. Este artigo é o segundo de uma série sobre
Intuitivo Como os cronogramas são ordenados por tempo, é natural que as consultas também operem em ordem. Conforme o tempo avança, eventos adicionais – entrada – ocorrem e são refletidos na saída da consulta. Essa maneira de pensar sobre cálculos – como progresso ao longo do tempo – é intuitiva porque combina com a maneira como observamos os eventos.
Operações temporais declarativas – como janelamento e deslocamento – são claramente declaradas ao trabalhar com linhas de tempo porque o tempo faz parte da abstração.
Composable Cada operação usa linhas de tempo e produz linhas de tempo, o que significa que as operações podem ser encadeadas conforme necessário para produzir os resultados pretendidos.
Abaixo, dissecaremos quatro exemplos da vida real que demonstram os benefícios das linhas do tempo. Começaremos com uma consulta simples para agregação e abordaremos progressivamente janelas temporais mais complexas, janelas dependentes de dados e junções temporalmente corretas. No final, você deve ter uma compreensão profunda de como as linhas de tempo tornam a escrita de consultas temporais simples tão simples quanto o SQL e como elas nos capacitam a enfrentar as questões mais desafiadoras.
As linhas de tempo oferecem suporte a tudo o que você pode fazer no SQL , estendidas intuitivamente para operar ao longo do tempo. Antes de examinar alguns novos recursos para consultas temporais sofisticadas, vejamos algo simples – uma agregação. Escrever consultas simples é fácil: na verdade, como as linhas do tempo são ordenadas por tempo e agrupadas por entidade, elas podem ser ainda mais fáceis do que em SQL!
Considere a questão: quanto cada usuário gastou? Pensando nisso ao longo dos eventos, é natural processar as compras em ordem, atualizando o valor que cada usuário gastou ao longo do tempo. O resultado é uma soma cumulativa produzindo uma linha do tempo contínua.
A consulta correspondente é mostrada abaixo escrita de duas maneiras equivalentes. A primeira enfatiza o valor que está sendo aplicado nas compras enquanto a segunda enfatiza a cadeia de operações que compusemos – “pegue as compras e depois aplique o valor”. Daqui em diante, usaremos o último, pois ele corresponde melhor à maneira como tendemos a pensar sobre o processamento de cronogramas.
sum(Purchases.amount)
#OR
Purchases.amount | sum()
Escrever consultas temporais simples com linhas do tempo era tão fácil quanto SQL. O processamento de eventos em ordem é uma maneira intuitiva de operar ao longo do tempo. Claro, agregar todos os eventos é apenas uma maneira que podemos desejar para agregar coisas. No próximo exemplo, veremos como estender essa consulta usando janelas temporais para focar em eventos recentes.
Ao pensar em consultas temporais, é muito natural fazer perguntas sobre o passado recente: acumulado no ano ou nos últimos 30 dias. A intuição de processar eventos em ordem sugere que responder à pergunta “Quanto cada usuário gastou este mês” deveria exigir apenas a redefinição do valor no início de cada mês. E essa intuição é exatamente como esses tipos de janelas temporais funcionam com linhas de tempo.
A consulta temporal é mostrada abaixo. Indica claramente a intenção que expressamos acima – pegar as compras e agregá-las desde o início de cada mês.
Purchases.amount
| sum(window=since(monthly()))
Como o tempo é inerentemente parte de cada linha do tempo, cada agregação é capaz de operar dentro de janelas temporais. No próximo exemplo veremos como é fácil trabalhar com consultas mais complicadas, inclusive agregações com janelas mais sofisticadas.
Nem todas as janelas são definidas em termos de tempo. Geralmente é útil usar eventos para determinar as janelas usadas para agregação. Além disso, embora todos os exemplos até agora tenham operado em um único tipo de evento – purchases
–, examinar os padrões de atividade entre diferentes eventos é fundamental para identificar relações de causa e efeito.
Neste exemplo, aproveitaremos as linhas do tempo para expressar consultas de forma declarativa usando janelas definidas por dados e vários tipos de eventos. Também filtraremos uma linha do tempo intermediária para pontos específicos para controlar os valores usados nas etapas posteriores ao compor a consulta.
A pergunta que responderemos é “Qual é o número médio de visualizações de página entre cada compra para cada usuário?” Primeiro, calcularemos as visualizações de página desde a última compra, observaremos no momento de cada compra e, em seguida, tiraremos a média.
A primeira coisa que faremos é calcular o número de visualizações de página desde a última compra. No exemplo anterior, janelamos desde o início do mês. Mas não há nada de especial na linha do tempo que define o início de um mês – podemos janelar com qualquer outra linha do tempo.
PageViews
| count(window=since(is_valid(Purchases)))
Além do janelamento definido por dados, vemos como trabalhar com vários tipos de eventos. Como cada linha do tempo é ordenada por tempo e agrupada por entidade, cada linha do tempo pode ser alinhada por tempo e unida por entidade – automaticamente.
A etapa anterior nos deu as visualizações de página desde a última compra. Mas era uma linha do tempo contínua que aumentava a cada visualização de página até a próxima compra. Buscamos uma linha do tempo discreta com um único valor no momento de cada compra representando as visualizações de página desde a compra anterior. Para fazer isso, usamos a operação when
, que permite observar – e interpolar, se necessário – uma linha do tempo em pontos específicos no tempo.
A operação when pode ser usada em qualquer lugar em uma consulta temporal e permite pontos de filtragem, que estão presentes na saída – ou passados para agregações posteriores.
Com o número de visualizações de página entre compras calculado, agora podemos calcular a média desse valor. Tudo o que precisamos fazer é usar a agregação mean
.
A consulta completa é mostrada abaixo. Vemos que as etapas correspondem às etapas lógicas mencionadas acima. Embora a lógica seja razoavelmente complexa, a consulta é relativamente direta e captura nossa ideia do que queremos calcular – perguntas difíceis são possíveis.
PageViews
| count(window=since(is_valid(Purchases)))
| when(is_valid(Purchases))
| mean()
Esse tipo de consulta pode ser generalizado para analisar uma variedade de padrões na atividade de exibição de página. Talvez desejemos apenas observar as exibições de página do item visualizado com mais frequência, em vez de todos os itens, acreditando que o usuário está se concentrando mais nesse item. Talvez desejemos janela desde as compras do mesmo item, em vez de qualquer compra.
Esta consulta mostrou algumas maneiras pelas quais as linhas do tempo permitem que consultas temporais complexas sejam expressas:
A ordenação permite que as janelas sejam definidas por seus delimitadores – quando começam e terminam – em vez de ter que calcular um “ID de janela” de cada valor para agrupamento.
A ordenação também permite que várias linhas do tempo sejam usadas na mesma expressão – neste caso, pageviews
e purchases
.
A continuidade permite que os valores sejam interpolados em momentos arbitrários e filtrados usando a operação when
.
A capacidade de composição permite que o resultado de qualquer operação seja usado com operações posteriores para expressar questões temporais. Isso permite que questões complexas sejam expressas como uma sequência de operações simples.
Esses recursos permitem identificar padrões de causa e efeito. Embora possa ser que a compra agora me leve a fazer compras mais tarde, outros eventos costumam ter um relacionamento mais forte - por exemplo, ficar sem fita adesiva e comprar mais, ou agendar um acampamento e estocar. Ser capaz de observar a atividade ( pageviews
) em uma janela definida por outros eventos ( purchases
) é importante para entender a relação entre esses eventos.
Já vimos como as linhas do tempo permitem trabalhar com vários tipos de eventos associados a uma mesma entidade. Mas muitas vezes também é necessário trabalhar com várias entidades. Por exemplo, usando informações sobre toda a população para normalizar valores para cada usuário. Nosso exemplo final mostrará como trabalhar com várias entidades e realizar uma junção temporal.
A pergunta final que responderemos é “Qual é a média mínima de avaliação (pontuação) do produto no momento de cada compra?” Para fazer isso, primeiro trabalharemos com as avaliações associadas a cada produto para calcular a pontuação média e, em seguida, juntaremos cada compra com a avaliação média correspondente.
Para começar, queremos calcular a avaliação média do produto (pontuação) para cada item. Como as avaliações estão atualmente agrupadas por usuário, precisaremos reagrupar por item, usando a operação de tecla with. Feito isso, podemos usar a agregação média que já vimos.
Para cada compra (agrupada por usuário), queremos consultar a pontuação média da avaliação do item correspondente. Isso usa a operação lookup
.
Juntando tudo, usamos a pesquisa com uma agregação min
para determinar a classificação média mínima de itens comprados por cada usuário.
Reviews.score
| with_key(Reviews.item)
| mean()
| lookup(Purchases.item)
| min()
Esse padrão de reagrupamento em uma entidade diferente, realizando uma agregação e procurando o valor (ou voltando às entidades originais) é comum em tarefas de processamento de dados. Nesse caso, o valor resultante foi pesquisado e usado diretamente. Em outros casos é útil para normalização – como relacionar o valor de cada usuário com os valores médios de sua cidade.
A ordenação e o agrupamento permitem que os cronogramas expressem claramente as operações entre diferentes entidades. O resultado de uma pesquisa é do ponto no tempo em que a pesquisa é realizada. Isso fornece uma junção "a partir de" temporalmente correta.
Executar uma junção no momento correto é crítico para exemplos de treinamento de computação do passado que são comparáveis aos valores de recursos usados ao aplicar o modelo. Da mesma forma, garante que qualquer painel, visualização ou análise realizada nos resultados da consulta estejam realmente corretos, como se estivessem olhando para os valores no passado, em vez de usar informações que não estavam disponíveis naquele momento.
Demonstramos o poder das linhas de tempo como uma abstração de alto nível para lidar com dados temporais. Por meio de operações intuitivas, declarativas e combináveis, mostramos como as linhas de tempo permitem a expressão eficiente de consultas temporais em eventos e entre eventos. Com exemplos que variam de agregações simples a consultas sofisticadas, como janelas dependentes de dados e junções temporalmente corretas, ilustramos como as operações da linha do tempo podem ser encadeadas para produzir os resultados pretendidos. A potência das linhas do tempo reside em sua capacidade de expressar facilmente questões temporais simples e estender intuitivamente a questões temporais complexas.
Do gasto total à pontuação mínima da revisão, percorremos quatro exemplos ilustrativos que destacam os recursos das linhas do tempo na consulta temporal. Exploramos agregação cumulativa, janelas temporais e observamos como janelas definidas por dados oferecem a capacidade de expressar questões temporais complexas. Também mostramos como as linhas do tempo facilitam o manuseio de várias entidades e junções temporais. Esses exemplos mostram que, com linhas de tempo, você tem uma ferramenta poderosa para identificar padrões de causa e efeito e calcular exemplos de treinamento que são comparativamente válidos ao aplicar um modelo.
A seguir, vamos nos aprofundar mais na dinâmica das consultas temporais em linhas do tempo. Exploraremos como essas consultas são executadas com eficiência aproveitando as propriedades das linhas do tempo.\
Nós encorajamos você a
Também publicado aqui.