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

Création d'une application Web CRUD simple et d'un magasin d'images à l'aide de Cloudera Operational Database et Flask

La base de données opérationnelle Cloudera (COD) est une solution dbPaaS gérée disponible en tant qu'expérience dans Cloudera Data Platform (CDP). Il offre un accès client multimodal avec valeur-clé NoSQL à l'aide des API Apache HBase et du SQL relationnel avec JDBC (via Apache Phoenix). Ce dernier rend COD accessible aux développeurs habitués à créer des applications utilisant MySQL, Postgres, etc. Les principaux avantages de COD incluent :

  • Auto-scaling : basé sur l'utilisation de la charge de travail du cluster et aura bientôt la possibilité d'augmenter/réduire le cluster
  • Réglage automatique :meilleures performances dans l'empreinte de l'infrastructure existante.
  • Réparation automatique :résolvez automatiquement les problèmes de fonctionnement (à venir).

Dans ce blog, je vais démontrer comment COD peut facilement être utilisé comme système backend pour stocker des données et des images pour une application Web simple. Pour créer cette application, nous utiliserons Phoenix, l'un des composants sous-jacents de COD, avec Flask. Pour stocker les images, nous utiliserons une fonctionnalité HBase (stockage principal d'Apache Phoenix) appelée MOB (objets moyens). MOB nous permet de lire/écrire rapidement des valeurs de 100 k à 10 Mo.

*Pour faciliter le développement, vous pouvez également utiliser le serveur de requête Phoenix au lieu de COD. Le serveur de requêtes est une petite version de Phoenix destinée uniquement à des fins de développement, et les données sont supprimées dans chaque version.

Tout le code est dans mon référentiel github.

Consigne :

1. Connectez-vous à Cloudera Management Console et sélectionnez l'expérience de base de données opérationnelle

2. Choisissez votre environnement et nommez votre DB

3. Une fois la base de données en place, prenez l'URL du client léger JDBC

4. Définissez votre mot de passe de charge de travail CDP

5. Cloner le dépôt git du projet et les exigences d'installation :$ pip install -r requirements.txt

6. Allez dans le dossier de l'application et exécutez "setup.py" - cela créera un tableau avec 3 enregistrements d'utilisateurs et leurs images $ python setup.py

7. Exécutez le serveur Web flask pour que l'application Web démarre :$ FLASK_APP=app.py python -m flask run –port=8888 –host=127.0.0.1  –reload –with-threads –debugger

8. Accédez à http://localhost:8888/users sur votre navigateur. Vous devriez pouvoir voir l'application en cours d'exécution ! C'est aussi simple que ça.

En passant par le code

1. La classe Schema contient essentiellement les détails de connexion et les méthodes de création et de suppression de table. Comme vous pouvez le voir, la colonne "photo" est de type VARBINARY, qui se traduit par un objet MOB dans HBase :

import phoenixdb
import phoenixdb.cursor
class Schema:
    def __init__(self):
        opts = {}
        opts['authentication'] = 'BASIC'
        opts['avatica_user'] = '<cod workload username>'
        opts['avatica_password'] = '<cod workload pw>'
        database_url = "<cod thin jdbc url>"
        self.TABLENAME = "users"
        self.conn = phoenixdb.connect(database_url, autocommit=True,**opts)
        self.curs = self.conn.cursor()

    def create_users_table(self):
        query = """
        CREATE TABLE IF NOT EXISTS """+self.TABLENAME+""" (
        username VARCHAR NOT NULL,
        firstname VARCHAR,
        lastname  VARCHAR,
        telephone VARCHAR,
        message VARCHAR,
        email VARCHAR,
        photo VARBINARY,
        photo_name VARCHAR,
        photo_type VARCHAR,
        photo_chars VARCHAR
        CONSTRAINT my_pk PRIMARY KEY (username))
        """
        self.curs.execute(query)

    def drop_users_table(self):
        query = "DROP TABLE "+self.TABLENAME
        self.curs.execute(query)

2 La classe des utilisateurs est responsable de toutes les opérations d'application avec Phoenix. Nous pouvons mettre à jour/insérer (upsert en langage phénix), supprimer, répertorier et gérer les transactions d'images :

import phoenixdb
from schema import Schema
import json
class UsersModel:
    TABLENAME = "users"

    def __init__(self):
        db = Schema()
        self.conn=db.conn
        self.curs=db.curs

    def upsert(self, params):

        sql = "upsert into " + self.TABLENAME + \
            " (username ,message,telephone,firstname,lastname,email) \
             values (?,?,?,?,?,?)"
        data = (params.get('username'),params.get('message'),\
            params.get('telephone'),params.get('firstname'),\
            params.get('lastname'),params.get('email'))
        results = self.curs.execute(sql,data)
        return results

    def upsert_photo(self, params):
        if params.get('photo') is None:
            photo = bytes('','utf-8')
        else:
            photo = params.get('photo')

        sql = "upsert into " + self.TABLENAME + \
            " (username, photo,photo_name) values (?,?,?)"

        data = (params.get('username'),photo, params.get('photo_name'))
        results = self.curs.execute(sql,data)
        return results

    def delete(self, username):
        query = f"DELETE from {self.TABLENAME} " \
                f"WHERE username = {username}"

        self.curs.execute(query)

    def list_items(self, where_clause="",format="json"):
        query = f"SELECT username ,email,message,telephone,firstname,\
            lastname,photo_name " \
            f"from {self.TABLENAME} WHERE  " + where_clause

        self.curs.execute(query)
        if format=="json":
            r = [dict((self.curs.description[i][0].lower(), value) \
                   for i, value in enumerate(row)) for row in \
                   self.curs.fetchall()]
            self.conn.close()
            data={'data': r }
            return json.dumps(data)

        result_set=self.curs.fetchall()
        result = [{column: row[i]
            for i, column in enumerate(result_set[0].keys())}
                for row in result_set]
        return result
    def get_image(self, username):
        query = f"SELECT photo,photo_name " \
                f"from {self.TABLENAME} WHERE  username='"+username+"'"

        self.curs.execute(query)
        row = self.curs.fetchone()
        return row

3. L'app.py est le routeur principal de l'application. Il contient toutes les manipulations avec les entrées utilisateur et les achemine vers les méthodes de connexion. J'ai séparé la gestion des images pour la facilité d'utilisation, et ainsi je peux obtenir une image spécifique pour un utilisateur :

from flask import Flask, request, send_file ,jsonify,render_template
import phoenixdb
import io
from users import UsersModel
from schema import Schema
import json

app = Flask(__name__)

@app.after_request
def add_headers(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Headers'] =  \
        "Content-Type, Access-Control-Allow-Headers, Authorization, \
        X-Requested-With"
    response.headers['Access-Control-Allow-Methods']=  "POST, GET, PUT, \
    DELETE, OPTIONS"
    response.headers['Allow']=  "POST, GET, PUT, OPTIONS"
    return response

@app.route("/")
def hello():
    return "Hello World!"

@app.route("/users")
def return_form():
    return render_template("users.html")

@app.route("/handle_data",methods=['POST'])
def handle_data():
    if request.method == 'POST':
        username = request.form['username']
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        telephone = request.form['telephone']
        message = request.form['message']
        photo = request.files['photo']
        photo_bytes = photo.read()
        model=Schema()
        usersmodel=UsersModel()
        data = {'username':f"{username}",'firstname':f"{firstname}",\
            'lastname':f"{lastname}",'telephone':f"{telephone}",\
            'message':f"{message}"}
        photo_data = {'username':f"{username}",\
            'photo':photo_bytes,\
            'photo_name':f"{photo.filename}"}
        usersmodel.upsert(data)
        usersmodel.upsert_photo(photo_data)
        return render_template('users.html')
    else:
        return render_template('users.html')

@app.route("/get_users",methods=['GET'])
def get_users():
    if request.method == 'GET':
        usersmodel=UsersModel()
        users = usersmodel.list_items("1=1")
        return users

@app.route("/get_image",methods=['GET'])
def get_image():
    if request.method == 'GET':
        username = request.args.get('username')
        usersmodel=UsersModel()
        imagedb = usersmodel.get_image(username)
        return send_file(io.BytesIO(imagedb[0]),mimetype='image/png', \
            attachment_filename=imagedb[1])

if __name__ == "__main__":
    Schema()
    app.run(debug=True, port=8888)

Prochaines étapes, vous pouvez utiliser ce référentiel github pour tester votre application.

J'espère que vous le trouverez utile, bon codage !!