.Net

HdInsight : lancer des requêtes hive avec .Net Core

Juin 18, 2019

Nicolas Bailly

Nous avons vu dans un précédent article comment exécuter des requêtes Hive avec python. Nous allons maintenant voir comment faire de même en .Net Core, ce qui permettra d’exécuter une application .Net sur le cluster qui est sous linux.
Pour cela, on va s’appuyer sur un package NuGet que j’ai développé pour cet effet ( https://www.nuget.org/packages/Hive4Net) dont le code source est disponible sur Github : https://github.com/nicolasbailly1/Hive4Net

Comment lancer des requêtes Hive

Il existe différents moyens de lancer des requêtes Hive sur HdInsight, dont :

  • Webhcat : c’est une API Rest pour HCatalalog. Mais ce n’est pas disponible sur HdInisght 4.0 et même sur certains types de cluster de HdInsight 3. Si vous utilisez des requêtes Powershell (New-AzHDInsightHiveJobDefinition -Query $queryString) ou le package NuGet Microsoft.Azure.Management.HDInsight.Job, c’est WebHcat qui est utilisé. Donc si vous avez un cluster sans WebHcat, ceux-ci ne peuvent pas fonctionner.
  • Hive View : c’est une interface web qui permet lancer des requêtes Hive. Cette interface utilise une API Rest qu’il est possible d’utiliser. Mais sur HdInsight 4.0, Hive View n’est plus disponible.
  • Driver Odbc : il existe un driver Odbc (https://www.microsoft.com/en-us/download/details.aspx?id=40886) qui permet de se connecter à HdInsight. Si vous utilisez Visual Studio, vous l’avez déjà, et vous pouvez lancer des requêtes Hive.
  • Requêtes via Apache Thrift : c’est ce que nous allons voir ici et c’est ce que nous avons utilisé en python dans le précédent article. Il s’agit d’un protocol de communication disponible sur le cluster HdInisght. L’inconvénient est que ça ne fonctionne que depuis le réseau local du cluster car le Load Balancer ne permet pas d’accéder à l’API Thrift depuis l’extérieur. Il faut donc se connecter en SSH sur le cluster et lancer l’application sur celui-ci. C’est là où .Net Core devient intéressant, puisque nous pouvons lancer une application sur le cluster qui tourne sous linux.

Création d’une application .Net Core

J’ai développé un package Nuget .Net Core qui s’appuie sur Thrift pour lancer des requêtes Hive :
https://www.nuget.org/packages/Hive4Net
Ce package fonctionne exactement comme le package python PyHive. C’est-à-dire que nous pouvons l’utiliser simplement comme ceci :

Hive hive = new Hive("localhost", 10001, "admin", "myPassword");
await hive.OpenAsync();
var cursor = hive.GetCursorAsync();
cursor.ExecuteAsync("SHOW TABLES");
var result = cursor.FetchAsync(100);

Mais dans le cas de HdInsight, il faut que nous passions par une communication en HTTP. Pour cela, nous utilisons un objet THttpClientTransport dans lequel nous passons le login et le mot de passe dans le Header pour une authentification basique :

private static TClientTransport AddHttpMode(string userName, string password, string host, int port = 10001)
{
    var byteArray = Encoding.ASCII.GetBytes($"{userName}:{password}");
    Dictionary<string, string> customHeaders = new Dictionary<string, string>();
    customHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(byteArray)}");
    Uri uri = new Uri($"https://{host}:{port}/cliservice");
    return new THttpClientTransport(uri, customHeaders);
}

private static async Task<List<ExpandoObject>> GetResultSet(TClientTransport transport, string query)
{
    Hive hive = new Hive(transport);
    await hive.OpenAsync();
    var cursor = await hive.GetCursorAsync();
    await cursor.ExecuteAsync(query);
    return await cursor.FetchManyAsync(100);
}

static void Main(string[] args)
{
    string userName = "";
    string password = "***";
    var transport = AddHttpMode(userName, password, "localhost");
    var resultSet = GetResultSet(transport, query).Result;
}

Si on regarde un peu plus en détail ce qui est fait :

  • D’abord nous ouvrons une connexion avec la méthode OpenAsync. C’est à ce moment là que l’objet transport est utilisé. Par défaut, la méthode OpenAsync instancie un objet TSocketClientTransport pour communiquer par un mode binaire. C’est pourquoi nous passons en paramètre un objet de type THttpClientTransport, pour communiquer en HTTP.
  • GetCursorAsync génère une session et renvoie un objet Cursor. Cet objet Cursor va permettre de conserver une session. Vous pouvez par exemple, lancer une première requête qui vous positionne sur une base de données spécifique : « USE MaBaseDeDonnees; », puis lancer une autre requête sur cette base de données. Si vous recréez un objet Cursor à chaque fois, ceci ne sera pas possible car le contexte sera perdu.
  • Avec l’objet Cursor, on exécute la requête. On peut alors s’arrêter là si la requête ne renvoie rien.
  • Toujours avec l’objet Curosor, on récupère le résultat avec la méthode FetchManyAsync. A savoir que cet objet Cursor permet également d’avoir des informations sur le résultat retourné par la requête comme le nom des colonnes, le type de données et la position de la colonne.

Dans l’exemple ci-dessus, le résultat de la requête est récupéré à l’aide de la méthode FetchManyAsync mais nous pouvons utiliser d’autres méthodes :
FetchOne qui renvoie le premier élément du résultat de la requête.
Fetch qui renvoie un objet de type Rowset. Ce sont les données brutes avec la liste des lignes et la liste des colonnes.
FetchMany qui renvoie une liste d’objet de type ExpandoObject. Avec cette méthode, il est plus aisé de parcourir les lignes de résultat car elles se trouvent sous forme de clé/valeur où la clé est le nom de la colonne.

Les méthodes Fetch et FetchMany prennent en argument un entier de type int pour limiter le nombre de lignes à retourner. Ceci est une précaution puisqu’on travaille sur de fortes volumétries.

Voici comment parcourir l’objet retourné avec la méthode FetchMany :

private static void DisplayResultSet(List<ExpandoObject> resultSet)
{
    if (!resultSet.IsEmpty())
    {
        Console.WriteLine("-----------Début-------------");
        foreach (var row in resultSet)
        {
            Console.Write("Row - ");
            var dict = (IDictionary<string, object>)row;
            foreach (var key in dict.Keys)
            {
                Console.WriteLine($"{key} : {dict[key]}");
            }
        }
        Console.WriteLine("-----------Fin-------------");
    }
    else
    {
            Console.WriteLine("No result");
    }
}

Déploiement de l’application

Maintenant que nous avons vu comment lancer des requêtes Hive en .Net, nous allons déployer une application sur le cluster.
Tout d’abord, il faut installer dotnet core :

  • Se connecter en SSH
  • Récupérer le script d’installation : wget https://dot.net/v1/dotnet-install.sh
  • Ajouter les droits d’exécution sur le script : chmod +x dotnet-install.sh
  • Installer la dernière version de .Net Core dans le répertoire /usr/share/dotnet : ./dotnet-install.sh -c Current –install-dir /usr/share/dotnet
  • Ajouter un lien symbolique de l’exécutable dotnet vers /usr/bin : sudo ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

Voici le script complet qui peut être lancer en tant qu’action script à la création du cluster :

#! /bin/bash

wget https://dot.net/v1/dotnet-install.sh
chmod +x dotnet-install.sh
./dotnet-install.sh -c Current --install-dir /usr/share/dotnet
sudo ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

Une fois que votre application est compilée, copiez-la sur le cluster et lancez la commande « dotnet monapplication.dll »

Liens

Package nuget Hive4Net : https://www.nuget.org/packages/Hive4Net
Code source Hive4Net : https://github.com/nicolasbailly1/Hive4Net
Projet PyHive : https://pypi.org/project/PyHive/

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Découvrez nos autres articles

Aller au contenu principal