web-dev-qa-db-fra.com

Comment lire depuis hbase en utilisant spark

Le code ci-dessous va lire dans la base de données, puis le convertir en structure json et le convertir en schémaRDD. Mais le problème est que je suis using List pour stocker la chaîne json, puis passez à javaRDD. Pour des données d’environ 100 Go, le maître sera chargé avec les données en mémoire. Quelle est la bonne façon de charger les données à partir de hbase, puis de les manipuler, puis de les convertir en JavaRDD.

package hbase_reader;


import Java.io.IOException;
import Java.io.Serializable;
import Java.util.ArrayList;
import Java.util.List;

import org.Apache.spark.api.Java.JavaPairRDD;
import org.Apache.spark.api.Java.JavaRDD;
import org.Apache.spark.api.Java.JavaSparkContext;
import org.Apache.spark.rdd.RDD;
import org.Apache.spark.sql.api.Java.JavaSQLContext;
import org.Apache.spark.sql.api.Java.JavaSchemaRDD;
import org.Apache.commons.cli.ParseException;
import org.Apache.hadoop.hbase.HBaseConfiguration;
import org.Apache.hadoop.hbase.KeyValue;
import org.Apache.hadoop.hbase.client.HTable;
import org.Apache.hadoop.hbase.client.Result;
import org.Apache.hadoop.hbase.client.ResultScanner;
import org.Apache.hadoop.hbase.client.Scan;
import org.Apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.Apache.hadoop.hbase.mapreduce.TableInputFormat;
import org.Apache.hadoop.hbase.util.Bytes;
import org.Apache.hadoop.io.Text;
import org.Apache.spark.SparkConf;

import scala.Function1;
import scala.Tuple2;
import scala.runtime.AbstractFunction1;

import com.google.common.collect.Lists;

public class hbase_reader {

    public static void main(String[] args) throws IOException, ParseException {

        List<String> jars = Lists.newArrayList("");

        SparkConf spconf = new SparkConf();
        spconf.setMaster("local[2]");
        spconf.setAppName("HBase");
        //spconf.setSparkHome("/opt/human/opt/spark-0.9.0-hdp1");
        spconf.setJars(jars.toArray(new String[jars.size()]));
        JavaSparkContext sc = new JavaSparkContext(spconf);
        //spconf.set("spark.executor.memory", "1g");

        JavaSQLContext jsql = new JavaSQLContext(sc);


        HBaseConfiguration conf = new HBaseConfiguration();
        String tableName = "HBase.CounData1_Raw_Min1";
        HTable table = new HTable(conf,tableName);
        try {

            ResultScanner scanner = table.getScanner(new Scan());
            List<String> jsonList = new ArrayList<String>();

            String json = null;

            for(Result rowResult:scanner) {
                json = "";
                String rowKey  = Bytes.toString(rowResult.getRow());
                for(byte[] s1:rowResult.getMap().keySet()) {
                    String s1_str = Bytes.toString(s1);

                    String jsonSame = "";
                    for(byte[] s2:rowResult.getMap().get(s1).keySet()) {
                        String s2_str = Bytes.toString(s2);
                        for(long s3:rowResult.getMap().get(s1).get(s2).keySet()) {
                            String s3_str = new String(rowResult.getMap().get(s1).get(s2).get(s3));
                            jsonSame += "\""+s2_str+"\":"+s3_str+",";
                        }
                    }
                    jsonSame = jsonSame.substring(0,jsonSame.length()-1);
                    json += "\""+s1_str+"\""+":{"+jsonSame+"}"+",";
                }
                json = json.substring(0,json.length()-1);
                json = "{\"RowKey\":\""+rowKey+"\","+json+"}";
                jsonList.add(json);
            }

            JavaRDD<String> jsonRDD = sc.parallelize(jsonList);

            JavaSchemaRDD schemaRDD = jsql.jsonRDD(jsonRDD);




            System.out.println(schemaRDD.take(2));

        } finally {
            table.close();
        }

    }

}
44
madan ram

Exemple de base pour lire les données HBase en utilisant Spark (Scala), vous pouvez également écrire ceci Java:

import org.Apache.hadoop.hbase.client.{HBaseAdmin, Result}
import org.Apache.hadoop.hbase.{ HBaseConfiguration, HTableDescriptor }
import org.Apache.hadoop.hbase.mapreduce.TableInputFormat
import org.Apache.hadoop.hbase.io.ImmutableBytesWritable

import org.Apache.spark._

object HBaseRead {
  def main(args: Array[String]) {
    val sparkConf = new SparkConf().setAppName("HBaseRead").setMaster("local[2]")
    val sc = new SparkContext(sparkConf)
    val conf = HBaseConfiguration.create()
    val tableName = "table1"

    System.setProperty("user.name", "hdfs")
    System.setProperty("HADOOP_USER_NAME", "hdfs")
    conf.set("hbase.master", "localhost:60000")
    conf.setInt("timeout", 120000)
    conf.set("hbase.zookeeper.quorum", "localhost")
    conf.set("zookeeper.znode.parent", "/hbase-unsecure")
    conf.set(TableInputFormat.INPUT_TABLE, tableName)

    val admin = new HBaseAdmin(conf)
    if (!admin.isTableAvailable(tableName)) {
      val tableDesc = new HTableDescriptor(tableName)
      admin.createTable(tableDesc)
    }

    val hBaseRDD = sc.newAPIHadoopRDD(conf, classOf[TableInputFormat], classOf[ImmutableBytesWritable], classOf[Result])
    println("Number of Records found : " + hBaseRDD.count())
    sc.stop()
  }
}

MISE À JOUR -2016

À partir de Spark 1.0.x +, vous pouvez maintenant utiliser Spark-HBase Connector également:

Dépendance Maven à inclure:

<dependency>
  <groupId>it.nerdammer.bigdata</groupId>
  <artifactId>spark-hbase-connector_2.10</artifactId>
  <version>1.0.3</version> // Version can be changed as per your Spark version, I am using Spark 1.6.x
</dependency>

Et trouvez un exemple de code ci-dessous pour le même:

import org.Apache.spark._
import it.nerdammer.spark.hbase._

object HBaseRead extends App {
    val sparkConf = new SparkConf().setAppName("Spark-HBase").setMaster("local[4]")
    sparkConf.set("spark.hbase.Host", "<YourHostnameOnly>") //e.g. 192.168.1.1 or localhost or your hostanme
    val sc = new SparkContext(sparkConf)

    // For Example If you have an HBase Table as 'Document' with ColumnFamily 'SMPL' and qualifier as 'DocID, Title' then:

    val docRdd = sc.hbaseTable[(Option[String], Option[String])]("Document")
    .select("DocID", "Title").inColumnFamily("SMPL")

    println("Number of Records found : " + docRdd .count())
}

MISE À JOUR - 2017

À partir de Spark 1.6.x +, vous pouvez maintenant utiliser le connecteur SHC également (utilisateurs de Hortonworks ou HDP):

Dépendance Maven à inclure:

    <dependency>
        <groupId>com.hortonworks</groupId>
        <artifactId>shc</artifactId>
        <version>1.0.0-2.0-s_2.11</version> // Version depends on the Spark version and is supported upto Spark 2.x
    </dependency>

Le principal avantage de l'utilisation de ce connecteur est qu'il offre une flexibilité dans la définition du schéma et ne nécessite pas de paramètres Hardcoded, comme dans nerdammer/spark-hbase-connector. N'oubliez pas non plus qu'il prend en charge Spark 2.x), de sorte que ce connecteur est assez flexible et offre une prise en charge de bout en bout des problèmes et des relations publiques.

Recherchez le chemin de référentiel ci-dessous pour le dernier fichier Lisezmoi et les derniers exemples:

Hortonworks Spark HBase Connector

Vous pouvez également convertir ce RDD en DataFrames et exécuter du SQL dessus. Vous pouvez également mapper ces ensembles de données ou DataFrames à la classe définie par l'utilisateur Java Pojo's ou Case. Cela fonctionne très bien.

Veuillez commenter ci-dessous si vous avez besoin d'autre chose.

50
Murtaza Kanchwala

Je préfère lire à partir de hbase et faire la manipulation json tout en étincelle.
Spark fournit la fonction JavaSparkContext.newAPIado_RDD permettant de lire des données à partir du stockage hadoop, y compris HBase. Vous devrez fournir la configuration HBase, le nom de la table et l'analyse dans le paramètre de configuration et le format d'entrée de la table, ainsi que sa valeur-clé.

Vous pouvez utiliser format d'entrée de table class et son paramètre de travail pour fournir le nom de la table et la configuration de l'analyse.

exemple:

conf.set(TableInputFormat.INPUT_TABLE, "tablename");
JavaPairRDD<ImmutableBytesWritable, Result> data = 
jsc.newAPIHadoopRDD(conf, TableInputFormat.class,ImmutableBytesWritable.class, Result.class);

alors vous pouvez faire la manipulation json dans spark. Puisque spark peut effectuer un recalcul lorsque la mémoire est pleine, il ne chargera que les données nécessaires à la partie de recalcul (cmiiw), de sorte que vous n’aurez plus à vous soucier de la taille des données.

10
Averman

juste pour ajouter un commentaire sur la façon d'ajouter l'analyse:

TableInputFormat a les attributs suivants:

  1. SCAN_ROW_START
  2. SCAN_ROW_STOP
conf.set(TableInputFormat.SCAN_ROW_START, "startrowkey");
conf.set(TableInputFormat.SCAN_ROW_STOP, "stoprowkey");
7
Zhang Kan

Comme la question n’est pas nouvelle, il existe pour le moment quelques autres alternatives:

Je ne connais pas grand chose au sujet du premier projet, mais on dirait qu’il ne supporte pas Spark 2.x. Cependant, il possède un support riche au niveau RDD pour Spark 1.6.x.

Spark-on-HBase, d’autre part, a des branches pour Spark 2.0 et les prochains Spark 2.1. Ce projet est très prometteur car il est axé sur Dataset/DataFrame API. Sous le capot, il implémente le standard Spark API Datasource et exploite le Spark Moteur Catalyst pour l’optimisation des requêtes. La demande des développeurs ici qu’il est capable d’élaguer les partitions, d’élaguer les colonnes, de réduire les prédicats et d’atteindre la localité des données.

Un exemple simple, qui utilise le com.hortonworks:shc:1.0.0-2.0-s_2.11 artefact de ce repo et Spark 2.0.2, est présenté ensuite:

case class Record(col0: Int, col1: Int, col2: Boolean)

val spark = SparkSession
  .builder()
  .appName("Spark HBase Example")
  .master("local[4]")
  .getOrCreate()

def catalog =
  s"""{
      |"table":{"namespace":"default", "name":"table1"},
      |"rowkey":"key",
      |"columns":{
      |"col0":{"cf":"rowkey", "col":"key", "type":"int"},
      |"col1":{"cf":"cf1", "col":"col1", "type":"int"},
      |"col2":{"cf":"cf2", "col":"col2", "type":"boolean"}
      |}
      |}""".stripMargin

val artificialData = (0 to 100).map(number => Record(number, number, number % 2 == 0))

// write
spark
  .createDataFrame(artificialData)
  .write
  .option(HBaseTableCatalog.tableCatalog, catalog)
  .option(HBaseTableCatalog.newTable, "5")
  .format("org.Apache.spark.sql.execution.datasources.hbase")
  .save()

// read
val df = spark
  .read
  .option(HBaseTableCatalog.tableCatalog, catalog)
  .format("org.Apache.spark.sql.execution.datasources.hbase")
  .load()

df.count()
7
Anton Okolnychyi