Ir para o conteúdo

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:

%%{init: {"themeVariables": {"lineColor": "#6b7280", "edgeLabelBackground": "#f5f5f5"}}}%% flowchart LR A[Source activity] --> B["Transformation
(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:

  • ReadCache retorna null quando nenhum valor é armazenado para a chave (por exemplo, na primeira execução ou após expiração do cache). Um hash armazenado como null nunca é 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:

  • ReadCache sem 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 true e o registro é processado. Cada ocorrência subsequente da mesma chave retorna false e é 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)

  1. Implante e execute a operação pela primeira vez com seus dados de origem.

  2. Nos logs de operação, confirme que todos os registros foram processados. Na primeira execução, ReadCache retorna null para cada registro (nenhum hash armazenado existe ainda), portanto a condição de cada registro retorna true.

  3. Execute a operação uma segunda vez sem modificar nenhum registro de origem.

  4. 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.

  5. Modifique um registro de origem e execute a operação uma terceira vez.

  6. Nos logs de operação, confirme que exatamente o registro modificado foi processado e todos os outros foram ignorados.

  7. Se registros forem inesperadamente ignorados na primeira execução, confirme que o escopo do cache em ReadCache e WriteCache é "env" e que a expressão de chave de cache é idêntica em ambas as chamadas. Uma incompatibilidade no escopo ou nome da chave faz ReadCache sempre retornar null, 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)

  1. Prepare um conjunto de dados de origem que contenha pelo menos dois registros com o mesmo valor de chave de dedup.

  2. Implante e execute a operação.

  3. 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.

  4. Execute a operação uma segunda vez usando os mesmos dados de origem.

  5. 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.

  6. 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 null ou uma string vazia faz cada registro parecer único.