[原]深刻對比數據科學工具箱:Python和R 非結構化數據的結構化

概述

png

在現實場景中,因爲數據來源的異構,數據源的格式每每是難以統一的,這就致使大量具備價值的數據一般是以非結構化的形式聚合在一塊兒的。對於這些非結構化數據,最多見的數據結構就是JSON,而對應的數據庫就是MongoDB。java

利用MongoDB這樣的NoSQL數據庫,咱們能夠把異構的數據源整合到若干個collection中,經過key-value的形式對數據進行增刪改查。雖然MongoDB在數據聚合上有自然的優點,可是在事務處理(OLTP)與數據分析(OLAP)上的表現卻不盡人意。因爲MongoDB自身是一個文檔型數據庫,一方面,MongoDB 並無事務的概念,因此在須要保證數據一致性的場景下並很差用。另外一方面,MongoDB的join查詢也沒有RDBMS來得直觀方便,因此在須要多表關聯查詢的場景下也很是捉急。python

一般,對於小數據集,咱們都會將數據導入到相似MySQL這樣的RDBMS中作進一步的結構化處理,對於大數據集則能夠經過Hive導入到HDFS上。那麼,將MongoDB的非結構化數據導入到RDBMS中的最優方案又是什麼呢?本文將對非結構化數據與結構化數據的管道構建作詳細的討論。mysql

從 Mongo 到 MySQL

iPython

從Mongo遷移數據到MySQL,個人第一個反應是應該寫個腳本,我首先想到了用Python從Mongo讀取數據到內存中而後再批量寫入MySQL。git

這裏,我選擇了使用pymongo。github

%% bash
pip install pymongo
# 這裏不須要安裝 Mongo的client

首先是讀取Mongo數據sql

from pymongo import MongoClient
client = MongoClient('192.168.1.100', 27017)
db = client['tesedb']
posts = db.test_collection
condition = {'_id':'harryzhu'}
result_set = posts.find(condition)
for i in result_set:
    print(i)

這裏因爲python會有中文的問題,我本身定義了一個將unicode轉爲utf-8的函數:mongodb

def getMongoData(data,field):
    if data[field] is None:
        return("")
    else:
        if isinstance(data[field], unicode):
            return(data[field].encode("utf-8"))
        else:
            return(data[field])

接着,準備往MySQL中導入數據數據庫

%% bash
pip install MySQL-python
# 這裏須要安裝 MySQL的client
import MySQLdb
db = MySQLdb.connect("192.168.1.100","root","harryzhu","testdb" )
cursor = db.cursor()

values = r"(\'{id}\',\'{value}\',\'{datetime}\',\'{stock_code}\',\'{share}\')".format(id=getMongoData(i,"_id"),value=getMongoData(i,"value"),datetime=getMongoData(i,"datetime"),stock_code=getMongoData(i,"stock_code"),share=getMongoData(i,"share"))

sql = r"INSERT INTO `FinanceR` (`id`,`value`,`datetime`,`stock_code`,`share`) VALUES " + values

try:
   cursor.execute(sql)
   db.commit()
except:
   db.rollback()

db.close()

從Mongo中讀取的JSON須要在這裏拼接SQL語句是一件用戶體驗很是糟糕的事情,若是有更好的方法歡迎在留言區討論。在嘗試拼接sql 2個小時後,我果斷放棄了用Python導數據的想法。json

R

因爲拼接SQL是很是蛋疼的一件事情,我想到了利用R中的data frame直接完成數據的插入黑魔法。segmentfault

首先,一樣是須要將數據從Mongo中讀取出來.在嘗試使用RMongormongodb以及mongolite以後,我依然選擇了比較古老的RMongo。在使用的過程當中,這三個包都有各自的問題。

rmongodb的教程含糊不清,看了好久都沒有找到調用遠程mongo數據庫的case,而出於jeroenooms大人之手的後起之秀mongolite則在導入數據的時候果斷的丟失了很是關鍵的_id字段,在安裝最新包以後會出現jsonlite依賴包的異常RMongo則在讀取數據時將兩個中文字段混淆成了一個字段,致使整個數據結構錯亂。

三條路子全軍覆沒,這讓我情何以堪,好在使用R的經驗頗豐,經過中文的轉換和切割就輕鬆解決了這個問題。

下面演示一下如何使用RMongo解決Mongo數據的讀取:

install.packages("RMongo")
Sys.setenv("JAVA_HOME"="/usr/bin/java")
library(RMongo)
# 這裏不須要安裝 Mongo的client
library(dplyr)
# 設置數據庫
FinanceR <- RMongo::mongoDbConnect(host="192.168.1.100")
dbShowCollections(FinanceR)

# 設置查詢語句
condition = "{}"
# 獲得返回結果
output <- RMongo::dbGetQuery(FinanceR, collection="portfolio_20160619", condition, skip=0, limit=2)

input <- output %>%
         dplyr::mutate(stock_name1 = iconv(strsplit(iconv(stock_name,from = "utf-8", to = "gbk"),"\100")[[1]][1],from = "gbk",to = "utf-8"))%>%
         dplyr::mutate(portfolio_name = iconv(strsplit(iconv(stock_name,from = "utf-8", to = "gbk"),"\100")[[1]][2],from = "gbk",to = "utf-8"))%>%
         dplyr::select(-stock_name)%>%
         rbind(cum_value="",risk="")

dbDisconnect(FinanceR)

如今,咱們已經把Mongo中的數據成功導入到了內存中,下面將講解如何使用黑魔法直接將整個data frame壓入數據庫。

install.packages("RMySQL")
library(RMySQL)
# 這裏不須要安裝 MySQL的client

con <- RMySQL::dbConnect(RMySQL::MySQL(),
         user="FinanceR", password="FinanceR",
         dbname="FinanceR", host="192.168.1.100")

# 選擇追加,而不是重寫的方式來添加數據,不然數據庫的schema會被重寫         
RMySQL::dbWriteTable(con,input,row.names = FASLE, overwrite = FALSE,
  append = TRUE)
on.exit(dbDisconnect(con))

Shell

Python 和 R 的方式各有利弊,對於Python而言目前簡單粗暴的方式就是SQL拼接,而R則在流水化上比較困難。因此最後轉向尋求Shell命令的方式,經過調用 Mongo client 和 MySQL client 的 API 來完成整個數據的轉化操做。

通過研究發現 Mongo Client 提供了將數據轉成 csv 格式的接口,以後mysql則經過load命令能夠將數據加載到數據庫中。

結論

經過將非結構化數據轉化爲 data frame 後直接壓入 RDBMS,一方面省去了枯燥的SQL拼接,一方面操做又直觀清晰不易出錯,對於小數據集合,直接用這樣的方法增量導入數據不失爲一種好方法,對於批量數據的流水化則採用Shell腳本調用Mongo和MySQL客戶端命令較爲合適。

參考資料

Python MySQL Database Access
R client to interface with MongoDB
python+mongoDB+pymongo常見命令及簡單案例

更優閱讀體驗可直接訪問原文地址:http://www.javashuo.com/article/p-xipwahnj-ev.html
做爲分享主義者(sharism),本人全部互聯網發佈的圖文均聽從CC版權,轉載請保留做者信息並註明做者 Harry Zhu 的 FinanceR專欄:https://segmentfault.com/blog/harryprince,若是涉及源代碼請註明GitHub地址:https://github.com/harryprince。微信號: harryzhustudio商業使用請聯繫做者。

相關文章
相關標籤/搜索