sql >> Database teknologi >  >> NoSQL >> HBase

Opbygning af en simpel CRUD-webapplikation og billedbutik ved hjælp af Cloudera Operational Database og Flask

Cloudera Operational Database (COD) er en administreret dbPaaS-løsning tilgængelig som en oplevelse i Cloudera Data Platform (CDP). Det tilbyder multimodal klientadgang med NoSQL-nøgleværdi ved hjælp af Apache HBase API'er og relationel SQL med JDBC (via Apache Phoenix). Sidstnævnte gør COD tilgængelig for udviklere, der er vant til at bygge applikationer, der bruger MySQL, Postgres osv. De vigtigste fordele ved COD omfatter:

  • Auto-skalering – baseret på arbejdsbyrdeudnyttelsen af ​​klyngen og vil snart have mulighed for at skalere klyngen op/ned
  • Auto-tune – bedre ydeevne inden for den eksisterende infrastrukturs fodaftryk.
  • Auto-heal – løs driftsproblemer automatisk (kommer snart).

I denne blog vil jeg demonstrere, hvordan COD nemt kan bruges som et backend-system til at gemme data og billeder til en simpel webapplikation. For at bygge denne applikation vil vi bruge Phoenix, en af ​​de underliggende komponenter i COD, sammen med Flask. Til lagring af billeder vil vi bruge en HBase (Apache Phoenix backend storage)-funktion kaldet MOB (medium objects). MOB giver os mulighed for at læse/skrive værdier fra 100k-10MB hurtigt.

*For at gøre det nemmere at bruge, kan du også bruge Phoenix-forespørgselsserveren i stedet for COD. Forespørgselsserveren er en lille build af phoenix, der kun er beregnet til udviklingsformål, og data slettes i hver build.

Al kode er i min github-repo.

Instruktioner:

1. Log ind på Cloudera Management Console, og vælg Operational Database-oplevelsen

2. Vælg dit miljø og navngiv din DB

3. Når DB'en er oppe, skal du tage URL'en fra den tynde JDBC-klient

4. Indstil din adgangskode til CDP-arbejdsbelastning

5. Klon projekt git repo og installationskrav:$ pip install -r requirements.txt

6. Gå til app-mappen og kør "setup.py" – dette vil oprette en tabel med 3 registreringer af brugere og deres billeder $ python setup.py

7. Kør flask-webserveren, så webapplikationen starter:$ FLASK_APP=app.py python -m flask run –port=8888 –host=127.0.0.1  –reload –with-threads –debugger

8. Gå til http://localhost:8888/users på din browser. Du burde kunne se programmet køre! Så enkelt er det.

Gennemgang af koden

1. Skema-klassen,  indeholder grundlæggende forbindelsesdetaljerne og metoder til oprettelse og slip af tabel. Som du kan se, er "foto"-kolonnen en VARBINARY-type, som oversættes til et MOB-objekt i 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 Brugerklassen er ansvarlig for al applikationsdrift med Phoenix. Vi kan opdatere/indsætte (upsert på phoenix-sprog), slette, liste og håndtere billedtransaktioner:

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. App.py er hovedrouteren for applikationen. Den indeholder al håndtering med brugerinput og routing af dem til tilslutningsmetoderne. Jeg adskilte håndteringen af ​​billeder for at gøre det nemmere at bruge, og på den måde kan jeg få et specifikt billede til en bruger:

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)

Næste trin, du kan bruge denne github-repo til at teste din applikation.

Håber du finder det nyttigt, Happy coding!!


  1. Redis er tom efter opstart, selvom der er en .rdb-fil

  2. MongoDB vælg hvor i rækken af ​​_id?

  3. MongoDB - admin bruger ikke autoriseret

  4. Socket.io, Redis Store og IE