HBase
 sql >> Datenbank >  >> NoSQL >> HBase

Erstellen einer einfachen CRUD-Webanwendung und eines Bildspeichers mit Cloudera Operational Database und Flask

Die Cloudera Operational Database (COD) ist eine verwaltete dbPaaS-Lösung, die als Erfahrung in der Cloudera Data Platform (CDP) verfügbar ist. Es bietet multimodalen Clientzugriff mit NoSQL-Schlüsselwerten unter Verwendung von Apache HBase-APIs und relationalem SQL mit JDBC (über Apache Phoenix). Letzteres macht COD für Entwickler zugänglich, die daran gewöhnt sind, Anwendungen zu erstellen, die MySQL, Postgres usw. verwenden. Zu den wichtigsten Vorteilen von COD gehören:

  • Auto-Skalierung – basierend auf der Workload-Nutzung des Clusters und wird bald die Möglichkeit haben, den Cluster nach oben/unten zu skalieren
  • Automatische Abstimmung – bessere Leistung innerhalb der bestehenden Infrastruktur.
  • Automatische Reparatur – Behebt Betriebsprobleme automatisch (demnächst verfügbar).

In diesem Blog werde ich demonstrieren, wie COD einfach als Backend-System verwendet werden kann, um Daten und Bilder für eine einfache Webanwendung zu speichern. Um diese Anwendung zu erstellen, verwenden wir Phoenix, eine der zugrunde liegenden Komponenten von COD, zusammen mit Flask. Zum Speichern von Bildern verwenden wir eine HBase-Funktion (Apache Phoenix Backend Storage) namens MOB (Medium Objects). MOB ermöglicht es uns, Werte von 100k-10MB schnell zu lesen/schreiben.

*Zur Vereinfachung der Entwicklung können Sie anstelle von COD auch den Phoenix-Abfrageserver verwenden. Der Abfrageserver ist ein kleiner Build von Phoenix, der nur für Entwicklungszwecke gedacht ist, und Daten werden in jedem Build gelöscht.

Der gesamte Code befindet sich in meinem Github-Repo.

Anleitung:

1. Melden Sie sich bei der Cloudera Management Console an und wählen Sie die Operational Database-Erfahrung aus

2. Wählen Sie Ihre Umgebung und benennen Sie Ihre DB

3. Sobald die DB hochgefahren ist, nehmen Sie die URL vom Thin JDBC-Client

4. Legen Sie Ihr CDP-Workload-Passwort fest

5. Klonen Sie das Git-Repository des Projekts und installieren Sie die Anforderungen:$ pip install -r requirements.txt

6. Gehen Sie zum App-Ordner und führen Sie „setup.py“ aus – dies erstellt eine Tabelle mit 3 Datensätzen von Benutzern und ihren Bildern $ python setup.py

7. Führen Sie den Flask-Webserver für die zu startende Webanwendung aus:$ FLASK_APP=app.py python -m Flask run –port=8888 –host=127.0.0.1  –reload –with-threads –debugger

8. Gehen Sie in Ihrem Browser zu http://localhost:8888/users. Sie sollten sehen können, wie die Anwendung ausgeführt wird! So einfach.

Den Kodex durchgehen

1. Die Schema-Klasse enthält im Wesentlichen die Verbindungsdetails und Methoden zum Erstellen und Löschen von Tabellen. Wie Sie sehen können, ist die Spalte „Foto“ ein VARBINARY-Typ, der in HBase in ein MOB-Objekt übersetzt wird:

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 Die Benutzerklasse ist für den gesamten Anwendungsbetrieb mit Phoenix verantwortlich. Wir können Bildtransaktionen aktualisieren/einfügen (Upsert in Phoenix-Sprache), löschen, auflisten und handhaben:

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. Die app.py ist der Hauptrouter für die Anwendung. Es enthält die gesamte Behandlung von Benutzereingaben und deren Weiterleitung an die Verbindungsmethoden. Ich habe die Handhabung von Bildern für die Benutzerfreundlichkeit getrennt, und auf diese Weise kann ich ein bestimmtes Bild für einen Benutzer erhalten:

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)

Als Nächstes können Sie dieses Github-Repo verwenden, um Ihre Anwendung zu testen.

Ich hoffe, Sie finden es nützlich. Viel Spaß beim Programmieren!