Data skipping para Spark SQL

O data skipping pode impulsionar significativamente o desempenho de consultas SQL ignorando arquivos ou objetos de dados irrelevantes com base em um resumo dos metadados associados a cada objeto.

O data skipping usa a biblioteca Xskipper de software livre para criar, gerenciar e implementar índices de data skipping com o Apache Spark. Consulte Xskipper-Um Extensible Data Skipping Framework.

Para obter mais detalhes sobre como trabalhar com o Xskipper, consulte:

Além dos recursos de software livre no Xskipper, os recursos a seguir também estão disponíveis:

Data skipping geoespacial

Também é possível usar o salto de dados ao consultar conjuntos de dados geoespaciais usando funções geoespaciais da biblioteca espaço-temporal.

  • Para se beneficiar do data skipping em conjuntos de dados com colunas de latitude e longitude, é possível coletar os índices mín-máx nas colunas de latitude e longitude.
  • O salto de dados pode ser usado em conjuntos de dados com uma coluna de geometria (uma coluna UDT) usando um plug-in Xskipper integrado.

As seções a seguir mostram como trabalhar com o plug-in geoespacial.

Configurando o plug-in geoespacial

Para usar um plug-in, carregue as implementações relevantes usando o módulo de registro:

  • Para Scala:

    import com.ibm.xskipper.stmetaindex.filter.STMetaDataFilterFactory
    import com.ibm.xskipper.stmetaindex.index.STIndexFactory
    import com.ibm.xskipper.stmetaindex.translation.parquet.{STParquetMetaDataTranslator, STParquetMetadatastoreClauseTranslator}
    import io.xskipper._
    
    Registration.addIndexFactory(STIndexFactory)
    Registration.addMetadataFilterFactory(STMetaDataFilterFactory)
    Registration.addClauseTranslator(STParquetMetadatastoreClauseTranslator)
    Registration.addMetaDataTranslator(STParquetMetaDataTranslator)
    
  • Para Python:

    from xskipper import Xskipper
    from xskipper import Registration
    
    Registration.addMetadataFilterFactory(spark, 'com.ibm.xskipper.stmetaindex.filter.STMetaDataFilterFactory')
    Registration.addIndexFactory(spark, 'com.ibm.xskipper.stmetaindex.index.STIndexFactory')
    Registration.addMetaDataTranslator(spark, 'com.ibm.xskipper.stmetaindex.translation.parquet.STParquetMetaDataTranslator')
    Registration.addClauseTranslator(spark, 'com.ibm.xskipper.stmetaindex.translation.parquet.STParquetMetadatastoreClauseTranslator')
    

Construção de índice

Para construir um índice, é possível usar a API addCustomIndex:

  • Para Scala:

    import com.ibm.xskipper.stmetaindex.implicits._
    
    // index the dataset
    val xskipper = new Xskipper(spark, dataset_path)
    
    xskipper
      .indexBuilder()
      // using the implicit method defined in the plugin implicits
      .addSTBoundingBoxLocationIndex("location")
      // equivalent
      //.addCustomIndex(STBoundingBoxLocationIndex("location"))
      .build(reader).show(false)
    
  • Para Python:

    xskipper = Xskipper(spark, dataset_path)
    
    # adding the index using the custom index API
    xskipper.indexBuilder() \
            .addCustomIndex("com.ibm.xskipper.stmetaindex.index.STBoundingBoxLocationIndex", ['location'], dict()) \
            .build(reader) \
            .show(10, False)
    

Funções suportadas do

A lista de funções geoespaciais suportadas inclui o seguinte:

  • ST_Distance
  • ST_Intersects
  • ST_Contains
  • ST_Equals
  • ST_Crosses
  • ST_Touches
  • ST_Within
  • ST_Overlaps
  • ST_EnvelopesIntersect
  • ST_IntersectsInterior

Criptografia de índices

Se um armazenamento de metadados Parquet for usado, opcionalmente, os metadados poderão ser criptografados usando Parquet Modular Encryption (PME). Isso é feito armazenando os próprios metadados como um conjunto de dados do Parquet e, sendo assim, o PME pode ser usado para criptografá-los. Esse recurso se aplica a todos os formatos de entrada, por exemplo, um conjunto de dados armazenado em formato CSV pode ter seus metadados criptografados usando o PME.

Na seção a seguir, salvo se especificado de outra forma, as referências a rodapés, colunas etc., serão a respeito dos objetos de metadados, e não dos objetos no conjunto de dados indexado.

A criptografia de índice é modular e granular conforme mostrado a seguir:

  • Cada índice pode ser criptografado (com uma granularidade de chave por índice) ou deixado como texto sem formatação
  • Coluna de rodapé + nome de objeto:
    • A coluna de rodapé do objeto de metadados, que é um arquivo do Parquet em si, contém, entre outras coisas:
      • Esquema do objeto de metadados, que revela os tipos, parâmetros e nomes de coluna para todos os índices coletados. Por exemplo, você pode aprender que um BloomFilter é definido na coluna city com uma probabilidade de falso-positivo igual a 0.1.
      • Caminho completo para o conjunto de dados original ou o nome da tabela em caso de uma tabela do metastore Hive.
    • A coluna de nome de objeto armazena os nomes de todos os objetos indexados.
  • A coluna de rodapé + metadados pode ser:
    • Criptografada usando a mesma chave. Este é o padrão. Nesse caso, a configuração do rodapé de texto sem formatação para os objetos do Parquet contendo os metadados é para o modo de rodapé criptografado e a coluna de nome de objeto é criptografada usando a chave selecionada.

    • Texto sem formatação. Nesse caso, os objetos do Parquet contendo os metadados estão no modo de rodapé de texto sem formatação e a coluna de nome de objeto não é criptografada.

      Se pelo menos um índice for marcado como criptografado, uma chave de rodapé deverá ser configurada, independentemente de o modo de rodapé de texto sem formatação estar ou não ativado. Se o rodapé de texto sem formatação estiver configurado, a chave de rodapé será usada para proteção contra violação. Observe que, nesse caso, a coluna de nome de objeto não tem proteção contra violação.

      Se uma chave de rodapé estiver configurada, pelo menos um índice deverá ser criptografado.

Antes de usar a criptografia de índice, deve-se verificar a documentação no PME e certificar-se de que você esteja familiarizado com os conceitos.

Ao usar a criptografia de índice, sempre que um key é configurado em qualquer API Xskipper, o rótulo é sempre NEVER the key itself.

Para usar criptografia de índice:

  1. Siga todas as etapas para assegurar que o PME esteja ativado. Consulte PME..

  2. Execute todas as configurações do PME regular, incluindo configurações de Gerenciamento de chaves.

  3. Crie metadados criptografados para um conjunto de dados:

    1. Siga o fluxo regular para criar metadados.
    2. Configure uma chave de rodapé. Se quiser configurar um rodapé de texto simples + coluna nome de objeto, configure io.xskipper.parquet.encryption.plaintext.footer para true (Veja amostras abaixo).
    3. Em IndexBuilder, para cada índice que deseja criptografar, inclua o rótulo da chave para usar para esse índice.

    Para usar metadados durante o tempo de consulta ou para atualizar os metadados existentes, nenhuma configuração é necessária além da configuração de PME regular, exigida para garantir que as chaves estejam acessíveis (literalmente a mesma configuração necessária para ler um conjunto de dados criptografados).

Amostras

As amostras a seguir exibem a criação de metadados usando uma chave denominada k1 como uma chave de rodapé + nome de objeto e uma chave denominada k2 como uma chave para criptografar um MinMax para temp, enquanto também cria um ValueList para city, que é deixado em texto simples.

  • Para Scala:

    // index the dataset
    val xskipper = new Xskipper(spark, dataset_path)
    // Configuring the JVM wide parameters
    val jvmComf = Map(
      "io.xskipper.parquet.mdlocation" -> md_base_location,
      "io.xskipper.parquet.mdlocation.type" -> "EXPLICIT_BASE_PATH_LOCATION")
    Xskipper.setConf(jvmConf)
    // set the footer key
    val conf = Map(
      "io.xskipper.parquet.encryption.footer.key" -> "k1")
    xskipper.setConf(conf)
    xskipper
      .indexBuilder()
      // Add an encrypted MinMax index for temp
      .addMinMaxIndex("temp", "k2")
      // Add a plaintext ValueList index for city
      .addValueListIndex("city")
      .build(reader).show(false)
    
  • Para Python

    xskipper = Xskipper(spark, dataset_path)
    # Add JVM Wide configuration
    jvmConf = dict([
    ("io.xskipper.parquet.mdlocation", md_base_location),
    ("io.xskipper.parquet.mdlocation.type", "EXPLICIT_BASE_PATH_LOCATION")])
    Xskipper.setConf(spark, jvmConf)
    # configure footer key
    conf = dict([("io.xskipper.parquet.encryption.footer.key", "k1")])
    xskipper.setConf(conf)
    # adding the indexes
    xskipper.indexBuilder() \
            .addMinMaxIndex("temp", "k1") \
            .addValueListIndex("city") \
            .build(reader) \
            .show(10, False)
    

Se quiser que o rodapé + nome do objeto sejam deixados no modo de texto sem formatação (conforme mencionado acima), será necessário incluir o parâmetro de configuração:

  • Para Scala:

    // index the dataset
    val xskipper = new Xskipper(spark, dataset_path)
    // Configuring the JVM wide parameters
    val jvmComf = Map(
      "io.xskipper.parquet.mdlocation" -> md_base_location,
      "io.xskipper.parquet.mdlocation.type" -> "EXPLICIT_BASE_PATH_LOCATION")
    Xskipper.setConf(jvmConf)
    // set the footer key
    val conf = Map(
      "io.xskipper.parquet.encryption.footer.key" -> "k1",
      "io.xskipper.parquet.encryption.plaintext.footer" -> "true")
    xskipper.setConf(conf)
    xskipper
      .indexBuilder()
      // Add an encrypted MinMax index for temp
      .addMinMaxIndex("temp", "k2")
      // Add a plaintext ValueList index for city
      .addValueListIndex("city")
      .build(reader).show(false)
    
  • Para Python

    xskipper = Xskipper(spark, dataset_path)
    # Add JVM Wide configuration
    jvmConf = dict([
    ("io.xskipper.parquet.mdlocation", md_base_location),
    ("io.xskipper.parquet.mdlocation.type", "EXPLICIT_BASE_PATH_LOCATION")])
    Xskipper.setConf(spark, jvmConf)
    # configure footer key
    conf = dict([("io.xskipper.parquet.encryption.footer.key", "k1"),
    ("io.xskipper.parquet.encryption.plaintext.footer", "true")])
    xskipper.setConf(conf)
    # adding the indexes
    xskipper.indexBuilder() \
            .addMinMaxIndex("temp", "k1") \
            .addValueListIndex("city") \
            .build(reader) \
            .show(10, False)
    

Suporte para metadados mais antigos

A Xskipper suporta os metadados mais antigos criados facilmente pelo MetaIndexManager. Os metadados mais antigos podem ser usados para skipping, já que as atualizações nos metadados da Xskipper são realizadas automaticamente pela operação de atualização seguinte.

Se você vir a DEPRECATED_SUPPORTED na frente de um índice ao listar índices ou executar uma operação describeIndex, a versão de metadados será descontinuada, mas ainda será suportada e a opção de ignorar funcionará. A próxima operação de atualização irá atualizar os metadados automaticamente.