HBase
 sql >> Base de données >  >> NoSQL >> HBase

Utilisation de Hive pour interagir avec HBase, partie 1

Cet article de blog a été publié sur Hortonworks.com avant la fusion avec Cloudera. Certains liens, ressources ou références peuvent ne plus être exacts.

Ceci est le premier de deux articles examinant l'utilisation de Hive pour l'interaction avec les tables HBase. Le deuxième message se trouve ici.

On me demande souvent comment utiliser HBase d'Apache Hive. Pas seulement comment le faire, mais ce qui fonctionne, dans quelle mesure cela fonctionne-t-il et comment en faire bon usage. J'ai fait quelques recherches dans ce domaine, alors j'espère que cela sera utile à quelqu'un d'autre que moi. C'est un sujet que nous n'avons pas pu couvrir dans HBase en action, peut-être que ces notes deviendront la base de la 2e édition 😉 Ces notes s'appliquent à Hive 0.11.x utilisé conjointement avec HBase 0.94.x. Ils devraient être largement applicables à 0.12.x + 0.96.x, bien que je n'aie pas encore tout testé.

Le projet Hive inclut une bibliothèque facultative pour interagir avec HBase. C'est là que la couche de pont entre les deux systèmes est implémentée. L'interface principale que vous utilisez lorsque vous accédez à HBase à partir de requêtes Hive s'appelle BaseStorageHandler. . Vous pouvez également interagir directement avec les tables HBase via les formats d'entrée et de sortie, mais le gestionnaire est plus simple et fonctionne pour la plupart des utilisations.

Tables HBase de Hive

Utilisez le HBaseStorageHandler pour enregistrer les tables HBase auprès du métastore Hive. Vous pouvez éventuellement spécifier la table HBase en tant que EXTERNAL , auquel cas Hive ne créera pas pour supprimer directement cette table. Vous devrez utiliser le shell HBase pour le faire.

[sql]
CREATE [EXTERNAL] TABLE foo(…)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
TBLPROPERTIES ('hbase.table.name' =' bar');
[/sql]

L'instruction ci-dessus enregistre la table HBase nommée bar dans le métastore Hive, accessible depuis Hive sous le nom foo .

Sous le capot, HBaseStorageHandler délègue l'interaction avec la table HBase à
HiveHBaseTableInputFormat et HiveHBaseTableOutputFormat . Vous pouvez enregistrer votre table HBase dans Hive en utilisant ces classes directement si vous le souhaitez. L'énoncé ci-dessus équivaut à peu près à :

[sql]
CRÉER TABLE foo(…)
STOCKÉ COMME
INPUTFORMAT 'org.apache.hadoop.hive.hbase.HiveHBaseTableInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive .hbase.HiveHBaseTableOutputFormat'
TBLPROPERTIES ('hbase.table.name' ='bar');
[/sql]

Le HiveHFileOutputFormat est également fourni. ce qui signifie qu'il devrait également être possible de générer des HFiles pour le chargement en masse à partir de Hive. En pratique, je n'ai pas réussi à faire fonctionner cela de bout en bout (voir HIVE-4627).

Mappage de schéma

L'enregistrement de la table n'est que la première étape. Dans le cadre de cet enregistrement, vous devez également spécifier un mappage de colonne. C'est ainsi que vous liez les noms de colonne Hive à la clé de ligne et aux colonnes de la table HBase. Faites-le à l'aide de hbase.columns.mapping Propriété SerDe.

[sql]
CREATE TABLE foo(rowkey STRING, a STRING, b STRING)
STOCKÉ PAR 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
AVEC SERDEPROPERTIES ('hbase.columns .mapping' =':key,f:c1,f:c2')
TBLPROPERTIES ('hbase.table.name' ='bar');

[/sql]

Les valeurs fournies dans la propriété de mappage correspondent une pour une aux noms de colonne de la table Hive. Les noms de colonne HBase sont entièrement qualifiés par famille de colonnes et vous utilisez le jeton spécial :key pour représenter la clé de ligne. Ce qui précède

l'exemple crée des lignes à partir de la table HBase bar disponible via la table Hive foo . Le foo colonne rowkey correspond à la clé de ligne de la table HBase, a à c1 dans le f famille de colonnes et b à c2 , également dans le f famille.

Vous pouvez également associer le MAP de Hive structures de données aux familles de colonnes HBase. Dans ce cas, seul le STRING Le type de ruche est utilisé. L'autre type de ruche actuellement pris en charge est BINARY . Voir la page wiki pour plus d'exemples.

Interagir avec les données

Une fois les mappages de colonnes définis, vous pouvez désormais accéder aux données HBase comme vous le feriez pour n'importe quelle autre donnée Hive. Seuls les prédicats de requête simples sont actuellement compatibles.

[sql]
SELECT * FROM foo WHERE …;
[/sql]

Vous pouvez également remplir une table HBase à l'aide de Hive. Cela fonctionne avec INTO et OVERWRITE clauses.

[sql]
FROM source_hive_table INSERT INTO TABLE my_hbase_table
SELECT source_hive_table.* WHERE …;
[/sql]

Sachez qu'il existe une régression dans Hive 0.12.0 qui interrompt cette fonctionnalité, voir HIVE-5515.

En pratique

Il reste encore un peu de finesse pour que tout soit correctement câblé au moment de l'exécution. Le module d'interaction HBase est entièrement facultatif, vous devez donc vous assurer qu'il et ses dépendances HBase sont disponibles sur le chemin de classe de Hive.

[bash]
$ export HADOOP_CLASSPATH=…
$ hive -e "CREATE TABLE … STORED BY 'org.apache…HBaseStorageHandler'"
[/bash]

L'environnement d'installation pourrait mieux gérer cela pour les utilisateurs, mais pour le moment, vous devez le gérer vous-même. Idéalement la hive bin script peut détecter la présence de HBase et créer automatiquement le CLASSPATH nécessaire ajustements. Cette amélioration semble être suivie dans HIVE-2055. Le dernier kilomètre est fourni par la distribution elle-même, garantissant que les variables d'environnement sont définies pour hive . Cette fonctionnalité est fournie par BIGTOP-955.

Vous devez également vous assurer que les jars nécessaires sont envoyés aux tâches MapReduce lorsque vous exécutez vos instructions Hive. Hive fournit un mécanisme permettant d'envoyer des dépendances de tâches supplémentaires via la fonctionnalité auxjars.

[bash]
$ export HIVE_AUX_JARS_PATH=…
$ hive -e "SELECT * FROM …"
[/bash]

J'ai découvert un petit bogue dans les versions HDP-1.3 qui masque les valeurs spécifiées par l'utilisateur de HIVE_AUX_JARS_PATH . Avec des droits d'administration, cela est facilement résolu en corrigeant la ligne dans hive-env.sh respecter une valeur existante. La
solution de contournement dans les scripts utilisateur consiste à utiliser le SET pour fournir une valeur une fois que vous avez lancé la CLI Hive.

[bash]
SET hive.aux.jars.path =…
[/bash]

Hive devrait être capable de détecter quels pots sont nécessaires et de les ajouter lui-même. HBase fournit le  TableMapReduceUtils#addDependencyJars  méthodes à cet effet. Il semble que cela se fasse dans hive-0.12.0, du moins selon HIVE-2379.

Travaux futurs

On a beaucoup parlé de la prise en charge appropriée du refoulement des prédicats (HIVE-1643, HIVE-2854, HIVE-3617,
HIVE-3684) et de la reconnaissance des types de données (HIVE-1245, HIVE-2599). Celles-ci vont de pair, car la sémantique des prédicats est définie en fonction des types sur lesquels elles opèrent. Davantage pourrait être fait pour mapper les types de données complexes de Hive, tels que Maps et Structs, sur les familles de colonnes HBase (HIVE-3211). La prise en charge des horodatages HBase est un peu compliquée ; ils ne sont pas mis à la disposition des applications Hive avec n'importe quel niveau de granularité (HIVE-2828, HIVE-2306). La seule interaction d'un utilisateur se fait via le paramètre du gestionnaire de stockage pour écrire un horodatage personnalisé avec toutes les opérations.

Du point de vue des performances, il y a des choses que Hive peut faire aujourd'hui (c'est-à-dire sans dépendre des types de données) pour tirer parti de HBase. Il est également possible qu'une ruche compatible avec HBase utilise les tables HBase comme emplacement de stockage intermédiaire (HIVE-3565), ce qui facilite les jointures côté carte par rapport aux tables de dimension chargées dans HBase. Hive pourrait utiliser la structure indexée naturelle de HBase (HIVE-3634, HIVE-3727), ce qui pourrait économiser d'énormes analyses. Actuellement, l'utilisateur n'a (aucun ?) contrôle sur les analyses exécutées. La configuration par tâche ou au moins par table doit être activée (HIVE-1233). Cela permettrait à un utilisateur connaissant HBase de fournir à Hive des conseils sur la manière dont il devrait interagir avec HBase. La prise en charge de l'échantillonnage fractionné simple des tables HBase (HIVE-3399) peut également être facilement réalisée car HBase gère déjà les partitions de table.

Autres canaux d'accès

Tout ce qui a été discuté jusqu'à présent a nécessité que Hive interagisse avec les serveurs de région HBase en ligne. Les applications peuvent bénéficier d'un débit important et d'une plus grande flexibilité en interagissant directement avec les données HBase conservées sur HDFS. Cela a également l'avantage d'empêcher les charges de travail Hive d'interférer avec les applications HBase liées au SLA en ligne (du moins, jusqu'à ce que nous constations des améliorations HBase dans l'isolation QOS entre les tâches, HBASE-4441).

Comme mentionné précédemment, il existe le HiveHFileOutputFormat . La résolution de HIVE-4627 devrait faire de Hive un moyen simple de générer des HFiles pour le chargement en masse. Une fois que vous avez créé les HFiles à l'aide de Hive, il reste la dernière étape d'exécution de
LoadIncrementalHFiles utilitaire pour les copier et les enregistrer dans les régions. Pour cela, le HiveStorageHandler  l'interface aura besoin d'une sorte de hook pour influencer le plan de requête lors de sa création, lui permettant d'ajouter des étapes. Une fois en place, il devrait être possible de SET un indicateur d'exécution, en changeant un INSERT  opération pour utiliser le chargement en masse.

HBase a récemment introduit la fonctionnalité d'instantané de table. Cela permet à un utilisateur de créer une vue ponctuelle persistante d'une table, conservée dans HDFS. HBase est capable de restaurer une table à partir d'un instantané vers un état antérieur et de créer une table entièrement nouvelle à partir d'un instantané existant. Hive ne prend actuellement pas en charge la lecture à partir d'un instantané HBase. D'ailleurs, HBase ne prend pas encore en charge les tâches MapReduce sur les instantanés, bien que la fonctionnalité soit en cours de développement (HBASE-8369).

Conclusion

L'interface entre HBase et Hive est jeune, mais a un beau potentiel. Il y a beaucoup de fruits à portée de main qui peuvent être ramassés pour rendre les choses plus faciles et plus rapides. Le problème le plus flagrant qui empêche le développement d'applications réelles est l'inadéquation de l'impédance entre le schéma dense et typé de Hive et le schéma clairsemé et non typé de HBase. C'est autant un problème cognitif qu'un problème technique. Les solutions ici permettraient à un certain nombre d'améliorations de tomber, y compris en termes d'amélioration des performances. J'espère que la poursuite des travaux visant à ajouter des types de données à HBase (HBASE-8089) pourra aider à combler cette lacune.

Les opérations de base fonctionnent pour la plupart, du moins de manière rudimentaire. Vous pouvez lire et réécrire des données dans HBase à l'aide de Hive. La configuration de l'environnement est un processus opaque et manuel, qui empêche probablement les novices d'adopter les outils. Il y a aussi la question des opérations en masse :la prise en charge de l'écriture de fichiers HFile et de la lecture d'instantanés HBase à l'aide de Hive fait totalement défaut à ce stade. Et bien sûr, il y a des bugs parsemés partout. La plus grande amélioration récente est la dépréciation de l'interface de HCatalog, supprimant la décision préalable nécessaire concernant l'interface à utiliser.

Hive fournit une interface SQL très utilisable en plus de HBase, qui s'intègre facilement dans de nombreux workflows ETL existants. Cette interface nécessite de simplifier une partie de la sémantique BigTable fournie par HBase, mais le résultat sera d'ouvrir HBase à un public d'utilisateurs beaucoup plus large. L'interopérabilité Hive complète extrêmement bien l'expérience fournie par Phoenix. Hive a l'avantage de ne pas nécessiter les complexités de déploiement actuellement requises par ce système. Espérons que la définition commune des types permettra un avenir complémentaire.