Usando o Conector HDFS com o Spark

Introdução

Este artigo fornece um passo a passo que ilustra como usar o conector HDFS (Hadoop Distributed File System) com o framework do aplicativo Spark. Para o passo a passo, usamos o sistema operacional Oracle Linux 7.4 e executamos o Spark como um elemento independente em um único computador.

Pré-requisitos

Estes são os pré-requisitos para completar o passo a passo:

  • Você deve ter permissão para criar uma instância de computação. Para obter orientação, consulte Criando uma Instância.
  • Você deverá conseguir se conectar com a instância do serviço iniciado. Para obter orientação, consulte Conexão com uma Instância.
  • É necessário ter o OCID, impressão digital e chave privada apropriados para o usuário do IAM (Identity and Access Management) que você usará para interagir com um Object Storage. Para obter orientação, consulte Configuração e Pré-requisitos.
  • Você deve ter um bucket do serviço Object Storage ao qual possa se conectar.
  • O usuário do IAM deve poder ler e gravar nesse bucket usando a Console.

Usando o Spark

Instalar Spark e Dependências

Observação

Para a finalidade desse exemplo, instale o Spark no diretório home do usuário atual. Observe que, para cenários de produção, não é necessário fazer isso.
Observação

As Versões 2.7.7.0 e mais recentes não instalam mais todas as dependências de terceiros necessárias. As dependências de terceiros necessárias são agrupadas na pasta third-party/lib no arquivo zip e devem ser instaladas manualmente.
  1. Crie uma instância do seu serviço Compute. Para obter orientação, consulte Criando uma Instância.
  2. Certifique-se de que a sua instância de serviço tenha um endereço IP público para que você possa se conectar usando uma conexão SSH (Secure Shell). Para obter orientação, consulte Conexão com uma Instância.
  3. Conecte-se com a sua instância de serviço usando uma conexão SSH.
  4. Instale o Spark e suas dependências, o Java e o Scala, usando os exemplos de código a seguir.
# We'll use wget to download some of the artifacts that need to be installed
sudo yum install wget
 
# First install Java
sudo yum install java-1.8.0-openjdk.x86_64
export JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk
# Should be something like: OpenJDK Runtime Environment (build 1.8.0_161-b14)
java -version
 
# Then install Scala
wget https://downloads.lightbend.com/scala/2.12.4/scala-2.12.4.rpm
sudo yum install scala-2.12.4.rpm
# Should be something like: Scala code runner version 2.12.4 -- Copyright 2002-2017, LAMP/EPFL and Lightbend, Inc.
scala -version
 
# Then download Spark
wget https://archive.apache.org/dist/spark/spark-2.2.1/spark-2.2.1-bin-hadoop2.7.tgz
tar xvf spark-2.2.1-bin-hadoop2.7.tgz
export SPARK_HOME=$HOME/spark-2.2.1-bin-hadoop2.7
export PATH=$PATH:$SPARK_HOME/bin
 
# Start a Spark master
cd $SPARK_HOME
./sbin/start-master.sh

Download do Conector HDFS e Criação de Arquivos de Configuração

Observação

Para a finalidade deste exemplo, coloque o JAR e os arquivos de chave no diretório home do usuário atual. Para cenários de produção, você incluiria esses arquivos em um local comum que impõe as permissões apropriadas (ou seja, legíveis pelo usuário para o qual o Spark e o Hive estão sendo executados).

Faça o download do Conector HDFS para a instância de serviço e adicione os arquivos de configuração relevantes usando o exemplo de código a seguir. Para obter informações adicionais, consulte Conector HDFS para o Serviço Object Storage.

wget https://github.com/oracle/oci-hdfs-connector/releases/download/v2.9.2.1/oci-hdfs.zip
unzip oci-hdfs.zip -d oci-hdfs
 
cd $HOME
mkdir .oci
# Create or copy your API key into the $HOME/.oci directory
 
cd $SPARK_HOME/conf
# Create a core-site.xml (e.g. by transferring one you have, using vi etc.). Consult
# https://docs.oracle.com/iaas/Content/API/SDKDocs/hdfsconnector.htm#Properties
# for what this should look like
 
# Create a spark-defaults.conf file from the template
cp spark-defaults.conf.template spark-defaults.conf

No arquivo spark-defaults.conf, adicione o seguinte ao final:

spark.sql.hive.metastore.sharedPrefixes= shaded.oracle,com.oracle.bmc

Preparar os Dados

Para testar dados, usaremos o conjunto de dados MovieLens.

  1. Faça o download do conjunto de dados mais recente em https://grouplens.org/datasets/movielens/latest/. Certifique-se de fazer o download do conjunto de dados "Pequeno".
  2. Descompacte o arquivo zip baixado.
  3. Faça upload do arquivo movies.csv para seu bucket do serviço Object Storage.

Testar Usando o Spark Shell

Com os dados prontos, agora podemos iniciar o Spark shell e testá-lo usando um exemplo de comando:

cd $SPARK_HOME
./bin/spark-shell
 
scala> sc.wholeTextFiles("oci://PipedUploadTest@sampletenancy/")
java.io.IOException: No FileSystem for scheme: oci

Você recebe um erro neste ponto porque o esquema do sistema de arquivos//oci não está disponível. Precisamos fazer referência ao arquivo JAR antes de iniciar o shell Spark. Este é um exemplo de como fazer isso:

./bin/spark-shell --jars $HOME/oci-hdfs/lib/oci-hdfs-full-1.2.7.jar --driver-class-path $HOME/oci-hdfs/lib/oci-hdfs-full-1.2.7.jar
 
scala> sc.wholeTextFiles("oci://PipedUploadTest@sampletenancy/")
res0: org.apache.spark.rdd.RDD[(String, String)] = oci://PipedUploadTest@sampletenancy/ MapPartitionsRDD[1] at wholeTextFiles at <console>:25
 
scala> sc.textFile("oci://PipedUploadTest@sampletenancy/movies.csv").take(20).foreach(println)
movieId,title,genres
1,Toy Story (1995),Adventure|Animation|Children|Comedy|Fantasy
2,Jumanji (1995),Adventure|Children|Fantasy
3,Grumpier Old Men (1995),Comedy|Romance
4,Waiting to Exhale (1995),Comedy|Drama|Romance
5,Father of the Bride Part II (1995),Comedy
6,Heat (1995),Action|Crime|Thriller
7,Sabrina (1995),Comedy|Romance
8,Tom and Huck (1995),Adventure|Children
9,Sudden Death (1995),Action
10,GoldenEye (1995),Action|Adventure|Thriller
11,"American President, The (1995)",Comedy|Drama|Romance
12,Dracula: Dead and Loving It (1995),Comedy|Horror
13,Balto (1995),Adventure|Animation|Children
14,Nixon (1995),Drama
15,Cutthroat Island (1995),Action|Adventure|Romance
16,Casino (1995),Crime|Drama
17,Sense and Sensibility (1995),Drama|Romance
18,Four Rooms (1995),Comedy
19,Ace Ventura: When Nature Calls (1995),Comedy

O comando foi bem-sucedido para que possamos estabelecer conexão com o Object Storage. Observe que se não quiser especificar o argumento --jars a cada vez que o comando for executado, você poderá copiar o arquivo JAR oci-hdfs-full para o diretório $SPARK_HOME/jars.

Iniciar o Servidor Spark Thrift

Inicie o Servidor Spark Thrift na porta 10015 e use a ferramenta de linha de comando Beeline para estabelecer uma conexão JDBC e executar uma consulta básica, conforme mostrado aqui:

cd $SPARK_HOME
./sbin/start-thriftserver.sh --hiveconf hive.server2.thrift.port=10015

Assim que o servidor Spark estiver em execução, poderemos iniciar o Beeline, conforme mostrado aqui:

cd $SPARK_HOME
./bin/beeline
Beeline version 1.2.1.spark2 by Apache Hive
beeline>

Em seguida, conecte-se com o servidor, como mostrado aqui:

Observação

Para a finalidade deste exemplo, não configuramos qualquer tipo de segurança. Portanto, quaisquer nomes de usuários e senhas serão aceitos. Para cenários de produção, você não deve fazer isso.
beeline> !connect jdbc:hive2://localhost:10015 testuser testpass
Connecting to jdbc:hive2://localhost:10015
log4j:WARN No appenders could be found for logger (org.apache.hive.jdbc.Utils).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Connected to: Spark SQL (version 2.2.1)
Driver: Hive JDBC (version 1.2.1.spark2)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://localhost:10015>

Se verificarmos agora quais tabelas existem, veremos o seguinte:

0: jdbc:hive2://localhost:10015> show tables;
+-----------+------------+--------------+--+
| database  | tableName  | isTemporary  |
+-----------+------------+--------------+--+
+-----------+------------+--------------+--+
No rows selected (0.724 seconds)

No momento, não existem tabelas; no entanto, podemos criar uma tabela e vinculá-la ao arquivo movies.csv que baixamos por download e colocamos no bucket do sistema Object Storage, como é mostrado aqui:

0: jdbc:hive2://localhost:10015> create table test_table (movieId integer, title string, genres string) using csv options (path "oci://myBucket@myTenant/movies.csv", header "true", delimiter ",");
 
0: jdbc:hive2://localhost:10015> describe formatted test_table;
+-------------------------------+------------------------------------------------------------+----------+--+
|           col_name            |                         data_type                          | comment  |
+-------------------------------+------------------------------------------------------------+----------+--+
| movieId                       | int                                                        | NULL     |
| title                         | string                                                     | NULL     |
| genres                        | string                                                     | NULL     |
|                               |                                                            |          |
| # Detailed Table Information  |                                                            |          |
| Database                      | default                                                    |          |
| Table                         | test_table                                                 |          |
| Owner                         | opc                                                        |          |
| Created                       | Thu Mar 01 20:45:18 GMT 2018                               |          |
| Last Access                   | Thu Jan 01 00:00:00 GMT 1970                               |          |
| Type                          | EXTERNAL                                                   |          |
| Provider                      | csv                                                        |          |
| Table Properties              | [transient_lastDdlTime=1519937118]                         |          |
| Location                      | oci://PipedUploadTest@sampletenancy/movies.csv    |          |
| Serde Library                 | org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe         |          |
| InputFormat                   | org.apache.hadoop.mapred.SequenceFileInputFormat           |          |
| OutputFormat                  | org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat  |          |
| Storage Properties            | [delimiter=,, header=true, serialization.format=1]         |          |
+-------------------------------+------------------------------------------------------------+----------+--+

Observe que a tabela armazena os dados externamente no serviço Object Storage, e os dados podem ser acessados com o Conector HDFS (o esquema do sistema de arquivos oci://). Agora que temos uma tabela, podemos consultá-la:

0: jdbc:hive2://localhost:10015> select * from test_table limit 10;
+----------+-------------------------------------+----------------------------------------------+--+
| movieId  |                title                |                    genres                    |
+----------+-------------------------------------+----------------------------------------------+--+
| 1        | Toy Story (1995)                    | Adventure|Animation|Children|Comedy|Fantasy  |
| 2        | Jumanji (1995)                      | Adventure|Children|Fantasy                   |
| 3        | Grumpier Old Men (1995)             | Comedy|Romance                               |
| 4        | Waiting to Exhale (1995)            | Comedy|Drama|Romance                         |
| 5        | Father of the Bride Part II (1995)  | Comedy                                       |
| 6        | Heat (1995)                         | Action|Crime|Thriller                        |
| 7        | Sabrina (1995)                      | Comedy|Romance                               |
| 8        | Tom and Huck (1995)                 | Adventure|Children                           |
| 9        | Sudden Death (1995)                 | Action                                       |
| 10       | GoldenEye (1995)                    | Action|Adventure|Thriller                    |
+----------+-------------------------------------+----------------------------------------------+--+