Detectar e desduplicar registros usando funções de hash no Jitterbit Studio
Introdução
Funções de hash geram uma impressão digital curta e de comprimento fixo para cada registro, derivada de seus valores de campo. Dois registros com valores de campo idênticos produzem impressões digitais idênticas; um registro cujos valores foram alterados produz uma impressão digital diferente daquela calculada na execução anterior. O Studio fornece duas funções de hash criptográficas para esse propósito: SHA256, que retorna uma string hex de 64 caracteres, e MD5, que retorna uma string hex de 32 caracteres.
Este guia aborda dois padrões construídos em torno dessas funções:
- Parte 1: Detecção de alterações entre execuções: Calcule um hash de cada registro de origem durante uma sincronização, compare-o com o hash armazenado em cache da execução anterior e ignore registros cujo hash não foi alterado.
- Parte 2: Desduplicação dentro da execução: Acompanhe quais registros já foram processados durante uma única execução usando cache e ignore registros duplicados encontrados posteriormente no mesmo conjunto de dados.
Ambos os padrões usam as funções de cache do Harmony na nuvem ReadCache e WriteCache para armazenar estado. As chamadas de cache estão sujeitas a um limite combinado de 100 chamadas por minuto por organização; para necessidades de armazenamento de alto volume ou longa duração, Cloud Datastore é a alternativa recomendada.
Este guia pressupõe familiaridade com condições de transformação. Para obter mais informações, consulte Filtrar registros usando condições.
Padrão de design
Ambos os padrões usam uma única operação:
(with condition)"] --> C[Target activity]
O nó de condição de transformação é executado uma vez por registro de origem. O script de condição lê do cache, avalia se o registro deve ser processado e retorna true (processar) ou false (ignorar). Quando um registro é processado, o script também escreve o estado atualizado no cache para uso na próxima avaliação.
A lógica de cache reside na condição de transformação em vez de em uma etapa de script separada. Isso mantém o gerenciamento de estado próximo aos dados e evita a complexidade de coordenar quais registros foram processados através de um limite de etapa.
Parte 1: Detecção de alterações baseada em hash entre execuções
Este padrão detecta se um registro de origem foi alterado desde a última execução de integração. Um hash dos campos de cada registro é armazenado em cache com expiração de 30 dias para que persista entre execuções.
Etapa 1: Escolha uma função de hash
Use SHA256 a menos que a velocidade de processamento seja a principal preocupação. SHA256 retorna uma string hex de 64 caracteres e não tem vulnerabilidades de colisão práticas conhecidas para esse caso de uso. MD5 retorna uma string hex de 32 caracteres e é um pouco mais rápido, mas produz uma impressão digital mais fraca.
Para a maioria dos volumes de integração, a diferença de desempenho é negligenciável. Use SHA256 por padrão.
Etapa 2: Construa a entrada de hash
Concatene os campos que devem disparar o processamento quando forem alterados. Use | como separador entre valores de campo para evitar que valores adjacentes produzam a mesma string concatenada por acaso.
Por exemplo, se um registro de contato deve ser processado quando email, first_name ou last_name forem alterados:
Source.id + "|" + Source.email + "|" + Source.first_name + "|" + Source.last_name
Nota
Inclua cada campo que deve ativar o processamento quando alterado. Os campos omitidos da entrada de hash são invisíveis para o detector de alterações: as alterações nesses campos são silenciosamente ignoradas.
Etapa 3: Escrever o script de condição
Abra a transformação e adicione um script de condição ao nó de nível raiz. O script lê o hash armazenado, calcula o hash atual e retorna true ou false.
Substitua Source.id, Source.email, Source.first_name e Source.last_name pelos nomes de campo reais do esquema de origem. Substitua "my_project" por um prefixo estável que identifique a integração: isso evita colisões de chave de cache com outras operações no mesmo ambiente.
// Build the cache key using a stable prefix and the record's unique ID
cacheKey = "my_project_contact_hash_" + Source.id;
// Read the hash stored from the previous run (env scope, 30-day expiration)
storedHash = ReadCache(cacheKey, 2592000, "env");
// Compute the hash of the fields that matter for this record
currentHash = SHA256(Source.id + "|" + Source.email + "|" + Source.first_name + "|" + Source.last_name);
// Write the current hash back to cache.
// If the record is unchanged, this renews the cache expiration timer.
// If the record changed, this updates the stored hash for the next run.
WriteCache(cacheKey, currentHash, 2592000, "env");
// Return true to process the record, false to skip it
If(storedHash == currentHash, false, true);
Dica
Para usar MD5 em vez de SHA256, substitua SHA256(...) por MD5(...). O resto do script permanece idêntico.
Pontos-chave sobre este script:
ReadCacheretornanullquando nenhum valor é armazenado para a chave (por exemplo, na primeira execução ou após expiração do cache). Um hash armazenado comonullnunca é igual ao hash calculado, então todos os registros são processados na primeira execução.WriteCacheé chamado para cada registro, incluindo os não alterados. Para registros não alterados, isso renova a expiração de 30 dias sem modificar o valor armazenado.2592000é a expiração máxima do cache em segundos (30 dias). Ajuste esse valor se a sincronização for executada com menos frequência e os registros podem não aparecer em execuções consecutivas.- O escopo
"env"torna a entrada de cache visível para todas as operações no mesmo ambiente e faz com que persista entre execuções separadas. O escopo padrão"project"não persiste entre execuções.
Aviso
ReadCache e WriteCache combinados são limitados a 100 chamadas por minuto por organização. Este padrão faz duas chamadas de cache por registro: uma leitura e uma escrita. Uma operação que processa mais de 50 registros por minuto se aproxima desse limite. Para operações com volumes de registro maiores, use Cloud Datastore para armazenar hashes.
Etapa 4: Mapear campos de origem para o destino
Com a condição em vigor, mapeie campos da atividade de origem para a atividade de destino na transformação como de costume. Os registros para os quais a condição retorna false são ignorados: nenhum mapeamento de destino é executado para esses registros.
Parte 2: Deduplicação dentro da execução usando cache
Este padrão detecta registros duplicados dentro de uma única execução de operação. É apropriado quando um conjunto de dados de origem pode conter o mesmo registro mais de uma vez (por exemplo, um relatório que retorna uma linha por linha de transação, o que pode resultar no mesmo ID de cliente aparecendo várias vezes).
As entradas de cache gravadas neste padrão usam a expiração padrão de 30 minutos e escopo "project" (ambos padrões). A janela de 30 minutos é longa o suficiente para abranger uma única execução, e o escopo do projeto é apropriado porque o estado de dedup não precisa sobreviver além da execução atual.
Etapa 1: Escolher uma chave de dedup
Identifique o campo ou a combinação de campos que torna um registro único. Se o registro de origem tiver um campo de chave primária como id ou order_id, use-o diretamente. Se a unicidade depender de uma combinação de campos, concatene-os com separadores |.
-
Opção A: Campo de ID único
Source.customer_id -
Opção B: Chave composta
Source.order_id + "|" + Source.line_number
Etapa 2: Escrever o script de condição
Abra a transformação e adicione um script de condição ao nó de nível raiz.
Substitua "my_project_dedup_" por um prefixo estável e substitua Source.customer_id pela chave de dedup da Etapa 1.
// Build the dedup cache key
dedupeKey = "my_project_dedup_" + Source.customer_id;
// Check whether this key has been seen already in this run
existing = ReadCache(dedupeKey);
If(existing == null,
// First occurrence: mark this key as seen and process the record
WriteCache(dedupeKey, "1");
true;
,
// Duplicate: skip the record
false;
);
Pontos-chave sobre este script:
ReadCachesem argumentos de expiração ou escopo usa a expiração padrão de 30 minutos e escopo"project", que é apropriado para o estado dentro da execução.WriteCache(dedupeKey, "1")armazena um valor de espaço reservado. O valor em si não importa: a presença da chave no cache é o sinal.- Na primeira vez que uma chave é encontrada, a condição retorna
truee o registro é processado. Cada ocorrência subsequente da mesma chave retornafalsee é ignorada.
Aviso
ReadCache e WriteCache estão sujeitos ao mesmo limite de 100 chamadas por minuto por organização da Parte 1. Cada registro único neste padrão faz duas chamadas de cache (uma leitura e uma escrita na primeira ocorrência). Registros duplicados fazem uma chamada (apenas leitura). Para conjuntos de dados grandes, um dicionário indexado no campo de dedup é uma alternativa com maior taxa de transferência e sem limite de taxa de chamadas. Consulte Popular e usar um dicionário. Dicionários têm escopo da thread de operação e não são adequados para estado entre execuções.
Etapa 3: Mapear campos de origem para o destino
Mapeie campos da atividade de origem para a atividade de destino conforme usual. Registros para os quais a condição retorna false são ignorados.
Verificar a integração
Verificando Parte 1 (detecção de mudanças entre execuções)
-
Implante e execute a operação pela primeira vez com seus dados de origem.
-
Nos logs de operação, confirme que todos os registros foram processados. Na primeira execução,
ReadCacheretornanullpara cada registro (nenhum hash armazenado existe ainda), portanto a condição de cada registro retornatrue. -
Execute a operação uma segunda vez sem modificar nenhum registro de origem.
-
Nos logs de operação, confirme que nenhum registro foi processado. Todos os hashes armazenados agora correspondem aos hashes calculados, portanto cada condição retorna
false. -
Modifique um registro de origem e execute a operação uma terceira vez.
-
Nos logs de operação, confirme que exatamente o registro modificado foi processado e todos os outros foram ignorados.
-
Se registros forem inesperadamente ignorados na primeira execução, confirme que o escopo do cache em
ReadCacheeWriteCacheé"env"e que a expressão de chave de cache é idêntica em ambas as chamadas. Uma incompatibilidade no escopo ou nome da chave fazReadCachesempre retornarnull, o que significa que mudanças são sempre detectadas, mas hashes são escritos em uma chave inacessível.
Verificando Parte 2 (deduplicação dentro da execução)
-
Prepare um conjunto de dados de origem que contenha pelo menos dois registros com o mesmo valor de chave de dedup.
-
Implante e execute a operação.
-
Nos logs de operação, confirme que apenas um registro foi escrito no destino para cada chave de dedup única e que registros duplicados foram ignorados.
-
Execute a operação uma segunda vez usando os mesmos dados de origem.
-
Confirme que a primeira ocorrência de cada chave de dedup é processada novamente. O tempo padrão de expiração do cache de 30 minutos significa que o estado de dedup não se estende entre execuções: cada execução começa do zero.
Nota
Se executar a operação duas vezes dentro de 30 minutos, as entradas de cache da primeira execução ainda estão ativas. Nesse caso, a segunda execução ignora todos os registros como duplicados, o que é o comportamento esperado. Aguarde a expiração do cache antes de executar novamente ou use um prefixo de chave de dedup diferente para isolar execuções de teste.
-
Se duplicatas não estão sendo ignoradas, verifique se a expressão de chave de dedup produz um valor estável e não vazio para cada registro. Uma chave que avalia para
nullou uma string vazia faz cada registro parecer único.