BrWaC: do rastreamento da web ao Parquet no Hugging Face
O tamanho e o formato original do BrWaC dificultavam seu uso direto com a biblioteca datasets. Para facilitar esse acesso, publiquei no Hugging Face um espelho em Parquet do corpus criado por Wagner Filho e colaboradores, cuja versão de referência reúne 3,53 milhões de documentos e 2,68 bilhões de tokens. Minha contribuição é o empacotamento para carregamento e processamento no ecossistema atual, não a criação ou a curadoria científica do corpus [3, 4].
Uma distinção de autoria é indispensável. Jorge A. Wagner Filho, Rodrigo Wilkens, Marco Idiart e Aline Villavicencio são os autores do corpus descrito no LREC 2018; o trabalho continua uma coleta anterior de Wagner Filho, Wilkens, Leonardo Zilio, Idiart e Villavicencio [3, 4]. Eu não criei nem conduzi a curadoria científica do BrWaC original. Em 8 de janeiro de 2023, publiquei no Hugging Face um empacotamento/espelho em Parquet, adequado à biblioteca datasets [1, 2]. Portanto, cite os autores originais pelo corpus e dominguesm/brwac pela distribuição utilizada.
Linhagem da coleta
O BrWaC segue a família metodológica WaCky (Web-As-Corpus Kool Yinitiative), criada para produzir corpora de bilhões de palavras mediante busca, rastreamento, limpeza, deduplicação e anotação [4, 5]. A versão inicial do BrWaC tinha cerca de 1,5 a 1,6 bilhão de tokens. A versão publicada em janeiro de 2017 agregou uma nova coleta e chegou a 2,68 bilhões.
O processo relatado no artigo tem quatro etapas:
- Identificação de URLs. Foram sorteados 8.000 pares de palavras de frequência média do repositório Linguateca. Para cada par, os dez primeiros resultados da API do Microsoft Bing formaram 80 mil sementes. Os links foram expandidos por dois níveis de recursão e restringidos ao domínio de topo
.br, gerando mais de 38 milhões de URLs candidatas. - Limpeza pós-rastreamento. Filtros removeram HTML, cabeçalhos, rodapés, anúncios e outros elementos de boilerplate. O pipeline controlou densidade de etiquetas HTML e exigiu ao menos 25% de stopwords, heurística de idioma. Após a limpeza com jusText, textos menores que 256 caracteres foram rejeitados.
- Remoção de duplicatas. Duplicatas exatas foram descartadas. Para sobreposição parcial, o sistema manteve um conjunto global de sentenças com mais de 25 caracteres e rejeitou documentos em que mais de 10% dessas sentenças já haviam aparecido. A inserção imediata no conjunto também detectava repetição dentro do próprio documento.
- Anotação. Os documentos aceitos foram analisados pelo parser Palavras e a distribuição original ofereceu formatos CoNLL e Moses. O espelho HF, porém, contém texto segmentado, metadados e sentenças; seu esquema público não expõe as colunas morfossintáticas do Palavras.
O resumo do LREC fala em mais de 60 milhões de páginas rastreadas e filtradas; a seção de URLs informa mais de 38 milhões de URLs após expansão. Esses números descrevem estágios/unidades diferentes e não devem ser tratados como contagens equivalentes. Aproximadamente 95% dos documentos processados foram descartados, sobretudo por duplicação exata e por tamanho insuficiente; apenas 5,6% chegaram à seleção final [4].
Renderizando diagrama...
Restringir a coleta a .br aumenta a probabilidade de português brasileiro, mas não me permite concluir idioma, nacionalidade do autor nem variedade linguística de cada página. Da mesma forma, 121.075 sites representados e a contribuição máxima de 70.348 documentos por um único site sugerem diversidade de origem, não representatividade demográfica. O artigo classificou os cem sites mais frequentes pela taxonomia IAB e encontrou várias categorias, uma evidência útil, porém limitada aos domínios de maior volume [4].
Números, tokens e tipos
As estatísticas da versão de referência são:
| Medida | Valor publicado | Observação |
|---|---|---|
| Documentos | 3.530.796 | Coincide com as linhas do split HF train |
| Sentenças | cerca de 145 milhões | O artigo também reporta 145,3 milhões na comparação de duplicação |
| Tokens | 2,68 bilhões | Contagem da publicação, não recalculada sobre os Parquets |
| Tipos | 5,79 milhões | Vocabulário sob a tokenização/filtro dos autores |
| Sites | 121.075 | Diversidade de hosts na coleta original |
Os autores excluíram das contagens de tokens e tipos itens com números ou caracteres especiais, exceto hífen. Isso importa: “token” não é byte, palavra ortográfica nem subword de um modelo. Recontar com spaCy, SentencePiece ou str.split() produzirá outro resultado.
A razão tipo-token é definida por:
em que é o número de tipos distintos e é o número total de tokens.
Com os valores publicados,
coerente com o TTR arredondado de 0,0021 na página original [3]. TTR cai mecanicamente à medida que o corpus cresce; só compare corpora com tokenização, normalização e tamanho controlados. Para comparações robustas, use amostras do mesmo número de tokens ou medidas como MSTTR.
Uma divisão igualmente simples dá
tokens por documento. Essa média é apenas uma estimativa agregada: combina números arredondados da versão publicada, esconde uma distribuição provavelmente assimétrica e não constitui recontagem do pacote HF. Documentos muito longos elevam a média; o título de uma linha não revela mediana, percentis ou truncamentos.
Arquivos e esquema no Hugging Face
Distribuí dominguesm/brwac em um único split train e 38 arquivos Parquet. Registrei 3.530.796 exemplos, download de 11.616.550.261 bytes, cerca de 11,62 GB decimais ou 10,82 GiB, e 18.828.412.956 bytes como tamanho lógico do dataset [1, 2]. O endpoint atual do Dataset Viewer estima 22.629.083.411 bytes em memória. Essa diferença pode depender da representação Arrow e da versão do serviço; planeje disco e RAM com margem e meça no ambiente real, em vez de interpretar qualquer desses campos como memória máxima garantida.
Cada linha tem quatro campos:
doc_id: string
title: string
uri: string
text:
paragraphs:
- [sentença 1, sentença 2, ...] # parágrafo 1
- [sentença 1, sentença 2, ...] # parágrafo 2text.paragraphs é, portanto, uma lista de parágrafos, e cada parágrafo é uma lista de sentenças. Não é uma string e tampouco uma lista plana. O card representa text tecnicamente como uma sequência cujo campo paragraphs também é sequência, enquanto as linhas serializadas pelo Viewer aparecem como {"text": {"paragraphs": [[...], [...]]}} [1, 2]. O código de consumo deve validar a forma observada e achatar apenas quando a tarefa dispensar limites de parágrafo.
Renderizando diagrama...
Não há partições oficiais de validação ou teste. Criá-las por sorteio ingênuo pode espalhar textos quase duplicados, o mesmo host ou versões da mesma página entre conjuntos. Para avaliação, agrupe primeiro por host e por similaridade de conteúdo, depois divida por grupo e, quando houver datas confiáveis, considere corte temporal.
Carregamento sem esgotar memória
Para exploração, prefira streaming. O exemplo usa a distribuição pública do Hub; no relatório do experimento, registre a URL, a data de acesso, a edição BrWaC 2017 e as versões das bibliotecas.
from datasets import load_dataset
stream = load_dataset(
"dominguesm/brwac",
split="train",
streaming=True,
)
def sentences(row):
for paragraph in row["text"]["paragraphs"]:
yield from paragraph
for row in stream.take(3):
plain_text = "\n\n".join(
" ".join(paragraph)
for paragraph in row["text"]["paragraphs"]
)
print(row["doc_id"], len(list(sentences(row))), plain_text[:160])Para operações aleatórias repetidas, baixe o dataset, mas espere dezenas de gigabytes entre Parquet, cache Arrow e artefatos derivados:
from datasets import load_dataset
dataset = load_dataset(
"dominguesm/brwac",
split="train",
cache_dir="/volume/grande/huggingface",
)
assert dataset.num_rows == 3_530_796
print(dataset.features)Validação de integridade
Antes da análise linguística, registre proveniência e verifique a entrega:
- Registre a edição BrWaC 2017, a distribuição
dominguesm/brwac, a data de acesso e as versões dedatasets,pyarrowe do tokenizer. - Confirme 38 Parquets, nomes esperados e soma das linhas igual a 3.530.796.
- Preserve um inventário local dos arquivos e documente qualquer falha ou nova tentativa de download.
- Valide tipos, níveis de listas, nulos, IDs repetidos e URIs malformadas.
- Separe métricas reproduzidas no pacote HF de números citados da publicação original.
import re
from huggingface_hub import HfApi
REPO = "dominguesm/brwac"
api = HfApi()
files = api.list_repo_files(REPO, repo_type="dataset")
shards = sorted(f for f in files if re.fullmatch(r"data/.*\.parquet", f))
assert len(shards) == 38, f"inventário inesperado: {len(shards)} shards"
assert "README.md" in files
print(shards[0], shards[-1])O inventário confirma a entrega observada, mas a reprodução completa deve registrar também como os textos foram normalizados e tokenizados. Se o projeto exigir cadeia de custódia, preserve uma cópia imutável em armazenamento controlado e publique um manifesto legível com edição, origem, data de aquisição, arquivos e tamanhos, sem modificar o corpus.
Validação de qualidade
O artigo já fornece um ponto de partida. Apenas 1,3% das sentenças do BrWaC aparecem repetidas na avaliação dos autores; para sentenças com mais de 20 tokens, a incidência cai a 0,5%, contra 5,7% no ukWaC e 9,0% no frWaC [4]. Isso não significa “zero duplicação”. Menus reescritos, paráfrases, páginas espelho e trechos abaixo do limiar podem sobreviver. A própria amostra exibida no card contém sinais de mojibake em títulos, como sequências Ã/Â, além de conteúdo de navegação e uma frase em inglês [1].
Uma taxa simples de duplicação exata de sentenças normalizadas pode ser definida como:
em que é o total de ocorrências de sentenças na amostra e é o número de sentenças normalizadas distintas na amostra.
Essa fórmula não reproduz automaticamente a métrica do artigo: os autores usaram limiares de comprimento e comparações específicas. Documente normalização, unidade e amostragem. Para duplicação documental, compare documentos normalizados; para quase duplicatas, use MinHash/LSH ou similaridade de shingles.
O seguinte esqueleto faz uma triagem limitada, não uma certificação:
import re
import unicodedata
from collections import Counter
from datasets import load_dataset
def normalize(text):
text = unicodedata.normalize("NFKC", text).casefold()
return re.sub(r"\s+", " ", text).strip()
stream = load_dataset(
"dominguesm/brwac",
split="train",
streaming=True,
)
sample = stream.shuffle(seed=42, buffer_size=20_000).take(100_000)
sentences_seen = Counter()
missing = Counter()
mojibake = 0
for row in sample:
for field in ("doc_id", "title", "uri", "text"):
missing[field] += row.get(field) in (None, "")
mojibake += bool(re.search(r"Ã.|Â.", row["title"] or ""))
for paragraph in row["text"]["paragraphs"]:
for sentence in paragraph:
sentences_seen[normalize(sentence)] += 1
S = sum(sentences_seen.values())
U = len(sentences_seen)
print({"duplicate_rate": 1 - U / S, "missing": missing, "mojibake_titles": mojibake})Amplie a validação com distribuição de comprimentos, proporção de português por documento, domínios, MIME residual, código, spam, pornografia, toxicidade, datas, documentos vazios, quebras de parágrafo e sobreposição com benchmarks. Leia amostras estratificadas por host, comprimento e score de idioma; médias globais escondem caudas problemáticas.
Aplicações e limites
O BrWaC é útil para modelos de linguagem e embeddings, léxicos e dicionários, frequências e colocações, similaridade semântica, indução de sentidos, classificação de documentos, legibilidade e adaptação de modelos ao português brasileiro. A segmentação em sentenças e parágrafos permite construir janelas sem atravessar arbitrariamente documentos. uri e title apoiam validações por fonte, mas não devem ser oferecidos como atributos de previsão se introduzirem atalhos.
Escala não substitui adequação. O corpus antecede muitos benchmarks modernos, mas páginas podem ter sido republicadas depois; faça detecção de contaminação antes de avaliar modelos. Como há apenas train, qualquer conjunto de teste deve ser criado externamente e documentado. A anotação automática do Palavras também carrega erros sistemáticos, e ela não está presente como estrutura no pacote HF descrito aqui.
PII, viés da web e direitos
Páginas públicas podem conter nomes, e-mails, telefones, endereços, identificadores, relatos de saúde, opiniões políticas ou textos de menores. Acesso público não equivale a consentimento para treinamento, inferência ou republicação. Detectores de PII têm falsos negativos; combine regras, modelos, revisão humana e um processo de exclusão. Minimize retenção, proteja os dados brutos, não tente reidentificar pessoas e avalie LGPD e outras normas aplicáveis ao contexto institucional.
O corpus herda vieses de acesso digital, ranqueamento do Bing, disponibilidade histórica, domínio .br, SEO, popularidade e decisões de filtragem. Grupos com menor presença na web ficam sub-representados; 25% de stopwords favorece certos gêneros; o mínimo de 256 caracteres remove textos curtos; deduplicação pode reduzir conteúdo legítimo altamente citado. Dialetos, oralidade transcrita e comunidades fora de .br não são amostrados de modo uniforme. “Multidomínio” não significa neutro, balanceado ou representativo da população brasileira.
Há ainda incerteza de licença. A página original diz que o BrWaC foi disponibilizado para fins de pesquisa, e o artigo fala em acesso livre para a comunidade de pesquisa [3, 4]. O card HF é mais restritivo: declara uso somente para pesquisa acadêmica e veda aplicações comerciais, mas seus metadados marcam license: unknown e a seção de licença permanece sem informação [1]. Isso não é uma licença padronizada e completa.
Também não se deve importar automaticamente termos do projeto WaCky. Suas páginas históricas dizem que os corpora eram gratuitos, não vendidos, ofereciam opt-out e exigiam contato para download; o rodapé licencia o conteúdo da wiki, salvo indicação contrária, sob CC BY-NC-SA 4.0 [6]. Esse rodapé não me permite concluir que cada corpus WaCky, o BrWaC ou as páginas rastreadas tenham a mesma licença. A licença CC BY 4.0 exibida pelo ACL Anthology cobre a publicação do LREC, não necessariamente os dados coletados. Direitos autorais e termos dos sites-fonte podem continuar aplicáveis.
Consequência prática: trate o pacote como uso acadêmico, não comercial e juridicamente não esclarecido até obter autorização dos responsáveis pelo corpus e revisão institucional. Não presuma que download público autoriza redistribuição, produto comercial ou publicação de trechos. Registre a versão dos termos consultados e, para um projeto novo, contate a equipe original antes de investir em treinamento de alto custo.
Conclusão
Com o empacotamento em Parquet, tornei o BrWaC original mais acessível pela biblioteca datasets, preservando a autoria de Wagner Filho e colaboradores. Entreguei uma distribuição prática para processamento em escala e aprendi que a reutilização responsável exige validar qualidade, proveniência, privacidade e licença conforme a aplicação.
Referências
- DominguesM. Dataset Card for BrWaC. Hugging Face, 2023.
- Hugging Face. API e inventário de arquivos de dominguesm/brwac.
- UFRGS PLN. BrWaC: Current version.
- Wagner Filho, J. A.; Wilkens, R.; Idiart, M.; Villavicencio, A. The brWaC Corpus: A New Open Resource for Brazilian Portuguese. LREC, 2018.
- Baroni, M.; Bernardini, S.; Ferraresi, A.; Zanchetta, E. The WaCky Wide Web. Language Resources and Evaluation 43, 209-226, 2009.
- WaCky. Corpora e Download/Use, cópias históricas no Internet Archive.
Consultas às páginas e APIs: 24 de julho de 2026.
@inproceedings{wagner-filho-etal-2018-brwac,
title = {The br{W}a{C} Corpus: A New Open Resource for {B}razilian {P}ortuguese},
author = {Wagner Filho, Jorge A. and Wilkens, Rodrigo and Idiart, Marco and Villavicencio, Aline},
booktitle = {Proceedings of the Eleventh International Conference on Language Resources and Evaluation (LREC 2018)},
year = {2018},
month = may,
address = {Miyazaki, Japan},
publisher = {European Language Resources Association (ELRA)},
url = {https://aclanthology.org/L18-1686/}
}
@article{baroni-etal-2009-wacky,
title = {The {WaCky} Wide Web: A Collection of Very Large Linguistically Processed Web-Crawled Corpora},
author = {Baroni, Marco and Bernardini, Silvia and Ferraresi, Adriano and Zanchetta, Eros},
journal = {Language Resources and Evaluation},
volume = {43},
pages = {209--226},
year = {2009},
doi = {10.1007/s10579-009-9081-4}
}
@misc{dominguesm-2023-brwac,
title = {{BrWaC}: Hugging Face Dataset Packaging},
author = {{DominguesM}},
year = {2023},
howpublished = {Hugging Face Datasets},
url = {https://huggingface.co/datasets/dominguesm/brwac},
note = {Empacotamento do corpus original; licença indicada como desconhecida no card}
}