Dentro do ecossistema de big data, cargas de trabalho e consultas altamente performáticas são essenciais para manter os clientes satisfeitos e os negócios funcionando com sucesso. No mundo do banco de dados SQL, os índices oferecem suporte às oportunidades de otimização de desempenho de consultas de forma bastante eficiente. No entanto, no Data Lakehouse, existem métodos limitados de aplicação de índices a tabelas delta. É aí que entram os Índices de Filtro de Bloom.
Os Índices de Filtro de Bloom são estruturas de dados eficientes em termos de espaço que permitem pular dados em colunas selecionadas. Eles operam afirmando que os dados definitivamente não estão no arquivo ou que provavelmente estão no arquivo, com uma probabilidade definida de falso positivo (FPP). Os Índices de Filtro de Bloom são essenciais para a construção de Data Lake houses altamente performáticas.
Solução
Um Índice de Filtro de Bloom é um índice específico do Databricks que pode ser aplicado a uma coluna específica em tabelas delta. Ele é capaz de melhorar o desempenho da execução de consultas em mais de 50% quando aplicado corretamente.
Neste artigo, abordaremos a questão de como começar com Índices de Filtro de Bloom. Aprenderemos como criar e aplicar um Índice de Filtro de Bloom em uma tabela do conjunto de dados do Táxi de Nova York e, em seguida, compararemos o desempenho da execução da consulta com uma tabela réplica que não possui um Índice de Filtro de Bloom aplicado à mesma coluna. Além disso, exploraremos como ajustar as opções do Índice de Filtro de Bloom e aplicar otimizações de ZOrder na tabela.
Passo 1: Criar um Cluster
O primeiro passo para começar com Índices de Filtro de Bloom é criar um cluster em seu ambiente Databricks. Observe que os Filtros de Bloom são habilitados automaticamente. No entanto, você verá o código para habilitar o filtro de bloom em tabelas delta nas seções subsequentes. Observe também os detalhes do tipo de worker e driver para este cluster, que podem ser considerados padrão. Isso pode ser dimensionado conforme necessário para melhorar e otimizar ainda mais o desempenho.
Passo 2: Criar um Notebook e Inserir Dados
Para este exemplo, crie um notebook SQL. A maioria do código e comandos será executada usando uma combinação de Scala e SQL nos blocos de código do notebook.
O código preliminar que precisará ser executado extrairá os arquivos CSV de dados do Táxi de Nova York de 2019 e o esquema dos conjuntos de dados do Databricks e os armazenará em um data frame. O conjunto de dados original contém aproximadamente 84 milhões de linhas de dados. O código adicional, que inclui explode(array((1 até 14).map(lit):_*))), duplicará os registros 13 vezes para produzir um conjunto de dados com pouco mais de 1 bilhão de linhas. Esse conjunto de dados maior será útil ao executar consultas, otimizar o desempenho e testar os tempos de consulta.
Aqui está o código Scala que você precisará executar para criar o conjunto de dados necessário:
import org.apache.spark.sql.functions._
val Data = "/databricks-datasets/nyctaxi/tripdata/yellow/yellow_tripdata_2019-*"
val SchemaDF = spark.read.format("csv").option("header", "true").option("inferSchema", "true").load("/databricks-datasets/nyctaxi/tripdata/yellow/yellow_tripdata_2019-02.csv.gz")
val df = spark.read.format("csv").option("header", "true").schema(SchemaDF.schema).load(Data)
val nyctaxiDF = df
.withColumn("VendorID", explode(array((1 until 14).map(lit): _*)))
.selectExpr(df.columns: _*)
Execute uma contagem no conjunto de dados para confirmar que você tem mais de 1 bilhão de linhas no conjunto de dados.
nyctaxiDF.count()
Neste ponto, você está pronto para persistir o conjunto de dados de preparação no formato delta em seu data lake.
Passo 3: Habilitar o Índice de Filtro de Bloom
Agora que você tem alguns dados grandes para trabalhar, é hora de habilitar o filtro de bloom no notebook. Por padrão, isso estará habilitado, no entanto, é sempre uma boa ideia habilitar manualmente para garantir que não haja erros causados mais adiante.
Aqui está o código SQL que você precisará executar para habilitar o filtro de bloom tanto para o Spark quanto para o Delta:
SET spark.databricks.io.skipping.bloomFilter.enabled = true;
SET delta.bloomFilter.enabled = true;
Passo 4: Criar Tabelas
Nesta seção, você precisará criar a tabela necessária na qual aplicará o Índice de Filtro de Bloom.
Aqui está o código SQL que você precisará executar para criar a tabela nyctaxi_bloom:
CREATE OR REPLACE TABLE nyctaxi_bloom (
VendorID int,
tpep_pickup_datetime string,
tpep_dropoff_datetime string,
passenger_count int,
trip_distance double,
RatecodeID int,
store_and_fwd_flag string,
PULocationID int,
DOLocationID int,
payment_type int,
fare_amount double,
extra double,
mta_tax double,
tip_amount double,
tolls_amount double,
improvement_surcharge double,
total_amount double,
congestion_surcharge double)
USING DELTA
Também execute o seguinte código SQL para criar a tabela delta nyctaxi_nonbloom:
CREATE TABLE nyctaxi_nonbloom
USING DELTA
LOCATION 'dbfs:/mnt/rcpdlhcore/datalakehouse/dlhcore/raw/delta/nyctaxi_nonbloom'
Passo 5: Criar um Índice de Filtro de Bloom
Agora é hora de criar o Índice de Filtro de Bloom na tabela nyctaxi_bloom.
Aqui está o código SQL que você precisará executar na tabela nyctaxi_bloom para aplicar o Índice de Filtro de Bloom na coluna tpep_dropoff_datetime:
CREATE BLOOMFILTER INDEX
ON TABLE nyctaxi_bloom
FOR COLUMNS(tpep_dropoff_datetime OPTIONS (fpp=0.1, numItems=50000000))
Execute o seguinte código para visualizar os metadados das colunas na tabela nyctaxi_bloom e observe nos detalhes da coluna tpep_dropoff_datetime que o Índice de Filtro de Bloom foi aplicado:
spark.table("nyctaxi_bloom").schema.foreach(field => println(s"${field.name}: metadata=${field.metadata}"))
Em seguida, execute o seguinte código para inserir dados na tabela nyctaxi_bloom a partir da tabela nyctaxi_nonbloom e garantir que as contagens entre a fonte e o destino correspondam:
INSERT INTO nyctaxi_bloom TABLE nyctaxi_nonbloom;
Passo 6: Otimizar a Tabela com Z-Order
O último passo do processo seria executar um comando de otimização de ZOrder em uma coluna selecionada.
Aqui está o código SQL que você precisará executar para otimizar a tabela nyctaxi_bloom e ordenar por VendorID:
SET spark.databricks.delta.optimize.maxFileSize = 1600000000;
OPTIMIZE nyctaxi_bloom
ZORDER BY VendorID
Passo 7: Verificar Melhorias de Desempenho
Execute a seguinte consulta de contagem na tabela nyctaxi_nonbloom com uma cláusula WHERE aplicada à coluna do Índice de Filtro de Bloom e observe a duração da execução da consulta. Em seguida, execute a mesma consulta na tabela nyctaxi_bloom e observe que o tempo foi reduzido, resultando em aproximadamente 50% de melhoria no desempenho.
Por fim, para a tabela nyctaxi_nonbloom, tente filtrar um valor que você sabe que não existe e observe o tempo de execução. Mais uma vez, execute a mesma consulta na tabela nyctaxi_bloom e observe que o tempo de execução é significativamente menor, resultando em aproximadamente 70% de melhoria no desempenho.
Resumo
Neste artigo, apresentamos o Índice de Filtro de Bloom e o guiamos por um exercício completo sobre como criar um Índice de Filtro de Bloom para otimizar o desempenho em uma coluna filtrada. Com base nos resultados de desempenho excepcionais, fica evidente que o Índice de Filtro de Bloom é um impulsionador promissor de desempenho para executar consultas do tipo “agulha no palheiro” que podem filtrar conjuntos de dados extremamente grandes em uma coluna específica. No geral, ele promove e suporta Data Lake houses altamente performáticas.
Artigo Atualizado em: 2021-09-14