第8章應用數據庫python
本章中,咱們將爲讀者介紹各類數據庫及其應用編程接口。這裏所說的數據庫包括關係型數據庫以及非關係型(NoSQL)數據庫。關係型數據庫是由數據表聚集而成的,更重要的是,這些數據表中的數據是按照數據項之間的關係進行組織的。固然,這裏所說的關係,也能夠是某個數據表中的行數據與其餘數據表中的行數據之間的關係。關係型數據庫不只涉及數據表之間的關係,首先,它要處理同一個數據表中不一樣列之間的關係(很明顯,一個數據表內的各列毫無疑問是相關的);其次,它還要處理數據表之間的關係。redis
伴隨着大數據和Web應用的流行,非關係型(Not Only SQL,NoSQL)數據庫也開始野蠻生長。NoSQL系統將成爲類SQL事實上的標準。NoSQL數據庫的主旨在於,使用比關係模型更爲靈活的方式來存儲數據。這就可能意味着,無需數據庫模式或者靈活的數據庫模式。固然,靈活性和速度也是有代價的,例如沒法始終保證事務的一致性。NoSQL數據庫能夠利用面向列的方法以字典的形式來儲存數據,這些數據對象包括文檔、對象、圖、元組,甚至這些對象的組合體。本章將要介紹的主題以下。sql
8.1基於sqlite3的輕量級訪問數據庫
SQLite是一款很是流行的關係型數據庫,它很是輕盈,所以被大量應用程序普遍採納,如Mozilla Firefox等瀏覽器。安卓系統上的大部分應用的數據存儲也是經過SQLite完成的。編程
Sqlite3是Python標準發行版自帶的一個模塊,能夠用於處理SQLite數據庫。使用sqlite3模塊時,數據庫既能夠存放到文件中,也能夠保留在內存中。本例採用後一種方式。下面咱們導入sqlite3,代碼以下。json
import sqlite3
首先,鏈接數據庫。若是但願把數據庫存到文件中,那麼必須提供一個文件名,不然,能夠經過下列方式將數據庫留在內存中。設計模式
with sqlite3.connect(":memory:") as con:
上面使用了Python的with語句。須要注意的是,這個語句依賴於特定上下文管理器類的exit()方法的存在。若是使用了這個語句,咱們就無需顯式關閉數據庫鏈接了。這是由於上下文管理器會自動替咱們關閉鏈接。鏈接到數據庫後,咱們還須要一個遊標。遊標在數據庫中的做用,至少從概念上來說,相似於文本編輯器中的光標。注意,這個遊標也須要由咱們來關閉。api
下面開始建立遊標,代碼以下。瀏覽器
c = con.cursor()
如今,能夠直接建立數據表了。一般,必須首先建立一個數據庫,或數據庫專家已經替咱們創建了一個數據庫。在本章中,咱們不只須要瞭解Python,並且還得懂SQL。SQL是一種專門用來查詢和操做數據庫的語言。限於篇幅,這裏不可能對SQL進行詳盡地介紹。不過,只要稍微努力,讀者就可以掌握基本的SQL。爲了建立數據表,咱們須要向遊標傳遞一個SQL字符串,具體以下。
c.execute('''CREATE TABLE sensors (date text, city text, code text, sensor_id real, temperature real)''')
上面的代碼會建立一個包含不少列的數據表,具體名稱爲sensors。在上面的字符串中,text和real用來代表字符串和數值的類型。經過上面的代碼,咱們就能建立一個可用的數據表了。若是建立過程發生錯誤,咱們就會收到相應的出錯提示。列出數據庫中數據表的方法與數據庫自己緊密相關。一般,有一個或一組專門的數據表來存放用戶數據表的元數據。下面咱們列出SQLite數據表,具體以下。
for table in c.execute("SELECT name FROM sqlite_master WHERE type = 'table'"): print("Table", table[0])
正如所料,咱們將獲得以下的輸出。
Table sensors
如今,咱們要插入並查詢一些隨機數據,具體以下。
1 c.execute("INSERT INTO sensors VALUES ('2016-11-05','Utrecht','Red',42,15.14)") 2 c.execute("SELECT * FROM sensors") 3 print(c.fetchone())
下面咱們輸出插入的記錄。
(u’2016-11-05’, u’Utrecht’, u’Red’, 42.0, 15.14)
當再也不須要某個數據表時,咱們就能夠將其刪除了。須要注意的是,刪除是一項很是危險的操做,所以,咱們必須絕對確定再也用不到這個數據表了。由於數據表一旦被刪,就沒法恢復了,除非以前已經作好了備份。下面的代碼將刪除數據表並顯示刪除操做執行後所剩數據表的數量,具體以下。
1 con.execute("DROP TABLE sensors") 2 print("# of tables", c.execute("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'").fetchone()[0])
輸出內容以下。
# of tables 0
下列代碼摘自本書代碼包中的ch-08.ipynb文件。
1 import sqlite3 2 3 with sqlite3.connect(":memory:") as con: 4 c = con.cursor() 5 c.execute('''CREATE TABLE sensors (date text, city text, code text, sensor_id real, temperature real)''') 6 7 for table in c.execute("SELECT name FROM sqlite_master WHERE type = 'table'"): 8 print("Table", table[0]) 9 10 c.execute("INSERT INTO sensors VALUES ('2016-11-05','Utrecht','Red',42,15.14)") 11 c.execute("SELECT * FROM sensors") 12 print(c.fetchone()) 13 con.execute("DROP TABLE sensors") 14 15 print("# of tables", c.execute("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'").fetchone()[0]) 16 17 c.close()
8.2經過Pandas訪問數據庫
咱們能夠向Pandas提供一個數據庫鏈接,如前面例子中的鏈接或SQLAlchemy鏈接。關於SQLAlchemy鏈接,咱們將在本章後面部分進行講解。正如第7章所述,這裏也要用到statsmodels模塊的太陽黑子活動數據。爲了加載數據,咱們可使用下列代碼。
(1)建立元組列表,以構建Pandas DataFrame。
rows = [tuple(x) for x in df.values]
與以前的示例不一樣,這裏要建立的是一個未規定數據類型的數據表,代碼以下。
con.execute("CREATE TABLE sunspots(year, sunactivity)")
(2)咱們知道,executemany()方法能夠執行多條語句。就本例而言,咱們要插入一些記錄,這些記錄來自元組列表。下面將這些數據行插入數據表並顯示行數。
1 con.executemany("INSERT INTO sunspots(year, sunactivity) VALUES (?, ?)", rows) 2 c.execute("SELECT COUNT(*) FROM sunspots") 3 print(c.fetchone())
數據表的行數以下。
(309,)
(3)execute()函數返回結果中rowcount屬性存放的是受影響的數據行的數量。這個屬性有點古怪,並且與SQLite版本密切相關。另外,就像上面代碼中看到的那樣,SQL查詢是無歧義的。下面咱們刪除事件數大於20的記錄,代碼以下。
print("Deleted", con.execute("DELETE FROM sunspots where sunactivity > 20").rowcount, "rows")
結果以下。
Deleted 217 rows
(4)若是把數據庫鏈接至Pandas,就能夠利用read_sql()函數來執行查詢並返回Pandas DataFrame了。下面選擇前1732條記錄,代碼以下。
print(read_sql("SELECT * FROM sunspots where year < 1732", con))
最終獲得以下Pandas DataFrame。
year sunactivity
0 1700.0 5.0
1 1701.0 11.0
2 1702.0 16.0
3 1707.0 20.0
4 1708.0 10.0
5 1709.0 8.0
6 1710.0 3.0
7 1711.0 0.0
8 1712.0 0.0
9 1713.0 2.0
10 1714.0 11.0
11 1723.0 11.0
如下代碼摘自本書代碼包中的ch-08.ipynb文件。
1 import statsmodels.api as sm 2 from pandas.io.sql import read_sql 3 import sqlite3 4 5 with sqlite3.connect(":memory:") as con: 6 c = con.cursor() 7 8 data_loader = sm.datasets.sunspots.load_pandas() 9 df = data_loader.data 10 rows = [tuple(x) for x in df.values] 11 12 con.execute("CREATE TABLE sunspots(year, sunactivity)") 13 con.executemany("INSERT INTO sunspots(year, sunactivity) VALUES (?, ?)", rows) 14 c.execute("SELECT COUNT(*) FROM sunspots") 15 print(c.fetchone()) 16 print("Deleted", con.execute("DELETE FROM sunspots where sunactivity > 20").rowcount, "rows") 17 18 print(read_sql("SELECT * FROM sunspots where year < 1732", con)) 19 con.execute("DROP TABLE sunspots") 20 21 c.close()
8.3SQLAlchemy
SQLAlchemy以基於設計模式(design pattern)的對象關係映射(ORM)而聞名。也就是說,它能夠把Python的類映射爲數據庫的數據表。實際上,這意味着添加了一個額外的抽象層,所以,咱們須要使用SQLAlchemy應用程序接口來跟數據庫打交道,而非使用SQL命令。使用SQLAlchemy的好處是,它可以在幕後替咱們處理各類細節。不過,凡事有利皆有弊,使用SQLAlchemy的缺點是咱們不得不學習其應用程序接口,同時,性能也會有所降低。本節將學習如何安裝SQLAlchemy以及如何經過SQLAlchemy填充和查詢數據庫。
8.3.1 SQLAlchemy的安裝和配置
下面是安裝SQLAlchemy所需的命令。
$ pip3 install sqlalchemy
在編寫本書時,SQLAlchemy的最新版本是1.3.15。從其官網能夠找到SQLAlchemy的安裝程序和代碼倉庫。
此外,SQLAlchemy還有一個支持頁面,在使用SQLAlchemy的時候,須要定義一個超類,代碼以下。
1 from sqlalchemy.ext.declarative import declarative_base 2 Base = declarative_base()
本節及後面幾節中會使用一個帶有兩個數據表的小型數據庫,其中第1個數據表是關於觀測站的,第2個數據表是描述觀測站內的傳感器的。每一個觀測站能夠有0個、1個或者多個傳感器,其中,每一個觀測站都有一個整數ID,這些數字是由數據庫自動生成的。此外,每一個觀測站都有一個名稱,並且這個名稱是惟一的,也是強制性的。
同時,每一個傳感器也有本身的整數ID。咱們將記錄傳感器的最後一次觀察值。這個值能夠是觀測值的倍數。具體狀況讀者能夠參考本書代碼包中的ch-08.ipynb代碼。注意,咱們沒必要直接運行這個腳本,由於它是供其餘腳本使用的。
1 from sqlalchemy import Column, ForeignKey, Integer, String, Float 2 from sqlalchemy.ext.declarative import declarative_base 3 from sqlalchemy.orm import relationship 4 from sqlalchemy import create_engine 5 from sqlalchemy import UniqueConstraint 6 7 Base = declarative_base() 8 class Station(Base): 9 __tablename__ = 'station' 10 id = Column(Integer, primary_key=True) 11 name = Column(String(14), nullable=False, unique=True) 12 13 def __repr__(self): 14 return "Id=%d name=%s" %(self.id, self.name) 15 16 class Sensor(Base): 17 __tablename__ = 'sensor' 18 id = Column(Integer, primary_key=True) 19 last = Column(Integer) 20 multiplier = Column(Float) 21 station_id = Column(Integer, ForeignKey('station.id')) 22 station = relationship(Station) 23 24 def __repr__(self): 25 return "Id=%d last=%d multiplier=%.1f station_id=%d" 26 # %(self.id, self.last, self.multiplier, self.station_id) 27 28 if __name__ == "__main__": 29 print("This script is used by code further down in this notebook.")
8.3.2 經過SQLAlchemy填充數據庫
數據表的建立將在後面介紹。本節先來準備一個腳本,以便用來填充數據庫(注意,不用直接運行這個腳本,由於它是供8.3.3節中的腳本使用的)。經過DBSession對象,能夠向數據表中插入數據。固然,咱們還須要一個引擎,不過,引擎的建立方法也留到8.3.3節介紹。
1. 建立DBSession對象,代碼以下。
1 Base.metadata.bind = engine 2 3 DBSession = sessionmaker(bind=engine) 4 session = DBSession()
2. 建立兩個觀測站。
1 de_bilt = Station(name='De Bilt') 2 session.add(de_bilt) 3 session.add(Station(name='Utrecht')) 4 session.commit() 5 print("Station", de_bilt)
在提交這個會話前,這些數據行是不會被插入的。下面是與第一個觀測站有關的輸出。
Station Id=1 name=De Bilt
3.一樣,還要插入傳感器記錄,代碼以下。
1 temp_sensor = Sensor(last=20, multiplier=.1, station=de_bilt) 2 session.add(temp_sensor) 3 session.commit() 4 print("Sensor", temp_sensor)
這個傳感器位於第一個觀察站中,因此,將獲得以下輸出內容。
Sensor Id=1 last=20 multiplier=0.1 station_id=1
數據庫填充代碼能夠在本書代碼包中的ch-08.ipynb文件中找到。一樣,這個腳本也無需直接運行,它也是供其餘腳本使用的。填充代碼以下。
1 from sqlalchemy import create_engine 2 from sqlalchemy.orm import sessionmaker 3 4 #from alchemy_entities import Base, Sensor, Station 5 6 def populate(engine): 7 Base.metadata.bind = engine 8 9 DBSession = sessionmaker(bind=engine) 10 session = DBSession() 11 12 de_bilt = Station(name='De Bilt') 13 session.add(de_bilt) 14 session.add(Station(name='Utrecht')) 15 session.commit() 16 print("Station", de_bilt) 17 18 temp_sensor = Sensor(last=20, multiplier=.1, station=de_bilt) 19 session.add(temp_sensor) 20 session.commit() 21 print("Sensor", temp_sensor) 22 23 if __name__ == "__main__": 24 print("This script is used by code further down in this notebook")
8.3.3 經過SQLAlchemy查詢數據庫
下面經過URI來建立引擎,代碼以下。
1 engine = create_engine('sqlite:///demo.db')
經過這個URI,咱們規定要使用的引擎爲SQLite,同時指出要把數據存放到文件demo.db中。而後,利用剛纔建立的引擎來建立兩個數據表,即station和sensor。相應代碼以下。
1 Base.metadata.create_all(engine)
對於SQLAlchemy查詢,咱們也須要一個DBSession對象,這個對象在8.3.2節已經介紹過了。
下面選擇數據表station中的第一行數據。
1 station = session.query(Station).first()
下面代碼用於選擇全部觀測站,具體以下。
1 print("Query 1", session.query(Station).all())
下面是輸出結果。
Query 1 [Id=1 name=De Bilt, Id=2 name=Utrecht]
選擇全部傳感器,代碼以下。
1 print("Query 2", session.query(Sensor).all())
下面是輸出結果。
Query 2 [Id=1 last=20 multiplier=0.1 station_id=1]
下面,選擇第一個觀測站的第一個傳感器,代碼以下。
1 print("Query 3", session.query(Sensor).filter(Sensor.station == station).one())
下面是輸出結果。
Query 3 Id=%d last=%d multiplier=%.1f station_id=%d
還可使用pandas的read_sql()方法進行查詢,具體以下。
1 print(read_sql("SELECT * FROM station", engine.raw_connection()))
輸出內容以下。
id name 0 1 De Bilt 1 2 Utrecht
如下代碼摘自本書代碼包中的ch-08.ipynb文件。
1 #from alchemy_entities import Base, Sensor, Station 2 #from populate_db import populate 3 from sqlalchemy import create_engine 4 from sqlalchemy.orm import sessionmaker 5 import os 6 from pandas.io.sql import read_sql 7 8 9 engine = create_engine('sqlite:///demo.db') 10 Base.metadata.create_all(engine) 11 populate(engine) 12 Base.metadata.bind = engine 13 DBSession = sessionmaker() 14 DBSession.bind = engine 15 session = DBSession() 16 17 station = session.query(Station).first() 18 19 print("Query 1", session.query(Station).all()) 20 print("Query 2", session.query(Sensor).all()) 21 print("Query 3", session.query(Sensor).filter(Sensor.station == station).one()) 22 print(read_sql("SELECT * FROM station", engine.raw_connection())) 23 24 try: 25 os.remove('demo.db') 26 print("Deleted demo.db") 27 except OSError: 28 pass
8.4Pony ORM
Pony ORM是Python編程語言下的另外一款ORM程序包。Pony ORM是用純Python編寫的,它能自動進行查詢優化,同時提供了一個圖形用戶界面的數據庫模式編輯器。此外,它還支持自動事務處理、自動緩存和組合關鍵字(Composite Keys)。有了Pony ORM,咱們就能夠經過Python的生成器表達式來查詢數據庫了。固然,這些生成器最終都會轉換爲SQL。
安裝這個程序庫的命令以下。
1 $ pip3 install pony
本例中咱們將用到這個程序包,所以須要將其導入。下面的導入代碼摘自本書代碼包中的pony_ride.py文件。
1 from pony.orm import * 2 # database,db_session 3 import statsmodels.api as sm
下面咱們來建立一個in-memory型的SQLite數據庫。
1 db = Database('sqlite', ':memory:', create_db = True)
下面經過Pandas的write_frame()函數來加載太陽黑子數據並將其寫入數據庫。具體代碼以下。
1 with db_session: 2 data_loader = sm.datasets.sunspots.load_pandas() 3 df = data_loader.data 4 df.to_sql("sunspots", db.get_connection()) 5 6 print(db.select(" count(*) from sunspots"))
這個太陽黑子數據表的行數以下。
[309]
8.5Dataset:懶人數據庫
Dataset是一個Python庫,實際上就是SQLAlchemy的一個包裝器。這個庫的開發主旨是儘可能作到易於使用,也就是儘可能讓懶人滿意。
安裝dataset的命令以下。
$ pip3 install dataset
建立並鏈接一個in-memory型的SQLite數據庫,代碼以下。
1 import dataset 2 3 db = dataset.connect('sqlite:///:memory:')
建立一個名爲books的數據表,代碼以下。
1 table = db["books"]
事實上,在數據庫中這個表還沒有建立,由於咱們尚未爲其指定任何列。咱們只是建立了一個相關的對象。咱們調用insert()方法時,會自動建立數據表模式,同時,向insert()方法傳遞含有書名的字典,具體代碼以下。
1 table.insert(dict(title="NumPy Beginner's Guide", author='Ivan Idris')) 2 table.insert(dict(title="NumPy Cookbook", author='Ivan Idris')) 3 table.insert(dict(title="Learning NumPy", author='Ivan Idris'))
經過下列代碼,能夠顯示數據表各行的內容。
1 for row in table.find(_limit=5): 2 print(row)
結果以下。
id title author 0 1 NumPy Beginner's Guide Ivan Idris 1 2 NumPy Cookbook Ivan Idris 2 3 Learning NumPy Ivan Idris OrderedDict([('index', 0), ('YEAR', 1700.0), ('SUNACTIVITY', 5.0)]) OrderedDict([('index', 1), ('YEAR', 1701.0), ('SUNACTIVITY', 11.0)]) OrderedDict([('index', 2), ('YEAR', 1702.0), ('SUNACTIVITY', 16.0)]) OrderedDict([('index', 3), ('YEAR', 1703.0), ('SUNACTIVITY', 23.0)]) OrderedDict([('index', 4), ('YEAR', 1704.0), ('SUNACTIVITY', 36.0)])
如今,咱們能夠輕鬆顯示該數據庫中各個數據表了,代碼以下。
1 print("Tables", db.tables)
上述代碼的輸出結果以下。
Tables ['books', 'sunspots']
下面的代碼摘自本書代碼包中的ch-08.ipynb文件。(邀月修正「AttributeError: 'Connection' object has no attribute 'raw_connection'」錯誤)
1 import dataset 2 from pandas.io.sql import read_sql 3 from pandas.io.sql import to_sql 4 import statsmodels.api as sm 5 6 db = dataset.connect('sqlite:///:memory:') 7 table = db["books"] 8 table.insert(dict(title="NumPy Beginner's Guide", author='Ivan Idris')) 9 table.insert(dict(title="NumPy Cookbook", author='Ivan Idris')) 10 table.insert(dict(title="Learning NumPy", author='Ivan Idris')) 11 12 # print(help(db.executable)) 13 14 # print(read_sql('SELECT * FROM books', db.executable.raw_connection()) ) 15 # print(read_sql('SELECT * FROM books', db.executable.contextual_connect()) ) 16 print(read_sql('SELECT * FROM books', db.engine) ) 17 18 data_loader = sm.datasets.sunspots.load_pandas() 19 df = data_loader.data 20 #write_frame(df, "sunspots", db.executable.raw_connection()) 21 # df.to_sql("sunspots", db.executable.contextual_connect()) 22 df.to_sql("sunspots", db.engine) 23 24 25 table = db['sunspots'] 26 27 for row in table.find(_limit=5): 28 print(row) 29 30 print("Tables", db.tables)
tips:
一、原書中print(read_sql('SELECT * FROM books', db.executable.raw_connection()) )引起AttributeError: 'Connection' object has no attribute 'raw_connection'
二、改用print(read_sql('SELECT * FROM books', db.executable.contextual_connect()) )不報錯,但會引起一個警告,大意是:SADeprecationWarning: The Engine.contextual_connect() and Connection.contextual_connect() methods are deprecated. This method is an artifact of the threadlocal engine strategy which is also to be deprecated. For explicit connections from an Engine, use the Engine.connect() method
三、最後使用print(read_sql('SELECT * FROM books', db.engine) )正常運行。
8.6PyMongo與MongoDB
MongoDB是一個面向文檔的NoSQL數據庫,其名稱取自humongous一詞,即碩大無比之意,其中,文檔將以相似JSON的BSON格式進行存儲。咱們能夠下載MongoDB,安裝過程很是簡單,咱們只需將壓縮文件解壓便可。創做本書時,這個程序庫的版本爲3.4.0。這個版本的bin目錄下面有一個名爲mongod的文件,用來啓動服務器。MongoDB位於/data/db目錄下面,該目錄就是存儲數據的地方。固然,能夠經過下列命令來指定其餘目錄。
$ mkdir /tmp/db
進入存放數據庫二進制可執行代碼的目錄並啓動數據庫,命令以下。
./mongod –dbpath /tmp/db
這個進程須要一直運行,這樣咱們才能查詢數據庫。
PyMongo是MongoDB的Python驅動程序,這個程序的安裝方法以下。
1 $ pip3 install pymongo
與MongoDB的測試數據庫創建鏈接,代碼以下。
1 from pymongo import MongoClient 2 3 client = MongoClient() 4 db = client.test_database
別忘了,咱們是能夠利用pandas DataFrame來建立JSON的。下面建立JSON並將其存於MongoDB中,代碼以下。
1 data_loader = sm.datasets.sunspots.load_pandas() 2 df = data_loader.data 3 rows = json.loads(df.T.to_json()).values() 4 db.sunspots.insert_many(rows)
如今,咱們來查詢剛纔建立的文檔。
1 cursor = db['sunspots'].find({}) 2 df = pd.DataFrame(list(cursor)) 3 print(df)
這將打印輸出整個pandas DataFrame。下列代碼摘自本書代碼包中的ch-08.ipynb文件。
1 from pymongo import MongoClient 2 import statsmodels.api as sm 3 import json 4 import pandas as pd 5 6 client = MongoClient() 7 db = client.test_database 8 9 data_loader = sm.datasets.sunspots.load_pandas() 10 df = data_loader.data 11 rows = json.loads(df.T.to_json()).values() 12 db.sunspots.insert_many(rows) 13 14 cursor = db['sunspots'].find({}) 15 df = pd.DataFrame(list(cursor)) 16 print(df) 17 18 db.drop_collection('sunspots')
注意:因邀月本機無MongoDB,因此未運行本實例,若有報錯,請告知。謝謝!
8.7利用Redis存儲數據
Redis是一個in-memory型的鍵-值數據庫,由C語言編寫而成。Redis這個名稱源自Remote Dictionary Server,即遠程字典服務器。處於內存存儲模式時,Redis的速度快得驚人,並且讀寫操做的速度幾乎同樣快。Redis遵循發佈訂閱模式而且經過Lua腳原本處理存儲過程。發佈訂閱模式經過客戶端可訂閱的信道來接收消息。創做本書時的Redis最新版本爲3.2.6,咱們能夠下載Redis。完成安裝以後,咱們就能夠經過如下命令來運行服務器了。
1 $ src/redis-server
下面開始安裝一個Python驅動程序,命令以下。
1 $ pip3 install redis
Redis的使用很是簡便,只要把它看成一個龐大的字典便可。不過,Redis也有自身的侷限性。有時,它的易用性僅僅體如今將複雜的對象存儲爲JSON字符串或其餘格式。這正是咱們聯合使用Pandas DataFrame的緣由。下面,咱們與Redis創建鏈接,代碼以下。
1 r = redis.StrictRedis()
經過JSON字符串建立一個鍵-值對,代碼以下。
1 r.set('sunspots', data)
經過下列代碼檢索數據。
1 blob = r.get('sunspots')
下面的代碼很是簡單,它們摘自本書代碼包中的ch-08.ipynb文件。
1 import redis 2 import statsmodels.api as sm 3 import pandas as pd 4 5 r = redis.StrictRedis() 6 data_loader = sm.datasets.sunspots.load_pandas() 7 df = data_loader.data 8 data = df.T.to_json() 9 r.set('sunspots', data) 10 blob = r.get('sunspots') 11 print(pd.read_json(blob))
注意:因邀月本機無Redis,因此未運行本實例,若有報錯,請告知。謝謝!
8.8利用memcache存儲數據
與Redis相似,memcache也是一個in-memory型的鍵-值數據庫。在安裝運行memcache服務器以後,就能夠經過下列命令來安裝memcache的Python客戶端了。
1 $ pip3 install python3-memcache
下面的代碼摘自ch-08.ipynb文件,它將建立一個memcache客戶端,而後將DataFrame存儲到Memcache,其中自動過時值爲600秒。這段代碼與前面介紹Redis時看到的代碼很是類似。
1 import memcache 2 import statsmodels.api as sm 3 import pandas as pd 4 5 client = memcache.Client([('127.0.0.1', 11211)]) 6 data_loader = sm.datasets.sunspots.load_pandas() 7 df = data_loader.data 8 data = df.T.to_json() 9 client.set('sunspots', data, time=600) 10 print("Stored data to memcached, auto-expire after 600 seconds") 11 blob = client.get('sunspots') 12 print(pd.read_json(blob))
注意:因邀月本機無memcache,因此未運行本實例,若有報錯,請告知。謝謝!
8.9Apache Cassandra
Apache Cassandra是結合了鍵-值和傳統關係型數據庫特性的混合型數據庫。對於傳統的關係型數據庫而言,數據表中的列是固定的。但是,對於Cassandra來講,同一個數據表中的各行能夠具備不一樣的列。從這個角度看,Cassandra是一種面向列的數據庫,由於它容許各行靈活使用不一樣的模式。這個數據庫中的各列,都是按照所謂的列族(Column Family)進行組織的,這裏的列族至關於關係型數據庫中的數據表。Cassandra數據庫已經摒棄了各類鏈接和子查詢操做。讀者能夠自行下載Cassandra。在本書寫做時,這個數據庫的最新版本是3.9。
(1) 從命令行運行服務器,命令以下。
1 $ bin/cassandra-f
(2)能夠建立conf/cassandra.yaml中列出的目錄,或者進行以下的調整。
1 data_file_directories:/tmp/lib/cassandra/data 2 commitlog_directory: /tmp/lib/cassandra/commitlog 3 saved_caches_directory: /tmp/lib/cassandra/saved_caches
(3)若是不想保存某些數據,能夠考慮下列命令。
1 $ mkdir -p /tmp/lib/cassandra/data 2 $ mkdir -p /tmp/lib/cassandra/commitlog 3 $ mkdir -p /tmp/lib/cassandra/saved_caches
(4)下面安裝Python驅動程序,命令以下。
1 $ pip3 install cassandra-driver
(5)下面開始編寫代碼。首先,與集羣創建鏈接並建立一個會話,代碼以下。
1 cluster = Cluster() 2 session = cluster.connect()
(6)在Cassandra中,有一個所謂的keyspace的概念,它實際上就是用來存放數據表的一個容器。Cassandra創建了本身的查詢語言,名爲Cassandra查詢語言(Cassandra Query Language,CQL)。CQL的用法與SQL相似。下面建立keyspace並設置使用該keyspace的會話,代碼以下。
1 session.execute("CREATE KEYSPACE IF NOT EXISTS mykeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };") 2 session.set_keyspace('mykeyspace')
(7)如今,建立一個數據表來存放太陽黑子數據,代碼以下。
1 session.execute("CREATE TABLE IF NOT EXISTS sunspots (year decimal PRIMARY KEY, sunactivity decimal);")
(8)建立一條語句,該語句將在循環語句中把元組做爲數據行來插入,代碼以下。
1 query = SimpleStatement( 2 "INSERT INTO sunspots (year, sunactivity) VALUES (%s, %s)", 3 consistency_level=ConsistencyLevel.QUORUM)
(9)下列代碼用於插入數據。
1 for row in rows: 2 session.execute(query, row)
(10)取得數據表中數據的行數。
1 rows=session.execute("SELECT COUNT(*) FROM sunspots") 2 for row in rows: 3 print(row)
輸出的行數以下。
[Row(count=309)]
(11)刪除keyspace,關閉集羣。
1 session.execute('DROP KEYSPACE mykeyspace') 2 cluster.shutdown()
下列代碼摘自本書代碼包中的ch-08.ipynb文件。
1 from cassandra import ConsistencyLevel 2 from cassandra.cluster import Cluster 3 from cassandra.query import SimpleStatement 4 import statsmodels.api as sm 5 6 cluster = Cluster() 7 session = cluster.connect() 8 session.execute("CREATE KEYSPACE IF NOT EXISTS mykeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };") 9 session.set_keyspace('mykeyspace') 10 session.execute("CREATE TABLE IF NOT EXISTS sunspots (year decimal PRIMARY KEY, sunactivity decimal);") 11 12 query = SimpleStatement( 13 "INSERT INTO sunspots (year, sunactivity) VALUES (%s, %s)", 14 consistency_level=ConsistencyLevel.QUORUM) 15 16 data_loader = sm.datasets.sunspots.load_pandas() 17 df = data_loader.data 18 rows = [tuple(x) for x in df.values] 19 for row in rows: 20 session.execute(query, row) 21 22 rows=session.execute("SELECT COUNT(*) FROM sunspots") 23 for row in rows: 24 print(row) 25 26 session.execute('DROP KEYSPACE mykeyspace') 27 cluster.shutdown()
注意:因邀月本機無Cassandra,因此未運行本實例,若有報錯,請告知。謝謝!
8.10小結
咱們能夠把年度太陽黑子周期數據存儲在不一樣的數據庫中,包括關係型數據庫和NoSQL數據庫。
這裏所謂的關係,不只限於數據表之間的關係,首先,它與一個數據表內部各列之間的關係有關;其次,它還涉及數據表之間的關係。
實際上,咱們能夠經過Python的標準模塊sqlite3來跟SQLite數據庫打交道。咱們能夠經過pandas與SQLite數據庫或SQLAlchemy數據庫來創建鏈接。
SQLAlchemy以其基於設計模式的ORM而聞名天下,經過這個庫,能夠把Python的類映射爲數據庫的數據表。實際上,ORM模式是一種通用的架構模式,所以一樣適用於其餘各類面向對象程序設計語言。SQLAlchemy將使用數據庫的各類技術細節剝離出去,有了它,咱們甚至連SQL都不用寫了。
MongoDB是一個面向文檔的數據倉庫,能夠存放巨量的數據。
進入in-memory模式後,Redis不只運行速度極快,並且寫操做也幾乎與讀操做同樣快。Redis是一個鍵-值型數據倉庫,功能上與Python的字典相仿。
Apache Cassandra不只具備鍵-值數據庫的特性,同時還具有傳統的關係型數據庫特性。這是一種面向列的數據庫,它的各個列都以列族的形式組織在一塊兒,這裏的列族至關於關係型數據庫中的數據表。在Apache Cassandra數據庫中,數據行已經擺脫了特定列組合的束縛。
第9章將介紹純文本數據的分析技術,由於純文本數據在各個組織和互聯網上隨處可見。通常來講,純文本數據的非結構化程度都很高,與處理已經清洗並製表的數據相比,分析純文本數據須要使用一些大相徑庭的方法。爲了分析這類數據,咱們須要藉助另外一個開源Python程序包,即NLTK。NLTK發展得已經很是完備,並且自身備有相應的數據集。
第8章完。
隨書源碼官方下載:
https://www.ptpress.com.cn/shopping/buy?bookId=bae24ecb-a1a1-41c7-be7c-d913b163c111
須要登陸後免費下載。