sql >> Database >  >> NoSQL >> HBase

Een eenvoudige CRUD-webtoepassing en afbeeldingsopslag bouwen met Cloudera Operational Database en Flask

De Cloudera Operational Database (COD) is een beheerde dbPaaS-oplossing die beschikbaar is als een ervaring in Cloudera Data Platform (CDP). Het biedt multimodale clienttoegang met NoSQL-sleutelwaarde met behulp van Apache HBase API's en relationele SQL met JDBC (via Apache Phoenix). Dit laatste maakt COD toegankelijk voor ontwikkelaars die gewend zijn applicaties te bouwen die MySQL, Postgres, enz. gebruiken. De belangrijkste voordelen van COD zijn:

  • Automatisch schalen –  gebaseerd op het gebruik van de werkbelasting van het cluster en zal binnenkort de mogelijkheid hebben om het cluster omhoog/omlaag te schalen
  • Auto-tune – betere prestaties binnen de bestaande infrastructuur.
  • Auto-heal – los operationele problemen automatisch op (binnenkort beschikbaar).

In deze blog laat ik zien hoe COD eenvoudig kan worden gebruikt als backend systeem om data en afbeeldingen op te slaan voor een eenvoudige webapplicatie. Om deze applicatie te bouwen, gebruiken we Phoenix, een van de onderliggende componenten van COD, samen met Flask. Voor het opslaan van afbeeldingen gebruiken we een HBase (Apache Phoenix backend storage) mogelijkheid genaamd MOB (medium objects). MOB stelt ons in staat om snel waarden van 100k-10MB te lezen/schrijven.

*Voor het gebruiksgemak van de ontwikkeling kunt u in plaats van COD ook de Phoenix-queryserver gebruiken. De queryserver is een kleine build van Phoenix die alleen bedoeld is voor ontwikkelingsdoeleinden en bij elke build worden gegevens verwijderd.

Alle code staat in mijn github-repo.

Instructies:

1. Log in op Cloudera Management Console en selecteer de Operational Database-ervaring

2. Kies uw omgeving en geef uw database een naam

3. Zodra de DB up is, neemt u de URL van de thin JDBC-client

4. Stel uw CDP-wachtwoord voor werkbelasting in

5. Kloon project git repo en installatievereisten:$ pip install -r requirements.txt

6. Ga naar de app-map en voer "setup.py" uit - dit zal een tabel maken met 3 records van gebruikers en hun afbeeldingen $ python setup.py

7. Voer de flask-webserver uit om de webtoepassing te starten:$ FLASK_APP=app.py python -m flask run –port=8888 –host=127.0.0.1  –reload –with-threads –debugger

8. Ga in uw browser naar http://localhost:8888/users. U zou de applicatie moeten kunnen zien draaien! Zo simpel is het.

De code doornemen

1. De Schema-klasse bevat in principe de verbindingsdetails en methoden voor het maken en neerzetten van tabellen. Zoals u kunt zien, is de kolom "foto" een VARBINARY-type, wat zich vertaalt naar een MOB-object in 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 De gebruikersklasse is verantwoordelijk voor alle applicatiebewerkingen met Phoenix. We kunnen beeldtransacties bijwerken/invoegen (upsert in fenikstaal), verwijderen, weergeven en afhandelen:

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. De app.py is de hoofdrouter voor de applicatie. Het bevat alle handelingen met gebruikersinvoer en het routeren ervan naar de verbindingsmethoden. Ik heb de verwerking van afbeeldingen gescheiden voor het gebruiksgemak, en op die manier kan ik een specifieke afbeelding voor een gebruiker krijgen:

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)

Volgende stappen, u kunt deze github-repo gebruiken om uw applicatie te testen.

Ik hoop dat je het nuttig vindt, veel plezier met coderen!!


  1. Top 10 kenmerken van MongoDB Atlas

  2. SQL NULLIF() uitgelegd

  3. Kan module '../build/Release/bson'] niet vinden code:'MODULE_NOT_FOUND' } js-bson:kan c++ bson-extensie niet laden, met pure JS-versie

  4. MongoDB en sluit zich aan