Python & Spark 操作常见数据库整理

Python

mysql

使用pymysql操作,连接主要配置参数:
config = {
'host': "host",
'port': 3306,
'database': "database",
'user': "user",
'password': "password"
}

# 使用pymysql库。
import pymysql

# 配置连接参数
config = {
    'host': "host",
    'port': 3306,
    'database': "database",
    'user': "user",
    'password': "password"
}


# 连接mysql
def mysql_conn(config):
    conn = pymysql.connect(**config)
    return conn


# mysql操作,查询
def get_mysql_data(conn, query: str):
    # 先创建cursor负责操作conn接口
    cursor = conn.cursor()
    try:
        # 执行sql操作,可以使用executemany批量操作
        cursor.execute(query)
        # 返回多个元组,即返回多条记录(rows),如果没有结果,则返回 (),fetchone返回单个记录。
        res = cursor.fetchall()
        cursor.close()
        conn.close()
    except Exception as e:
        print("mysql查询失败")
        cursor.close()
        conn.close()
    return res

# mysql操作,插入


def insert_data(conn, df):
    # 先创建cursor负责操作conn接口
    cursor = conn.cursor()
    # 先构造需要的或是和数据库相匹配的列
    columns = list(df.columns)
    # 可以删除不要的列或者数据库没有的列名
    columns.remove("列名")
    # 重新构造df,用上面的columns,到这里你要保证你所有列都要准备往数据库写入了
    new_df = df[columns].copy()

    # 构造符合sql语句的列,因为sql语句是带有逗号分隔的,(这个对应上面的sql语句的(column1, column2, column3))
    columns = ','.join(list(new_df.columns))

    # 构造每个列对应的数据,对应于上面的((value1, value2, value3))
    data_list = [tuple(i) for i in new_df.values]  # 每个元组都是一条数据,根据df行数生成多少元组数据

    # 计算一行有多少value值需要用字符串占位
    s_count = len(data_list[0]) * "%s,"

    # 构造sql语句
    insert_sql = "insert into " + "数据库表名" + \
        " (" + columns + ") values (" + s_count[:-1] + ")"
    try:
        cursor.executemany(insert_sql, data_list)
        cursor.close()
        conn.close()
    except Exception as e:
        print("mysql插入失败")
        cursor.close()
        conn.close()


if __name__ == '__main__':
    conn = mysql_conn(config)
    query = "select * from database limit 1"
    res = get_mysql_data(conn, query)

    import pandas as pd
    df = pd.DataFrame()
    insert_data(conn, df)

Hbase

使用happybase库,以下代码测试分spark df 和 本地python格式数据写入以及简单读取hbase:

# -*- coding:UTF-8 -*-
import happybase
from pyspark.sql import SparkSession
# 设置日志输出
import logging
s_logger = logging.getLogger('py4j.java_gateway')
s_logger.setLevel(logging.ERROR)

# 设置spark连接方式,local模式可读取本地文件
spark = SparkSession.builder.master("local") \
    .appName("hbase_wr") \
    .getOrCreate()

# happybase操作类
class Happybase_ope:
# 初始化连接参数
    def __init__(self, host="host", timeout=None, table_prefix=None):
        self.connection = happybase.Connection(
            host=host, timeout=timeout, table_prefix=table_prefix)
 # 建表
    def createTable(self, tablename, families):
        self.connection.create_table(tablename, families)
# 连接表
    def table(self, tablename):
        return self.connection.table(tablename)
# 关闭连接
    def close(self):
        self.connection.close()

# spark df 批量写入
def WriteDF(num):
    hpbase = Happybase_ope()
    tbname = 'tbname'
    table = hpbase.table(tbname)
    # 分批写入
    bat = table.batch()
    bat.put(row=num[0][0], data={'info:data': num[0][1]})
    bat.send()
    hpbase.close()

# 写入一条数据
def WriteData(row,data):
    hpbase = Happybase_ope()
    tbname = 'tbname'
    table = hpbase.table(tbname)
    table.put(row=row, data=data)
    hpbase.close()

# 获取数据
def getData():
    hpbase = Happybase_ope()
    tbname = 'tbname'
    table = hpbase.table(tbname)
    # 指定行和列族获取数据
    res = table.row(row="info:data", columns="ent_name_hash_code1")
    return res


if __name__ == '__main__':
    result = spark.read.csv(
        'FilePath',
        header=True)
    
    result_rdd = result.rdd
    result_rdd.zipWithIndex().repartition(
        100).foreach(lambda zipArr: WriteDF(zipArr))

Solr

使用pysolr库连接solr获取数据

import pysolr as pl
solr = pl.Solr('solr查询页面地址',timeout=500000)
# rows为批量读取行数
def get_solr_data(solr,rows=200, timeout=100):
    # 游标
    current_cursor = "*"
    # 状态判断是否还有数据
    has_more = True
    results = []
    # 查询数据数量
    count = solr.search('*:*', **{'fq':'fq'}).hits
    while has_more:
        try:
            result =  solr.search('q', **{'fq':'fq','fl':'fl', "rows": rows,'sort': 'ID asc',
                                         "cursorMark": current_cursor},  timeout=timeout)
            if current_cursor == result.nextCursorMark:
                has_more = False
            else:
                current_cursor = result.nextCursorMark
            if result.docs:
                results.extend(result.docs)
        except Exception as e:
            print(e)
        finally:
            print(str(len(results)) + "/" + str(count))

    return results
data = get_solr_data(solr)

MongoDB

使用Pymongo连接mongo数据库进行增删改查

from pymongo import MongoClient

#创建数据库需要使用 MongoClient 对象,并且指定连接的 URL 地址和要创建的数据库名。
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
#连接数据库
mydb = myclient["testdb"]
#连接表
mycol = mydb["testtabel"]
# 增加数据,mongo插入数据为字典格式,以"_id"为主键,如果插入数据中没有设置"_id",则会自己生成唯一id
mydict = {"name": "test", "sex": "男"}
mylists = [{"name": "test", "sex": "男"},
           {"name": "test1", "sex": "女"}]
# 插入一条数据
mycol.insert_one(mydict) 
# 插入多条数据
mycol.insert_many(mylist)
# 查询数据

# 获取第一条数据
mycol.find_one()

# 获取所有数据,find返回出来的数据是一个迭代器,需for循环使用或转为list等类型。
list(mycol.find())

# 条件查询,指定字典类型查询即可
query = {"name": "test"}
query1 = {"name": "test","sex": "男"}
mycol.find_one(query)
mycol.find_one(query1,{"name":1})  # {"name":1}表示只返回name列
# 修改数据

# 修改匹配到的第一条数据,update方法第一个参数为查询条件,第二个参数为修改字段。
myquery = { "name": "test" }
newvalues = { "$set": { "sex": "nan" } }
mycol.update_one(myquery, newvalues)
# 批量修改用many方法。
mycol.update_many(myquery, newvalues)
# 删除数据

# 条件删除,指定字典类型查询即可
query = {"name": "test"}
query1 = {"name": "test","sex": "男"}
# 删除匹配到的第一条数据
mycol.delete_one(query)
# 删除所有匹配到的数据
mycol.delete_many(query1)
批量更新
# 批量操作
# bulk_write(requests, ordered=True, bypass_document_validation=False, session=None)
# requests:一个包含写操作示例的列表(InsertOne, UpdateOne, UpdateMany, ReplaceOne, DeleteOne, or DeleteMany);
# ordered:表示是否顺序写入,设为True时其中的操作顺序执行,中间出错则后续操作都不会执行;设为False则所有的操作乱序执行,其中一个操作出错其余的操作不会受影响
from pymongo import ReplaceOne
# 一个批量更新方法
def upsert_mongo_data(data,batch_size = 200):
    bulk_list = []
    for da in data:
        doc = {"_id":id;
                "name":da["name"];
                "sex":da["sex"]
        }
        bulk_list.append(ReplaceOne({"_id":doc["_id"]},doc ,upsert = True))
        if len(bulk_list) < batch_size:
            continue
        mycol.bulk_write(bulk_list)
        bulk_list = []
    if bulk_list:
        mycol.bulk_write(bulk_list)
        
mylists = [{"name": "test", "sex": "男"},
           {"name": "test1", "sex": "女"}]

upsert_mongo_data(mylists)

SPARK

kudu

利用sparksession的read和write方法读取以及写入,需要设置用户和kudu表名,读取后数据格式为spark df。

from pyspark.sql import SparkSession

# 设置spark连接方式,local模式可读取本地文件
spark = SparkSession.builder.master("yarn") \
    .appName("xytest") \
    .getOrCreate()

# 读入kudu数据
data = spark.read.format("org.apache.kudu.spark.kudu")
        .option("kudu.table", "impala::test_tabel")
        .option("kudu.master", "master:7051")
        .option("kudu.operation.timeout.ms", "100000")
        .load()
        
# spark df 写入kudu表       
spark_df.write.format('org.apache.kudu.spark.kudu') \
    .option("kudu.table", "impala::test_tabel") \
    .option("kudu.master", "master:7051") \
    .mode('append') \
    .save()

hive

利用sparksession的sql和write方法读取以及写入,可直接读取平台上的hive数据库,读取后数据格式为spark df。

from pyspark.sql import SparkSession

# 设置spark连接方式,local模式可读取本地文件
spark = SparkSession.builder.master("yarn") \
    .appName("xytest") \
    .getOrCreate()

#hive读取,直接spark.sql
data = spark.sql('select * from db.tabel')

# spark df 写入hive表
spark_df.write.format("parquet").mode("overwrite").saveAsTable(hive_tabel)

hbase

有问题,后续解决补充。。。。。。

MongoDB

import os
from pyspark.sql import SparkSession
# set PYSPARK_PYTHON to python36
os.environ['PYSPARK_PYTHON'] = '/usr/bin/python36'
# load mongodb data # 格式是:"mongodb://127.0.0.1:database.collection"
input_uri = "mongodb://127.0.0.1:27017/spark.spark_test"
output_uri = "mongodb://127.0.0.1:27017/spark.spark_test"
# 创建spark,默认使用本地环境,或者"spark://master:7077"
spark = SparkSession.builder.master("local").appName("MyApp") \
        .config("spark.mongodb.input.uri",input_uri) \
        .config("spark.mongodb.output.uri", output_uri) \
        .config('spark.jars.packages', 'org.mongodb.spark:mongo-spark-connector_2.11:2.2.0') \
        .getOrCreate()
#collection:表名    pipeline:查询条件
df_1 = spark.read.format('com.mongodb.spark.sql.DefaultSource') \
        .option("collection", tabel) \
        .option("pipeline", query).load()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容