Contrato do resultado entregue
Uma equipa fictícia de suporte a fundos prepara dois produtos: um painel de exceções de processamento e uma pesquisa de procedimentos para os operadores. O painel deve indicar quais os lotes que ainda precisam de intervenção. A pesquisa deve encontrar documentos aplicáveis à entidade do operador e à versão atual do procedimento. Uma resposta rápida que usa dados antigos ou um documento de outra entidade pode induzir uma ação incorreta. O contrato de consumo deve, por isso, identificar população, momento de referência, autorização e critérios de utilidade. Escreve uma ficha de aceitação com o proprietário de negócio. No painel, regista a unidade de contagem, o atraso máximo aceite e a ação permitida quando os dados estão atrasados. Na pesquisa, regista a identidade utilizada, a origem dos documentos, o critério de versão e a evidência esperada na resposta. Define também o comportamento quando não existem resultados elegíveis: explicar a ausência e escalar a pesquisa é preferível a preencher a resposta com um procedimento sem validade. Estes são requisitos do exemplo, não regras internas de um banco real.
Comparar execução com execução
Um relatório de ensaio mostra 18 segundos na primeira execução e 0,4 segundos na segunda. Antes de atribuir a melhoria a uma alteração SQL, consulta cacheHit nas estatísticas do job. Se houve reutilização de resultados, as duas medições responderam a perguntas diferentes. Para comparar execução, desativa a reutilização de resultados e mantém constantes os dados de entrada, parâmetros, identidade e condições de capacidade. Regista também custo e correção do resultado; um tempo menor isolado não basta. No exemplo, prepara três execuções por variante e conserva os identificadores dos jobs. Se os tempos variam muito, descreve a dispersão e investiga concorrência antes de escolher um vencedor. Um painel com CURRENT_TIMESTAMP na consulta pode não usar cache mesmo sem alterações visíveis nos dados. Não retires a função só para obter um número melhor se ela representa o momento de observação exigido pelo negócio. Para alimentar outro job com resultados partilhados, usa uma tabela de destino com ciclo de vida definido, em vez de tratar uma tabela anónima de cache como uma interface estável.
Atualização, atraso e significado do painel
O responsável de exploração propõe refresh_interval_minutes=30 e escreve no SLA que os resultados estarão sempre atualizados em 30 minutos. A opção limita a frequência de atualização automática; não garante o início nem a conclusão de cada atualização. Distingue o estado materializado, o resultado da consulta e o instante dos dados de origem. Sem uma configuração especial de tolerância a atraso, a falta de refresh recente pode aumentar o trabalho necessário para obter o resultado atual. Com max_staleness, a consulta direta à materialized view aceita atraso dentro do intervalo configurado. Uma tolerância de quatro horas não cumpre, por si só, um requisito de quinze minutos. Prepara um ensaio com um movimento conhecido, instante de chegada e instante em que aparece no painel. Decide o que apresentar quando a origem não cumpre o prazo: indicador de atraso, bloqueio da decisão ou encaminhamento manual. Uma atualização tecnicamente bem-sucedida não prova que a origem enviou todos os lotes. Conserva estas duas verificações separadas no registo de aceitação e atribui responsáveis diferentes quando necessário.
Filtrar documentos e medir utilidade
Na pesquisa, a lista candidata está ordenada por um mecanismo externo. O exercício desta aula não calcula essa ordem. Para o pedido da entidade t1 no instante 60, os primeiros documentos são b e c: b pertence a t2 e c expirou no instante 50. Escolher primeiro dois documentos e só depois aplicar a elegibilidade devolve uma lista vazia. Percorrer os candidatos elegíveis antes de limitar a dois permite encontrar a e g mais abaixo. Nenhuma opção deve entregar b ou c ao consumidor. Em BigQuery, o efeito de um filtro depende da sua posição e das colunas armazenadas no índice. Um predicado na subconsulta da base não basta para garantir pre-filtering quando usa uma coluna não armazenada. Verifica a configuração e o plano utilizado; não deduzas o comportamento apenas pelo aspeto do SQL. Mesmo pre-filtering pode produzir poucos resultados numa pesquisa aproximada muito seletiva. O exercício ilustra a ordem das operações numa lista finita e fornecida. Não reproduz seleção de partições, distâncias vetoriais ou cobertura de um índice real.
Executar o contrato local de elegibilidade
Guarda o código como run.py e usa case.json do laboratório pde-retrieval-gate: python3 run.py < case.json. A entrada contém documents e queries. Cada documento tem identificador, tenant, versão representada no embedding, versão atual, sinal de eliminação e intervalo de validade. Cada pedido contém instante, tenant, k, referência elegível e candidatos ordenados. Os nomes são fictícios. Não são carregados documentos, credenciais ou dados de clientes. A regra aceita availableAt <= at < validUntil, exige versões iguais, tenant igual e deleted=false. A disponibilidade tem limite inclusivo; a expiração tem limite exclusivo. A referência contém entre um e k documentos elegíveis e sem duplicados. Se estiver errada, a entrada é rejeitada, em vez de ajustar silenciosamente a referência para melhorar a métrica. Na fixture, a e g são a referência. postFilterHits vale zero e preFilterHits vale dois, ambos sobre referenceCount=2. O relatório conserva os motivos de exclusão de cada candidato. Em produção, até esses identificadores e motivos exigiriam controlo de acesso; aqui são apenas dados sintéticos de aprendizagem.
Contraprovas antes de aceitar uma melhoria
Altera a lista candidata para h,a,g mantendo k=2. Os três documentos são elegíveis, mas h não pertence à referência. O resultado anterior ao limite é h,a, com um acerto em dois. Filtrar corretamente não torna uma ordenação útil. Se g faltar na lista fornecida, este código também não o descobre. Para avaliar um motor real, seria necessário um conjunto de pedidos representativo e uma referência construída com critérios e população coerentes. Depois altera availableAt de f para 60: passa a elegível exatamente no instante do pedido. Altera validUntil de c para 60: continua excluído. Corrige a versão embebida de d para a versão atual e observa como a sua posição pode ocupar uma vaga antes de g. Retirar um documento inválido e recuperar um documento relevante são propriedades diferentes. Os testes permutam a ordem do registo de documentos sem mudar resultados, mas não tratam a ordem dos candidatos como irrelevante. Essa ordem faz parte do contrato. O programa mantém authorizationEnforced e embeddingQualityProven a false porque valida metadata fornecida, sem autenticar entidades nem medir a qualidade do modelo.
Publicar para a identidade certa
Uma authorized view permite expor uma seleção de dados sem conceder leitura direta das tabelas de origem ao consumidor. Desenha o ensaio com a identidade que executa o job e com o projeto onde esse job é criado. Não uses apenas a conta do proprietário dos dados para aprovar a partilha. Confirma também a localização compatível dos datasets. Quando há VPC Service Controls, verifica o percurso pelos projetos da view e da origem, mesmo que o consumidor não precise de permissões IAM diretas sobre a origem. No caso fictício, o operador usa o projeto ops, a view está em reporting e a origem em funds. Um erro de perímetro não justifica conceder acesso global ao dataset funds. Recolhe o erro, identifica a etapa e corrige a autorização específica em falta com o proprietário do controlo. Testa uma entidade permitida e outra excluída, documentando o resultado esperado antes da execução. Para alterações de acesso a colunas, considera também resultados anteriormente obtidos em cache: a revogação do papel Fine-Grained Reader associado a um policy tag não invalida automaticamente esses resultados anteriores. Não generalizes esse comportamento a todas as formas de revogação.
Decisão de entrada em exploração
Prepara uma tabela de evidências para a reunião de passagem a exploração. Para o painel: pedido de negócio, SQL efetivo, intervalo dos dados, cacheHit, tempo, custo e exemplo reconciliado. Para a pesquisa: população elegível, versões, candidatos, referência, acertos e casos de exclusão. Para a partilha: identidade, projeto do job, caminho pelos projetos e resultado dos testes positivos e negativos. Associa cada falha a um responsável e a uma ação verificável. O patrocinador pede uma demonstração hoje. É aceitável mostrar o exercício com documentos sintéticos e explicar os resultados, mantendo a integração real pendente. Não é aceitável apresentar dois acertos locais como prova de isolamento entre clientes ou qualidade das respostas geradas. Na decisão final, distingue evidência disponível de hipótese: o laboratório prova a execução do seu contrato limitado; o serviço real precisa de ensaios próprios. Entrega ao suporte um procedimento para falta de resultados, atraso da origem e falha de acesso, com critérios de escalamento. Fecha a aula reproduzindo um resultado correto e uma contraprova, e explica em inglês o impacto operacional de cada um.
"""Original offline ranking/filter-order model. No embeddings or access enforcement."""
import json
import re
import sys
def require(ok, message):
if not ok:
raise ValueError(message)
def integer(v, low, high):
return type(v) is int and low <= v <= high
def identifier(v):
return type(v) is str and re.fullmatch(r'[A-Za-z0-9_-]{1,48}', v) is not None
def keys(v, expected):
require(type(v) is dict and set(v) == set(expected.split()), 'Unexpected object fields')
def blocked(doc, query):
reasons = []
if doc['tenant'] != query['tenant']:
reasons.append('tenant-mismatch')
if doc['deleted']:
reasons.append('deleted')
if doc['availableAt'] > query['at']:
reasons.append('not-yet-available')
if doc['validUntil'] <= query['at']:
reasons.append('expired')
if doc['embeddedVersion'] != doc['currentVersion']:
reasons.append('stale-version')
return reasons
def evaluate(payload):
keys(payload, 'documents queries')
documents, queries = payload['documents'], payload['queries']
require(type(documents) is list and 1 <= len(documents) <= 100, 'Need 1..100 documents')
require(type(queries) is list and 1 <= len(queries) <= 20, 'Need 1..20 queries')
registry = {}
for d in documents:
keys(d, 'id tenant embeddedVersion currentVersion deleted availableAt validUntil')
require(identifier(d['id']) and identifier(d['tenant']), 'Invalid document identifier')
require(d['id'] not in registry, 'Duplicate document id')
require(all(integer(d[k], 1, 1000000) for k in ['embeddedVersion', 'currentVersion']), 'Invalid version')
require(type(d['deleted']) is bool, 'deleted must be boolean')
require(all(integer(d[k], 0, 1000000000) for k in ['availableAt', 'validUntil']), 'Invalid document time')
require(d['availableAt'] < d['validUntil'], 'Invalid validity interval')
registry[d['id']] = d
ids = set()
result = []
for q in queries:
keys(q, 'id tenant at k reference candidate')
require(identifier(q['id']) and identifier(q['tenant']), 'Invalid query identifier')
require(q['id'] not in ids, 'Duplicate query id')
ids.add(q['id'])
require(integer(q['at'], 0, 1000000000) and integer(q['k'], 1, 10), 'Invalid query time or k')
for name, low, high in [('reference', 1, q['k']), ('candidate', 0, 100)]:
values = q[name]
require(type(values) is list and low <= len(values) <= high, 'Invalid '+name+' length')
require(all(identifier(v) and v in registry for v in values), 'Unknown '+name+' document')
require(len(set(values)) == len(values), 'Duplicate '+name+' document')
require(all(not blocked(registry[v], q) for v in q['reference']), 'Reference contains ineligible document')
eligible = lambda v: not blocked(registry[v], q)
post = [v for v in q['candidate'][:q['k']] if eligible(v)]
pre = [v for v in q['candidate'] if eligible(v)][:q['k']]
reference = set(q['reference'])
result.append({'id': q['id'], 'referenceCount': len(reference),
'postFilterIds': post, 'preFilterIds': pre,
'postFilterHits': len(reference.intersection(post)),
'preFilterHits': len(reference.intersection(pre)),
'blockedCandidates': [{'id': v, 'reasons': blocked(registry[v], q)}
for v in q['candidate'] if not eligible(v)]})
return {'queries': sorted(result, key=lambda x: x['id']),
'rankingExhaustive': False, 'authorizationEnforced': False,
'embeddingQualityProven': False, 'productionApproval': False}
def main():
raw = sys.stdin.read(1000001)
require(len(raw) <= 1000000, 'Input too large')
print(json.dumps(evaluate(json.loads(raw)), sort_keys=True))
if __name__ == '__main__':
try:
main()
except (ValueError, TypeError, RecursionError):
print('Invalid retrieval fixture', file=sys.stderr)
sys.exit(2)
Com k=2 e candidatos b,c,a,d,e,f,g,h, a fixture devolve zero acertos após limitar e dois acertos quando filtra antes do limite. A referência elegível é a,g.
Armadilhas comuns
Confundir cache com otimização; intervalo de refresh com SLA; elegibilidade com relevância; filtro local de tenant com autenticação real; testes com conta proprietária com acesso do consumidor.
Tópicos relacionados: Preparação de dados para análise · Contratos e alterações · Observabilidade de pipelines
Entrega resultados cuja população, validade, utilidade e identidade de consumo foram explicitamente verificadas.
Referência: Professional Data Engineer standard exam guide · Current linked standard guide (document title v4.2); edition date unconfirmed (2026-09-30 inspection)