Quando uma consulta pontual em grande escala é executada em uma tabela cujas linhas correspondentes estão dispersas em muitos arquivos, o MaxCompute precisa verificar todos esses arquivos para encontrar os resultados. Os índices de filtro Bloom permitem que o MaxCompute ignore arquivos que comprovadamente não contêm os valores alvo durante o planejamento da consulta, reduzindo a E/S e melhorando o desempenho da consulta sem exigir redistribuição de dados.
Pré-requisitos
Antes de começar, certifique-se de que você tem:
Um projeto do MaxCompute. Consulte Criar um projeto do MaxCompute.
-
Evolução de esquema ativada para o projeto. Para ativá-la, execute o seguinte comando no nível do projeto:
setproject odps.schema.evolution.enable=true;Se a evolução de esquema não estiver ativada, as operações DDL subsequentes falharão com um erro semelhante a:
Failed to run ddltask - Schema evolution DDLs is not enabled in project:default
Como funciona
Uma consulta pontual verifica se valores específicos existem em um conjunto de dados. Em cenários de big data, as linhas correspondentes podem estar distribuídas por muitos arquivos, tornando a verificação de todos eles custosa.
Um índice de filtro Bloom é uma estrutura de dados probabilística compacta armazenada junto com cada arquivo de dados. Ao executar uma consulta pontual, o MaxCompute consulta o índice durante o planejamento da consulta para identificar quais arquivos definitivamente não contêm os valores alvo e os ignora — isso é chamado de poda de arquivos. Para os arquivos que passam pelo filtro, o pushdown de predicado padrão na camada de armazenamento é aplicado como uma segunda passagem.
Essa abordagem de dois estágios funciona no nível do arquivo, não no nível da linha, portanto, é leve para criar e manter.
Em comparação com estatísticas de mínimo/máximo, os índices de filtro Bloom fornecem uma poda significativa mesmo para colunas de alta cardinalidade, onde os valores mínimo e máximo abrangem todo o intervalo do arquivo e não oferecem benefício de filtragem.
Em comparação com tabelas clusterizadas, os índices de filtro Bloom oferecem:
Alta eficiência: Os índices de filtro Bloom podem filtrar dados desnecessários com custo mínimo. O consumo de recursos das operações de inserção e consulta é menor do que o dos índices comuns.
Flexibilidade: Indexe qualquer coluna, incluindo chaves não clusterizadas, e combine com um índice clusterizado.
Sem custo de shuffle na escrita: Nenhuma redistribuição de dados é necessária durante as gravações.
Eficaz em colunas de alta cardinalidade: Funciona bem quando os valores dos dados estão amplamente distribuídos entre os arquivos.
Compensação: Os filtros Bloom têm uma probabilidade de falso positivo (FPP) configurável. Um falso positivo faz com que o MaxCompute leia um arquivo que acaba não contendo o valor alvo, mas nunca produz resultados de consulta incorretos — apenas uma pequena E/S extra em casos raros.
Eficiência de espaço: Os índices de filtro Bloom usam arrays de bits. Com 2^32 = 4.294.967.296 bits, um array de bits com 4.200 milhões de bits ocupa apenas 512 MB de espaço de memória (calculado como 4294967296/8/1024/1024 = 512 MB).
Casos de uso
Os índices de filtro Bloom são eficazes quando:
Uma ou mais colunas são usadas como condições de filtro de igualdade (
=,IN) em consultas pontuais de grande escala.Colunas em uma tabela clusterizada, diferentes das chaves de clusterização, são usadas como condições de filtro.
Os dados são ordenados por uma chave de clusterização, chave de ordenação ou função Zorder, e você deseja poda adicional de arquivos nas colunas ordenadas.
Limitações
Predicados suportados: apenas
=eIN. Operadores de intervalo (>,>=,<,<=) eIS NULL/IS NOT NULLnão são suportados.A eficácia da filtragem depende da distribuição dos dados. Os filtros Bloom trazem pouco benefício quando a distribuição dos dados não é discreta (colunas de baixa cardinalidade onde a maioria dos arquivos contém todos os valores).
Tipos de coluna não suportados: DECIMAL, INTERVAL_DAY_TIME, INTERVAL_YEAR_MONTH, STRUCT, MAP, ARRAY e JSON.
Um índice de filtro Bloom por coluna por instrução
CREATE. Para indexar várias colunas, execute instruçõesCREATE BLOOMFILTER INDEXseparadas.Partições dinâmicas não suportam mesclagem automática de índices. Reconstrua o índice manualmente após gravar em partições dinâmicas.
Faturamento
O armazenamento de índices é cobrado como armazenamento padrão no Apsara Distributed File System (Pangu).
|
Operação SQL |
Tarefa de índice acionada |
Faturamento |
|
|
Nenhuma tarefa de criação de índice (apenas DDL) |
Sem cobrança |
|
|
Criação ou reconstrução de índice |
Pagamento conforme o uso: |
|
|
Índice criado para dados inseridos; |
Com base no tamanho dos dados da coluna de índice |
|
|
Tarefa de consulta de índice executada antes da consulta principal |
Com base no tamanho do arquivo de índice |
Para recursos de assinatura, os recursos usados para criação de índices e consultas de índices são cobertos pela assinatura. A comercialização de índices de filtro Bloom não aumenta o custo dos trabalhos de assinatura.
Gerencie índices de filtro Bloom
Crie um índice de filtro Bloom
CREATE BLOOMFILTER INDEX <index_name>
ON TABLE <table_name>
FOR COLUMNS(<column_name>)
IDXPROPERTIES('numitems'='<estimated_distinct_values>', 'fpp'='<false_positive_probability>')
[COMMENT 'idxcomment']
;
|
Parâmetro |
Descrição |
|
|
Nome do índice. |
|
|
Nome da tabela. |
|
|
Nome da coluna a ser indexada. |
|
|
Número estimado de valores distintos na coluna de índice. Isso determina o tamanho do array de bits. Deve ser maior que 0 e não superior a 10.000.000. Defina este valor o mais próximo possível da contagem real de valores distintos — muito alto desperdiça espaço em disco; muito baixo aumenta a FPP. |
|
|
Probabilidade de falso positivo. Intervalo válido: |
Para indexar várias colunas, execute uma instrução CREATE BLOOMFILTER INDEX separada para cada coluna.
Reconstruir um índice
Reconstrua um índice após uma falha de mesclagem ou em uma partição específica:
ALTER TABLE <table_name> [PARTITION <partition_spec>] REBUILD BLOOMFILTER INDEX;
Apenas uma partição pode ser reconstruída por vez.
REBUILD aciona um trabalho de índice cobrado à taxa de pagamento conforme o uso.
Ative índices de filtro Bloom para consultas
Os índices de filtro Bloom não estão ativos por padrão durante o período Beta. Após o lançamento da versão Beta, o padrão poderá ser alterado para true com base no uso online. Ative a poda de arquivos no momento do planejamento da consulta definindo o seguinte antes da sua consulta:
SET odps.sql.enable.bloom.filter.index=true;
SELECT * FROM <table_name> WHERE <indexed_column> = <value>;
Quando esse sinalizador está ativado, o MaxCompute executa um trabalho de índice antes da consulta principal para podar arquivos. Os arquivos podados são aqueles que definitivamente não contêm os valores alvo.
Se os dados resultantes estiverem dispersos em muitos arquivos, a poda de arquivos pode não reduzir a contagem de arquivos o suficiente para compensar a sobrecarga do trabalho de índice. Nesse caso, defina odps.sql.enable.bloom.filter.index=false .
Após a execução de uma consulta com o índice ativado:
No LogView, o primeiro trabalho (
job_1) é o trabalho de índice que realiza a poda de arquivos.Na aba Summary, a tabela virtual com sufixo
bfcorresponde ao arquivo de índice de filtro Bloom.
Se o conjunto de dados for grande, o MaxCompute executará o trabalho de índice como um trabalho distribuído.
Visualize índices em uma tabela
SHOW INDEXES ON <table_name>;
Remover um índice
DROP INDEX [IF EXISTS] <index_name> ON TABLE <table_name>;
Modifique propriedades do índice
ALTER INDEX <index_name> ON <table_name>
SET IDXPROPERTIES(['comment' = '<new_comment>'], ['fpp' = '<new_fpp>']);
Como os índices são mesclados após gravações de dados
Ao inserir dados em uma tabela que possui um índice de filtro Bloom, o sistema gera incrementalmente um índice de filtro Bloom local para cada novo arquivo de dados. Esse índice local suporta pushdown de predicado na camada de armazenamento imediatamente.
Paralelamente, o MaxCompute inicia o BloomfilterAutoMergeTask para mesclar todos os arquivos de índice local em um arquivo de índice consolidado. O índice mesclado permite a poda de arquivos na etapa de planejamento, o que é mais eficiente para grandes conjuntos de dados.
INSERT OVERWRITE TABLE <table_name> [PARTITION <partition_spec>]
SELECT ...
Formato de
partition_spec:(partition_col1 = value1, partition_col2 = value2, ...). Apenas valores constantes são suportados — funções e expressões não são permitidas.
Comportamento de mesclagem:
Se a mesclagem for bem-sucedida, as palavras-chave de conclusão da mesclagem aparecerão na aba Json Summary no LogView. O tempo de mesclagem fica visível na aba SubStatusHistory.
A tarefa de gravação de dados é concluída independentemente do sucesso da mesclagem.
Se a mesclagem falhar (visível no status do BloomfilterAutoMergeTask no LogView), a poda de arquivos na etapa de planejamento ficará indisponível para os novos dados. O índice local ainda suporta pushdown de predicado na camada de armazenamento. Execute
REBUILD BLOOMFILTER INDEXna partição afetada para restaurar a poda na etapa de planejamento.Partições dinâmicas não suportam mesclagem automática. Após gravar em partições dinâmicas, reconstrua manualmente o índice em cada partição atualizada.
Exemplos
Exemplo 1: Crie um índice de filtro Bloom em uma tabela particionada comum
Este exemplo usa o conjunto de dados público TPCDS para demonstrar o fluxo de trabalho completo: criar uma tabela, criar um índice, importar dados e consultar com o índice ativo.
-
Verifique os dados de source.
SET odps.namespace.schema=true; SELECT * FROM bigdata_public_dataset.TPCDS_10G.call_center; -
Crie uma tabela particionada chamada
call_center_test.CREATE TABLE IF NOT EXISTS call_center_test( cc_call_center_sk BIGINT NOT NULL, cc_call_center_id CHAR(16) NOT NULL, cc_rec_start_date DATE, cc_rec_end_date DATE, cc_closed_date_sk BIGINT, cc_open_date_sk BIGINT, cc_name VARCHAR(50), cc_class VARCHAR(50), cc_employees BIGINT, cc_sq_ft BIGINT, cc_hours CHAR(20), cc_manager VARCHAR(40), cc_mkt_id BIGINT, cc_mkt_class CHAR(50), cc_mkt_desc VARCHAR(100), cc_market_manager VARCHAR(40), cc_division BIGINT, cc_division_name VARCHAR(50), cc_company BIGINT, cc_company_name CHAR(50), cc_street_number CHAR(10), cc_street_name VARCHAR(60), cc_street_type CHAR(15), cc_suite_number CHAR(10), cc_city VARCHAR(60), cc_county VARCHAR(30), cc_state CHAR(2), cc_zip CHAR(10), cc_country VARCHAR(20), cc_gmt_offset DECIMAL(5,2), cc_tax_percentage DECIMAL(5,2) ) PARTITIONED BY (ds STRING) ; -
Crie um índice de filtro Bloom na coluna
cc_call_center_sk.CREATE BLOOMFILTER INDEX call_center_test_idx01 ON TABLE call_center_test FOR COLUMNS(cc_call_center_sk) IDXPROPERTIES('fpp' = '0.03', 'numitems'='1000000') COMMENT 'cc_call_center_sk index'; -
Importe dados do conjunto de dados público.
SET odps.namespace.schema=true; INSERT OVERWRITE TABLE call_center_test PARTITION (ds='20241115') SELECT * FROM bigdata_public_dataset.TPCDS_10G.call_center LIMIT 10000;Se os índices de filtro Bloom forem mesclados com sucesso, as palavras-chave de conclusão da mesclagem aparecerão na aba Json Summary no LogView.

-
Consulte com o índice ativado.
SET odps.sql.enable.bloom.filter.index=true; SELECT * FROM call_center_test WHERE cc_call_center_sk = 10 AND ds='20241115';Saída esperada:
+-------------------+-------------------+-------------------+-----------------+-------------------+-----------------+---------------+------------+--------------+------------+------------+----------------+------------+----------------------------+---------------------------------------------------------------------------------------+-------------------+-------------+------------------+------------+-----------------+------------------+----------------+----------------+-----------------+------------+---------------+------------+------------+---------------+---------------+-------------------+------------+ | cc_call_center_sk | cc_call_center_id | cc_rec_start_date | cc_rec_end_date | cc_closed_date_sk | cc_open_date_sk | cc_name | cc_class | cc_employees | cc_sq_ft | cc_hours | cc_manager | cc_mkt_id | cc_mkt_class | cc_mkt_desc | cc_market_manager | cc_division | cc_division_name | cc_company | cc_company_name | cc_street_number | cc_street_name | cc_street_type | cc_suite_number | cc_city | cc_county | cc_state | cc_zip | cc_country | cc_gmt_offset | cc_tax_percentage | ds | +-------------------+-------------------+-------------------+-----------------+-------------------+-----------------+---------------+------------+--------------+------------+------------+----------------+------------+--------------+-------------+---------------------------------------------------------------------------------------+-------------------+-------------+------------------+------------+-----------------+------------------+----------------+----------------+-----------------+------------+---------------+------------+------------+---------------+---------------+-------------------+------------+ | 10 | AAAAAAAAKAAAAAAA | 1998-01-01 | 2000-01-01 | NULL | 2451050 | Hawaii/Alaska | large | 187 | 95744 | 8AM-8AM | Gregory Altman | 2 | Just back responses ought | As existing eyebrows miss as the matters. Realistic stories may not face almost by a | James Mcdonald | 3 | pri | 3 | pri | 457 | 1st | Boulevard | Suite B | Midway | Walker County | AL | 31904 | United States | -6 | 0.02 | 20241115 | +-------------------+-------------------+-------------------+-----------------+-------------------+-----------------+---------------+------------+--------------+------------+------------+----------------+------------+----------------------------+---------------------------------------------------------------------------------------+-------------------+-------------+------------------+------------+-----------------+------------------+----------------+----------------+-----------------+------------+---------------+------------+------------+---------------+---------------+-------------------+------------+No LogView, a tabela virtual com sufixo
bfconfirma que o índice de filtro Bloom foi usado.
-
Visualize o índice.
SHOW INDEXES ON call_center_test;Saída esperada:
ID = 20241115093930589g9biyii**** {"Indexes": [{ "id": "aabdaeb10a7b4e99a94716dabad8****", "indexColumns": [{"name": "cc_call_center_sk"}], "name": "call_center_test_idx01", "properties": { "comment": "cc_call_center_sk index", "fpp": "0.03", "numitems": "1000000"}, "type": "BLOOMFILTER"}]} OK -
Modifique as propriedades do índice. Altere
numitemsde1000000para10000e verifique a alteração.-- Update the property. ALTER INDEX call_center_test_idx01 ON call_center_test SET IDXPROPERTIES('fpp' = '0.03', 'numitems'='10000'); -- Verify the change. SHOW INDEXES ON call_center_test;
Exemplo 2: Crie um índice de filtro Bloom em uma tabela particionada com hash-cluster
Este exemplo indexa uma coluna que não é chave de clusterização (card) em uma tabela com hash-cluster, demonstrando que os índices de filtro Bloom funcionam independentemente da chave de clusterização.
-
Crie uma tabela temporária e carregue os dados.
Crie uma tabela chamada
scope_tmp. ``sql CREATE TABLE IF NOT EXISTS scope_tmp( phone STRING, card STRING, machine STRING, geohash STRING);``Carregue o arquivo scope2.csv usando o comando Tunnel no odpscmd. Execute este comando no diretório
bindo cliente MaxCompute: ``Tunnel upload scope2.csv scope_tmp;``
-
Crie uma tabela particionada com hash-cluster chamada
scope_hash_pt.CREATE TABLE scope_hash_pt ( phone STRING, card STRING, machine STRING, geohash STRING ) PARTITIONED BY (ds STRING) CLUSTERED BY (phone) SORTED BY (card) INTO 512 BUCKETS; -
Crie um índice de filtro Bloom na coluna
card.CREATE BLOOMFILTER INDEX scope_hash_pt_index01 ON TABLE scope_hash_pt FOR COLUMNS(card) IDXPROPERTIES('fpp' = '0.03', 'numitems'='1000000') COMMENT 'card index'; -
Importe os dados.
INSERT OVERWRITE TABLE scope_hash_pt PARTITION (ds='20241115') SELECT * FROM scope_tmp;Se os índices forem mesclados com sucesso, as palavras-chave de conclusão da mesclagem aparecerão na aba Json Summary no LogView.

-
Consulte com o índice ativado.
SET odps.sql.enable.bloom.filter.index=true; SELECT * FROM scope_hash_pt WHERE card='073415764266290' AND ds='20241115';Saída esperada:
+-------------+-----------------+----------------+------------+------------+ | phone | card | machine | geohash | ds | +-------------+-----------------+----------------+------------+------------+ | 1576426**** | 073415764266290 | 51133960245770 | fWbDDsf | 20241115 | +-------------+-----------------+----------------+------------+------------+No LogView, a tabela virtual com sufixo
bfconfirma que o índice de filtro Bloom foi usado.
Exemplo 3: Crie um índice de filtro Bloom em uma tabela particionada ordenada por Zorder
Este exemplo usa a ordenação Zorder para colocalizar dados relacionados antes de criar um índice de filtro Bloom, combinando ambas as técnicas para máxima eficácia de poda.
Prepare os dados seguindo a Etapa 1 do Exemplo 2.
-
Crie uma tabela particionada chamada
scope_zorder_ptcom uma coluna extrazvaluepara armazenar valores Zorder.CREATE TABLE scope_zorder_pt( phone STRING, card STRING, machine STRING, geohash STRING, zvalue BIGINT ) PARTITIONED BY (ds STRING) ; -
Crie um índice de filtro Bloom na coluna
card.CREATE BLOOMFILTER INDEX scope_zorder_pt_index01 ON TABLE scope_zorder_pt FOR COLUMNS(card) IDXPROPERTIES('fpp' = '0.05', 'numitems'='1000000') COMMENT 'idxcomment'; -
Importe dados com ordenação Zorder.
-
Baixe os seguintes pacotes JAR e salve-os em
D:\no seu computador: -
Adicione os pacotes JAR como recursos.
ADD JAR D:\odps-zorder-1.0-SNAPSHOT.jar; ADD JAR D:\odps-zorder-1.0-SNAPSHOT-jar-with-dependencies.jar; -
Crie a UDF Zorder.
CREATE FUNCTION zorder AS 'com.aliyun.odps.zorder.evaluateZValue2WithSize' USING 'odps-zorder-1.0-SNAPSHOT-jar-with-dependencies.jar'; -
Insira dados ordenados pelo valor Zorder.
-- Required to disable the ORDER BY row limit check. SET odps.sql.validate.orderby.limit=false; INSERT OVERWRITE TABLE scope_zorder_pt PARTITION (ds='20241115') SELECT *, zorder(HASH(phone), 100000000, HASH(card), 100000000) AS zvalue FROM scope_tmp ORDER BY zvalue;Se os índices forem mesclados com sucesso, as palavras-chave de conclusão da mesclagem aparecerão na aba Json Summary no LogView.

-
-
Consulte com o índice ativado.
SET odps.sql.enable.bloom.filter.index=true; SELECT * FROM scope_zorder_pt WHERE card='073415764266290' AND ds='20241115';Saída esperada:
+-------------+-----------------+----------------+------------+---------------------+------------+ | phone | card | machine | geohash | zvalue | ds | +-------------+-----------------+----------------+------------+---------------------+------------+ | 1576426**** | 073415764266290 | 51133960245770 | fWbDDsf | 3590549286038929408 | 20241115 | +-------------+-----------------+----------------+------------+---------------------+------------+No LogView, a tabela virtual com sufixo
bfconfirma que o índice de filtro Bloom foi usado.
Próximos passos
Instrução ANALYZE — colete estatísticas de tabela para auxiliar na otimização de consultas