sql >> Databasteknik >  >> NoSQL >> HBase

Bygga en enkel CRUD-webbapplikation och bildbutik med Cloudera Operational Database och Flask

Cloudera Operational Database (COD) är en hanterad dbPaaS-lösning tillgänglig som en upplevelse i Cloudera Data Platform (CDP). Den erbjuder multimodal klientåtkomst med NoSQL-nyckelvärde med hjälp av Apache HBase API:er och relationell SQL med JDBC (via Apache Phoenix). Det senare gör COD tillgängligt för utvecklare som är vana vid att bygga applikationer som använder MySQL, Postgres, etc. Huvudfördelarna med COD inkluderar:

  • Automatisk skalning – baserat på klustrets arbetsbelastning och kommer snart att ha möjlighet att skala upp/ned i klustret
  • Auto-tune – bättre prestanda inom den befintliga infrastrukturen.
  • Autoläkning – lös driftsproblem automatiskt (kommer snart).

I den här bloggen kommer jag att demonstrera hur COD enkelt kan användas som ett backend-system för att lagra data och bilder för en enkel webbapplikation. För att bygga denna applikation kommer vi att använda Phoenix, en av de underliggande komponenterna i COD, tillsammans med Flask. För att lagra bilder kommer vi att använda en HBase-funktion (Apache Phoenix backend-lagring) som kallas MOB (medium objects). MOB låter oss läsa/skriva värden från 100k-10MB snabbt.

*För enkel utveckling kan du också använda Phoenix frågeserver istället för COD. Frågeservern är en liten version av Phoenix som endast är avsedd för utvecklingsändamål, och data raderas i varje version.

All kod finns i min github-repo.

Instruktioner:

1. Logga in på Cloudera Management Console och välj Operational Database-upplevelse

2. Välj din miljö och namnge din DB

3. När DB är uppe, ta URL:en från den tunna JDBC-klienten

4. Ställ in ditt lösenord för CDP-arbetsbelastning

5. Klona projekt git repo och installationskrav:$ pip install -r requirements.txt

6. Gå till app-mappen och kör “setup.py” – detta skapar en tabell med tre poster över användare och deras bilder $ python setup.py

7. Kör flaskwebbservern för att webbapplikationen ska starta:$ FLASK_APP=app.py python -m flask run –port=8888 –host=127.0.0.1  –reload –with-threads –debugger

8. Gå till http://localhost:8888/users i din webbläsare. Du bör kunna se programmet köra! Enkelt är det.

Gå igenom koden

1. Schema-klassen, innehåller i princip anslutningsdetaljerna och skapa och släpp tabellmetoder. Som du kan se är kolumnen "foto" en VARBINARY-typ, som översätts till ett 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 Användarklassen ansvarar för all applikationsoperation med Phoenix. Vi kan uppdatera/infoga (upsert in phoenix language), radera, lista och hantera bildtransaktioner:

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 är huvudroutern för applikationen. Den innehåller all hantering med användaringångar och dirigering av dem till anslutningsmetoderna. Jag separerade hanteringen av bilder för att underlätta användningen, och på så sätt kan jag få en specifik bild för en användare:

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ästa steg, du kan använda denna github-repo för att testa din applikation.

Hoppas du finner det användbart, Happy coding!!


  1. Big Data Processing Engines – Vilken ska jag använda?:Del 1

  2. vilken är den bästa strategin för att synkronisera data mellan DB och redis cache

  3. Mongodb $där frågan alltid är sann med nodejs

  4. få objekt från redis utan eval?