Il existe différentes façons d'accéder et d'interagir avec Apache HBase. L'API Java fournit le plus de fonctionnalités, mais de nombreuses personnes souhaitent utiliser HBase sans Java.
Il existe deux approches principales pour ce faire : la première est l'interface Thrift, qui est la plus rapide et la plus légère des deux options. L'autre façon d'accéder à HBase consiste à utiliser l'interface REST, qui utilise des verbes HTTP pour effectuer une action, offrant aux développeurs un large choix de langages et de programmes à utiliser.
Cette série de procédures abordera l'interface REST et fournira des exemples de code Python pour y accéder. Le premier article couvrira HBase REST, certaines mises en garde Python et l'administration des tables. Le deuxième article expliquera comment insérer plusieurs lignes à la fois en utilisant XML et JSON. Le troisième article montrera comment obtenir plusieurs lignes en utilisant XML et JSON. Les exemples de code complets sont disponibles sur mon compte GitHub.
Les bases de HBase REST
Pour que Thrift et REST fonctionnent, un autre démon HBase doit être en cours d'exécution pour gérer ces demandes. Ces démons peuvent être installés dans les packages hbase-thrift et hbase-rest. Le diagramme ci-dessous illustre où Thrift et REST sont placés dans le cluster. Notez que les clients Thrift et REST n'exécutent généralement aucun autre service comme DataNode ou RegionServers pour réduire la charge et augmenter la réactivité des interactions REST.
Assurez-vous d'installer et de démarrer ces démons sur les nœuds qui ont accès à la fois au cluster Hadoop et au serveur d'applications Web. L'interface REST n'a pas d'équilibrage de charge intégré ; cela devra être fait avec du matériel ou en code. Cloudera Manager facilite l'installation et la gestion des services HBase REST et Thrift. (Vous pouvez le télécharger et l'essayer gratuitement !) L'inconvénient de REST est qu'il est beaucoup plus lourd que Thrift ou Java.
Une interface REST peut utiliser différents formats de données :XML, JSON et protobuf. En spécifiant le Accept
et Content-Type
en-têtes, vous pouvez choisir le format que vous souhaitez transmettre ou recevoir en retour.
Pour commencer à utiliser l'interface REST, vous devez déterminer sur quel port il s'exécute. Le port par défaut pour CDH est le port 8070. Pour cet article, vous verrez le baseurl
variable utilisée, et voici la valeur que j'utiliserai ::
baseurl = "http://localhost:8070"
L'interface REST peut être configurée pour utiliser un identifiant Kerberos afin d'augmenter la sécurité.
Pour votre code, vous devrez utiliser l'adresse IP ou le nom de domaine complet DNS du nœud exécutant le démon REST. Vérifiez également que le port est correct. Je recommande fortement de faire de cette URL une variable, car elle pourrait changer avec les changements de réseau.
Solutions de contournement des bogues Python et HBase
Deux bogues et solutions de contournement doivent être résolus. Le premier bogue est que les modules Python intégrés ne prennent pas en charge tous les verbes HTTP. Le second est un bogue HBase REST lors de l'utilisation de JSON.
Les modules Python intégrés pour l'interaction REST ne prennent pas facilement en charge tous les verbes HTTP nécessaires pour HBase REST. Vous devrez installer le module de requêtes Python. Le module de requêtes nettoie également le code et facilite grandement toutes les interactions.
L'interface HBase REST a un bug lors de l'ajout de données via JSON :il est nécessaire que les champs conservent leur ordre exact. Le Python dict
intégré type ne prend pas en charge cette fonctionnalité, donc pour maintenir l'ordre, nous devrons utiliser le OrderedDict
classe. (Ceux qui utilisent Python 2.6 et les versions antérieures devront installer le module orderdict.) Je couvrirai également le bogue et la solution de contournement plus tard dans l'article.
Il était également difficile d'utiliser l'encodage et le décodage d'entiers en base64, j'ai donc écrit du code pour le faire :
# Method for encoding ints with base64 encoding def encode(n): data = struct.pack("i", n) s = base64.b64encode(data) return s # Method for decoding ints with base64 encoding def decode(s): data = base64.b64decode(s) n = struct.unpack("i", data) return n[0]
Pour rendre les choses encore plus faciles, j'ai écrit une méthode pour confirmer que les réponses HTTP reviennent dans les 200, ce qui indique que l'opération a fonctionné. L'exemple de code utilise cette méthode pour vérifier le succès d'un appel avant de continuer. Voici la méthode :
# Checks the request object to see if the call was successful def issuccessful(request): if 200
Travailler avec des tableaux
À l'aide de l'interface REST, vous pouvez créer ou supprimer des tables. Examinons le code pour créer une table.
content = '' content += '' content += ' ' content += '' request = requests.post(baseurl + "/" + tablename + "/schema", data=content, headers={"Content-Type" : "text/xml", "Accept" : "text/xml"})
Dans cet extrait, nous créons un petit document XML qui définit le schéma de table dans la variable de contenu. Nous devons fournir le nom de la table et le nom de famille de la colonne. S'il y a plusieurs familles de colonnes, vous créez d'autres ColumnSchema
nœuds.
Ensuite, nous utilisons le module de requêtes pour POST
le XML à l'URL que nous créons. Cette URL doit inclure le nom de la nouvelle table. Notez également que nous définissons les en-têtes pour ce POST
appel. Nous montrons que nous envoyons en XML avec le Content-Type
défini sur "text/xml" et que nous voulons récupérer XML avec le Accept
défini sur "texte/xml".
Utiliser le request.status_code
, vous pouvez vérifier que la création de la table a réussi. L'interface REST utilise les mêmes codes d'erreur HTTP pour détecter si un appel a réussi ou généré une erreur. Un code d'état dans les 200 signifie que tout a fonctionné correctement.
Nous pouvons facilement vérifier si une table existe en utilisant le code suivant :
request = requests.get(baseurl + "/" + tablename + "/schema")
Les appels utilisent le GET
verbe pour dire à l'interface REST que nous voulons obtenir les informations de schéma sur la table dans l'URL. Encore une fois, nous pouvons utiliser le code d'état pour voir si la table existe. Un code de statut dans les années 200 signifie qu'il existe et tout autre nombre signifie qu'il n'existe pas.
Utilisation de la curl
commande, nous pouvons vérifier le succès d'une opération REST sans écrire de code. La commande suivante renverra un 200 indiquant le succès de l'appel car le messagestable
table existe dans HBase. Voici l'appel et sa sortie :
[user@localhost]$ curl -I -H "Accept: text/xml" http://localhost:8070/messagestable/schema HTTP/1.1 200 OK Content-Length: 0 Cache-Control: no-cache Content-Type: text/xml
Cet appel REST générera une erreur car le tablenotthere
table n'existe pas dans HBase. Voici l'appel et sa sortie :
[user@localhost]$ curl -I -H "Accept: text/xml" http://localhost:8070/tablenotthere/schema HTTP/1.1 500 org.apache.hadoop.hbase.TableNotFoundException: tablenotthere Content-Type: text/html; charset=iso-8859-1 Cache-Control: must-revalidate,no-cache,no-store Content-Length: 10767
Nous pouvons supprimer une table en utilisant le code suivant :
request = requests.delete(baseurl + "/" + tablename + "/schema")
Cet appel utilise le DELETE
verbe pour indiquer à l'interface REST que nous voulons supprimer la table. La suppression d'une table via l'interface REST ne vous oblige pas à la désactiver au préalable. Comme d'habitude, nous pouvons confirmer le succès en regardant le code d'état.
Dans le prochain article de cette série, nous aborderons l'insertion de lignes.
Jesse Anderson est instructeur à l'université Cloudera.
Si vous êtes intéressé par HBase, assurez-vous de vous inscrire à HBaseCon 2013 (13 juin, San Francisco) – L'événement communautaire pour les contributeurs, développeurs, administrateurs et utilisateurs de HBase. L'inscription anticipée est ouverte jusqu'au 23 avril.