Session des Journées SQL Server 2014 - David Joubert
---
Intégré par défaut sur la plateforme Hadoop, Hive est lien manquant entre SQL et Big Data dans l’éco-système.
Langage, stockage, exécution, cet entrepôt de données Big Data s’est toujours inspiré de ses équivalents relationnels dans son évolution.
Cette session sera l’occasion de faire le tour de la technologie et de démontrer cette convergence.
2. #JSS2014
Les journées
SQL Server 2014
Un événement organisé par GUSS
Hive ou la convergence entre
datawarehouse et Big Data
Julien Buret
David Joubert
5. #JSS2014
On va parler de
• Un peu d’Hadoop
• Beaucoup de Hive
– Historique
– Moteurs d’exécution
– Stockage
– Optimisation de requêtes
• Pas mal de démos
On ne vas pas en parler
• De tout le reste
Autres sessions Big Data
• APS, l’appliance Big Data, Lundi
à 15h30
• Big Data et Real Time, Mardi à
14h
Agenda
6. #JSS2014
• Framework aidant au développement
d’application distribué et scalable
• Projet débuté en 2005
– Basé sur 2 papiers de Google (GFS & MapReduce)
• Projet Apache depuis 2009
Hadoop : un peu d’histoire
7. #JSS2014
Map Reduce
class CompositeKeyWritableRSJ implements Writable,
WritableComparable<CompositeKeyWritableRSJ> {
// Data members
private String joinKey;// EmployeeID
private int sourceIndex;// 1=Employee data; 2=Salary (current) data; 3=Salary historical data
public CompositeKeyWritableRSJ() {
}
public CompositeKeyWritableRSJ(String joinKey, int sourceIndex) {
this.joinKey = joinKey;
this.sourceIndex = sourceIndex;
}
@Override
public String toString() {
return (new StringBuilder().append(joinKey).append("t").append(sourceIndex)).toString();
}
public void readFields(DataInput dataInput) throws IOException {
joinKey = WritableUtils.readString(dataInput);
sourceIndex = WritableUtils.readVInt(dataInput);
}
public void write(DataOutput dataOutput) throws IOException {
WritableUtils.writeString(dataOutput, joinKey);
WritableUtils.writeVInt(dataOutput, sourceIndex);
}
public int compareTo(CompositeKeyWritableRSJ objKeyPair) {
int result = joinKey.compareTo(objKeyPair.joinKey);
if (0 == result) {
result = Double.compare(sourceIndex, objKeyPair.sourceIndex);
}
return result;
}
public String getjoinKey() {
return joinKey;
}
public void setjoinKey(String joinKey) {
this.joinKey = joinKey;
}
public int getsourceIndex() {
return sourceIndex;
}
public void setsourceIndex(int sourceIndex) {
this.sourceIndex = sourceIndex;
}
}
public class MapperRSJ extends
Mapper<LongWritable, Text, CompositeKeyWritableRSJ, Text> {
CompositeKeyWritableRSJ ckwKey = new CompositeKeyWritableRSJ();
Text txtValue = new Text("");
int intSrcIndex = 0;
StringBuilder strMapValueBuilder = new StringBuilder("");
List<Integer> lstRequiredAttribList = new ArrayList<Integer>();
@Override
protected void setup(Context context) throws IOException,
InterruptedException {
// {{
// Get the source index; (employee = 1, salary = 2)
// Added as configuration in driver
FileSplit fsFileSplit = (FileSplit) context.getInputSplit();
intSrcIndex = Integer.parseInt(context.getConfiguration().get(
fsFileSplit.getPath().getName()));
// }}
// {{
// Initialize the list of fields to emit as output based on
// intSrcIndex (1=employee, 2=current salary, 3=historical salary)
if (intSrcIndex == 1) // employee
{
lstRequiredAttribList.add(2); // FName
lstRequiredAttribList.add(3); // LName
lstRequiredAttribList.add(4); // Gender
lstRequiredAttribList.add(6); // DeptNo
} else // salary
{
lstRequiredAttribList.add(1); // Salary
lstRequiredAttribList.add(3); // Effective-to-date (Value of
// 9999-01-01 indicates current
// salary)
}
// }}
}
public class ReducerRSJ extends
Reducer<CompositeKeyWritableRSJ, Text, NullWritable, Text> {
StringBuilder reduceValueBuilder = new StringBuilder("");
NullWritable nullWritableKey = NullWritable.get();
Text reduceOutputValue = new Text("");
String strSeparator = ",";
private MapFile.Reader deptMapReader = null;
Text txtMapFileLookupKey = new Text("");
Text txtMapFileLookupValue = new Text("");
@Override
protected void setup(Context context) throws IOException,
InterruptedException {
// {{
// Get side data from the distributed cache
Path[] cacheFilesLocal = DistributedCache.getLocalCacheArchives(context
.getConfiguration());
for (Path eachPath : cacheFilesLocal) {
if (eachPath.getName().toString().trim()
.equals("departments_map.tar.gz")) {
URI uriUncompressedFile = new File(eachPath.toString()
+ "/departments_map").toURI();
initializeDepartmentsMap(uriUncompressedFile, context);
}
}
// }}
}
8. #JSS2014
• Projet interne Facebook lancé en
2007
• Opensourcé en 2009
• Aujourd’hui le standard de fait
pour exécuter du SQL sur Hadoop
• Disponible sur toute les
distributions populaires
Hive : un peu d’histoire
9. #JSS2014
Hive fonctionnement globale
Block n
Block n
Block n
Block n
foo/foo1.tx
t
Hive METASTORE
FOO -> /dw/foo
select id, count(0)
from FOO group
by id
1. Créer des
jobs en se
servant des
metadonnées
2. Génère et soumet le
traitement au cluster
task
task
task
task
Hive DRIVER
10. #JSS2014
Interprétation SQL par Hive
Parser
Analyse
Sémantique
Générateur
plan
d’éxecution
logique
Générateur
plan
d’éxecution
physique
HiveQL
AST
QB
Operator
Tree
Task Tree
13. #JSS2014
Hive Quelle usage ?
Base de donneés Hive
Langage SQL HiveQL (SQL-92)
Update Oui Non
Delete Oui Non
Transactions Oui Non
Index Extensive Non / Limité
Latence Très faible Elevée
Volume de données To Po
Gestion des
données
Validation à
l’ecriture, contrainte
« schema on read »
14. #JSS2014
Hive Quelle usage ?
PAS DE REQUÊTES
INTERACTIVES
Datwarehouse
DB
Log
DB
SQL/NoSQL
Réseaux
sociaux
19. #JSS2014
• Nouveau moteur d’exécution pour Hadoop
– Supporte M/R + Join
– Permet de construire des plans d’exécution plus
complexe que M/R
• Pipelining
• Utilisation de la mémoire à la place du disque
• Multiple Reduce Stage
Tez
24. #JSS2014
• Hive peut analyser des formats textuels
(CSV, texte brut avec RegEx, Json, …)
– Permet de travailler sur de la donnée brut (log, export
d’API, …)
• Parsing couteux
• Problème de la compression
Hive sur donnée brut
25. #JSS2014
• SequenceFile, Avro, …
– Parsing moins couteux
• Compression par bloc de données
• Stockage adapté pour M/R
Format Binaire
26. #JSS2014
Format orienté colonne
a b c
a1 b1 c1
a2 b2 c2
a3 b3 c3
a4 b4 c4
a5 b5 c5
a1 b1 c1 a2 b2 c2 a3 b3 c3
a1 a2 a3 b1 b2 b3 c1 c2 c3
Représentation logique
des données
Stockage ligne
Stockage colonne
Metadata + Encoding +
Compression
27. #JSS2014
• ORC et Parquet
• Permet un stockage des données en
colonnes
• Améliore les performances en lecture,
écriture et traitement
• Optimisation du stockage grâce à la
compression induite par le format
Format orienté colonne
29. #JSS2014
• Hive traite les données ligne à ligne
– Inefficace notamment pour des agrégations
• Mais résolue dans le monde « SQL » par la
Vectorization
• Contribution hortonwork + microsoft sur Hive
– Modification du Query Engine pour traiter des « vecteurs
de colonnes »
– Meilleur utilisation du CPU et des caches
Vectorisation
30. #JSS2014
• Optimisation de l’arbre d’exécution
– Peu d’optimisations
• Partition pruning
• Projection pruning
• Filter push down
• Pas d’optimisation lié à la donnée
– Ordre des tables dans les jointures importants
– Pas de hint
Hive < 0.14 : RBO
33. #JSS2014
• Même problématique que pour une base
SQL
– Les statistiques doivent être calculé et représentative
des données
Hive : Calcul des statistiques
DAVID
Hadoop n’est pas une base de données.
C’est un système de fichiers distribué (HDFS) et un moteur de calcul (MapReduce)
D’ailleurs il est très peu performant sur l’analyse des données en temps réel => beaucoup d’évolutions dépendent de cette problématique.
La moitié du code nécessaire à la réalisation d’une jointure
Au moins 6 classes java à développer
DAVID
Développeurs très bon en SQL, mais pas développeurs JAVA
JULIEN
Hive n’est pas un moteur de base de données relationnel sur Hadoop
Hive est une application cliente hadoop qui permet de générer des jobs M/R à partir d’un langage, plus haut niveau et plus productif que M/R
Hive est composé de 2 principaux modules:
- Un metastore qui va stocker les informations sur la structure des données stocké dans HDFS. C’est l’équivalent d’un dictionnaire de données. Il contient notamment la correspondance entre un table et son stockage sur HDFS.
- le driver, qui va interpréter le SQL fournit par le client et le transformer en job map. reduce
JULIEN
Parser (ANTLR) : parser de hiveql vers un abstract syntax tree
Analyse sémantique (en 3 partie) :
Génération du plan logique à partir de l’AST (Query Block)
Optimisation du plan logique
Puis génération du plan d’execution physique: Map reduce
http://fr.slideshare.net/nzhang/hive-anatomy
JULIEN
Explain d’une requête simple.
Temps d’execution.
Create external table
DAVID
DAVID
Pattern classique avec MapReduce on récupère toute les données (DB + Log + social network, etc..)
On stocke tous dans hadoop
On fait les use-cases compliqué ou impossible à faire dans un datawarehouse
Par contre difficile d’intérogé les donnnés en interactifs
Obliger de remettre ces données dans une base de données classique :
Pré aggrégation
Duplication des données
synchronisation
JULIEN
JULIEN
JULIEN
JULIEN
JULIEN
JULIEN
JULIEN
JULIEN
DAVID
Impossible de relire un fichier compresse depuis le milieu
Donc pb avec le découpage
DAVID
Stockage en ligne par système de clé/valeur, optimisé pour le MapReduce (compris que par hadoop)
Peuvent être compressé par valeur ou bloc de données pour limiter les I/O.
Pas l’idéal pour Hive car stocké au format ligne. Obligé de lire la ligne complète même si on n’a besoin que d’une colonne.
JULIEN
Column-oriented organizations are more efficient when an aggregate needs to be computed over many rows but only for a notably smaller subset of all columns of data, because reading that smaller subset of data can be faster than reading all data.
Column-oriented organizations are more efficient when new values of a column are supplied for all rows at once, because that column data can be written efficiently and replace old column data without touching any other columns for the rows.
Row-oriented organizations are more efficient when many columns of a single row are required at the same time, and when row-size is relatively small, as the entire row can be retrieved with a single disk seek.
Row-oriented organizations are more efficient when writing a new row if all of the row data is supplied at the same time, as the entire row can be written with a single disk seek.
DAVID
Contribution hortonworks + Microsoft
JULIEN
JULIEN
JULIEN
JULIEN
DAVID
On parlait des speakers, il y a une chose qui leur tient à cœur !