實體、屬性和金鑰

注意:強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫;相較於此用戶端程式庫,NDB 用戶端程式庫有幾項優點,例如能透過 Memcache API 自動快取實體。如果您目前使用的是舊版 DB 用戶端程式庫,請參閱 DB 至 NDB 遷移指南

Cloud Datastore 中的資料物件又稱為「實體」。實體具有一項或多項命名「屬性」,每個屬性可以有一個或多個值。相同種類的實體不需要具有相同屬性,而指定屬性的實體值不需要全都屬於相同的資料類型。(如有必要,應用程式可在本身的資料模型內建立這類限制並強制執行)。

Cloud Datastore 支援各種屬性值的資料類型。這些資料類型列舉如下:

  • 整數
  • 浮點數
  • 字串
  • 日期
  • 二進位資料

如需這些類型的完整清單,請參閱屬性和值類型

Cloud Datastore 中每個實體都有專屬的識別「金鑰」。該金鑰是由以下元件組成:

  • 實體的「命名空間」,可允許多租戶架構
  • 實體的種類,可將實體分類以便進行 Cloud Datastore 查詢
  • 個別實體的 ID,可以是以下其中之一:
    • 「金鑰名稱」字串
    • 整數「數字 ID」
  • 選用的祖系路徑,可在 Cloud Datastore 階層之中找到實體的位置

應用程式可使用實體金鑰從 Cloud Datastore 擷取個別實體,或依據實體金鑰或屬性值發佈「查詢」,以擷取一個或多個實體。

Python App Engine SDK 含有資料模型程式庫,會將 Cloud Datastore 實體以 Python 類別執行個體的形式呈現,也會在 Datastore 中儲存並擷取這些執行個體。

Cloud Datastore 本身不會在實體結構上強制執行任何限制 (例如指定屬性是否具有特定類型的值),這種工作會留給應用程式與資料模型程式庫負責執行。

種類及 ID

每個 Cloud Datastore 實體都屬於特定「種類」,可將實體分門別類,方便查詢。舉例來說,人力資源應用程式能用 Employee 種類的實體來代表公司的每位員工。在 Python Datastore API 中,實體的種類是由「模型類別」決定,由您在應用程式中將此類別定義為資料模型程式庫 db.Model 的子類別。模型類別的名稱即成為屬於該類別的實體的種類。以兩條底線 (__) 為開頭的所有種類名稱均保留,且不得使用。

以下範例會建立 Employee 種類的實體,填入屬性值,並將實體儲存到 Datastore:

import datetime
from google.appengine.ext import db

class Employee(db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  hire_date = db.DateProperty()
  attended_hr_training = db.BooleanProperty()

employee = Employee(first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

Employee 類別會宣告四種資料模型屬性:first_namelast_namehire_dateattended_hr_trainingModel 父類別會確保 Employee 物件的屬性符合此模型,例如,嘗試指派字串值至 hire_date 屬性時,會導致出現執行階段的錯誤,因為 hire_date 的資料模型已宣告為 db.DateProperty

除了種類以外,每個實體在建立時都會指派到「ID」。因為 ID 屬於實體金鑰的一部分,所以會與實體建立永久的關聯,且無法變更。ID 可利用兩種方式指派:

  • 您的應用程式可以指定自身的實體「金鑰名稱」字串。
  • 可讓 Cloud Datastore 自動指派一個整數的「數字 ID」給實體。

如果要指派金鑰名稱給實體,請在建立實體時,提供命名引數 key_name 給模型類別建構函式:

# Create an entity with the key Employee:'asalieri'.
employee = Employee(key_name='asalieri')

如果要讓 Cloud Datastore 自動指派數字 ID,請省略 key_name 引數:

# Create an entity with a key such as Employee:8261.
employee = Employee()

指派 ID

可使用兩種不同的自動 ID 政策來設定 Cloud Datastore,以產生自動 ID:

  • default 政策可產生隨機順序的未使用 ID,近乎均勻分佈。每個 ID 最長可達 16 位數。
  • legacy 政策可建立較小整數 ID 的非連續序列。

如果您要向使用者顯示實體 ID,並/或依據 ID 順序顯示,最理想的方式就是使用手動分配。

Cloud Datastore 會產生隨機順序的未使用 ID,近乎均勻分佈。每個 ID 最長可達 16 位數。

系統分配的 ID 值可確保不和實體群組重複。如果您要將實體群組或命名空間中的某個實體複製到其他的實體群組或命名空間,且希望保留金鑰的 ID 部分,請務必先分配好 ID,以免 Cloud Datastore 選取該 ID 用於日後的指派作業。

祖系路徑

Cloud Datastore 中的實體會形成階層結構空間,與檔案系統的目錄結構相似。建立實體時,可選擇將其他實體指定為「父系」;新實體則為父系實體的「子系」(請注意,不同於檔案系統,父系實體不需要實際存在)。沒有父系的實體則是「根實體」。 實體與父系實體之間的關聯是永久的,一旦實體建立後就無法變更。Cloud Datastore 絕對不會將相同的數字 ID 指派給相同父系的兩個實體,也不會指派給兩個根實體 (即沒有父系的實體)。

任何實體的父系、父系的父系等等以此類推,都是這個實體的「祖系」;實體的子系、子系的子系等等都屬於「後代」。 根實體及所有子系都屬於相同的「實體群組」。 從根實體開始,再從父系到子系,最後到指定實體的實體序列,構成該實體的「祖系路徑」。 用於識別實體的完整金鑰,其中包含一系列用於指定祖系路徑的種類-識別碼組合,並會以實體本身的種類-識別碼組合作結。

[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]

根實體的祖系路徑為空白,且金鑰僅包含實體本身的種類與 ID。

[Person:GreatGrandpa]

本概念以下圖說明:

實體群組

如果要指定實體的父系,請在建立子系實體時,在模型類別建構函式中使用 parent 引數。此引數的值可以是父系實體本身的值,也可以是父系實體的金鑰值;可透過呼叫父系實體的 key() 方法來取得金鑰。下列範例會建立 Address 種類的實體,並示範指定 Employee 實體作為父系的兩種方法:

# Create Employee entity
employee = Employee()
employee.put()

# Set Employee as Address entity's parent directly...
address = Address(parent=employee)

# ...or using its key
e_key = employee.key()
address = Address(parent=e_key)

# Save Address entity to datastore
address.put()

交易和實體群組

每次嘗試建立、更新或刪除實體時,都是在交易的背景下進行。單一交易可包含的前述作業數量不受限制。為了維持資料一致性,交易會確保其中所有作業均以單元方式套用至 Cloud Datastore,如有任何作業失敗,則不會套用任何作業。此外,在相同交易內執行的所有同步一致性讀取作業 (祖系查詢或是「get」) 將出現一致的資料快照。

如以上所述,實體群組是透過祖系連接至共同根元素的一組實體。將資料組織為實體群組,即可限制執行的交易類型:

  • 一項交易所存取的所有資料,最多只能包含於 25 個實體群組中。
  • 如果您想在交易中使用查詢,必須將資料組織成實體群組,如此才能指定使用能比對出正確資料的祖系篩選器。
  • 單一實體群體中,一項交易每秒寫入總處理量有限制。有此限制是因為 Cloud Datastore 會執行每個實體群組的對等同步複製作業,此作業橫跨廣大的地理區域,以提供高度的可靠性和容錯能力。

許多應用程式在廣為取得不相關資料時,可以接受使用最終一致性,(例如:跨多個實體群組的非祖系查詢,有時此類查詢會傳回稍微過時的資料),再於查看或編輯一組高度相關資料時使用同步一致性 (祖系查詢或是單一實體的 get)。在此類應用程式中,在各組高度相關的資料上使用獨立實體群組,通常會有不錯的效果。詳情請參閱建構同步一致性一文。

屬性和值類型

與實體相關聯的資料值由一或多個「屬性」組成。 每個屬性都有一個名稱及一或多個值。一個屬性可能會有多個類型的值,而兩個實體的相同屬性可能會有不同類型的值。屬性可能已建立索引或未建立索引 (排序或篩選屬性「P」的查詢將忽略「P」未建立索引的實體)。實體最多可有 20,000 個已建立索引的屬性。

支援的值類型如下:

值的類型 Python 類型 排序順序 附註
整數 int
long
數字 64 位元整數,帶正負號
浮點數 float 數字 64 位元雙精準度
IEEE 754
布林值 bool False<True
文字字串 (短) str
unicode
Unicode
(str 當成 ASCII 文字處理)
最多 1500 個位元。
文字字串 (長) db.Text 最多 1 MB

未編入索引
位元組字串 (短) db.ByteString 位元組順序 最多 1500 個位元。
位元組字串 (長) db.Blob 最多 1 MB

未編入索引
日期與時間 datetime.date
datetime.time
datetime.datetime
依時間順序
地理點 db.GeoPt 依照緯度、
經度的順序
郵遞地址 db.PostalAddress Unicode
電話號碼 db.PhoneNumber Unicode
電子郵件地址 db.Email Unicode
Google 帳戶使用者 users.User 電子郵件地址
(以 Unicode 順序)。
即時通訊控點 db.IM Unicode
連結 db.Link Unicode
類別 db.Category Unicode
Rating db.Rating 數字
Cloud Datastore 金鑰 db.Key 按路徑元素
(種類、ID、
種類、ID...)
Blobstore 金鑰 blobstore.BlobKey 位元組順序
零值 NoneType

重要事項:強烈建議不要儲存 UserProperty,因為此屬性含有電子郵件地址和使用者的專屬 ID。如果使用者變更了電子郵件地址,但您還是使用先前儲存的 User 來比對新的 User 值,兩者將無法配對。

至於文字字串和未編碼的二進位資料 (位元組字串),Cloud Datastore 支援兩種值類型:

  • 短字串 (不超過 1500 位元組) 會編製為索引,可用於查詢篩選器條件與排序順序。
  • 長字串 (最多 1 MB) 不會邊製索引,且無法用於查詢篩選器和排序順序。
注意:長位元組字串類型在 Cloud Datastore API 中名為 Blob。此類型和 Blobstore API 使用的 blob 無關。

當查詢的屬性具有混合類型的值時,Cloud Datastore 會根據內部表示法來決定排序:

  1. 空值
  2. 固定點數
    • 整數
    • 日期和時間
    • 評分
  3. 布林值
  4. 位元組序列
    • 位元組字串
    • Unicode 字串
    • Blob 儲存庫鍵
  5. 浮點數
  6. 地理點
  7. Google 帳戶使用者
  8. Cloud Datastore 金鑰

長文字字串和長位元組字串不會建立索引,因此未定義排序。

處理實體

應用程式可使用 Cloud Datastore API 建立、擷取、更新及刪除實體。如果應用程式知道實體的完整金鑰 (或是可從父系金鑰、種類和 ID 中取得),即可在該實體上使用金鑰直接運作。應用程式也可依據 Cloud Datastore 查詢結果取得實體金鑰;詳情請參閱 Datastore 查詢頁面。

建立實體

在 Python 中,可以用以下方式建立新的實體:先建構模型類別的執行個體,視需求填入屬性,然後呼叫 put() 方法,將實體儲存到 Datastore 中。可傳送 key_name 引數至建構函式,藉此指定實體金鑰:

employee = Employee(key_name='asalieri',
                    first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

如果您提供金鑰名稱,Cloud Datastore 會自動產生用於實體金鑰的數字 ID:

employee = Employee(first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

擷取實體

如果要擷取指定金鑰所指定的實體,請將 Key 物件當做引數傳送至 db.get() 函式。可使用 Key.from_path() 類別方法來產生 Key 物件。完整路徑是祖系路徑中的實體序列,每個實體會以自己的種類 (一個字串) 以及 ID (金鑰名稱或數字 ID) 來呈現:

address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
address = db.get(address_k)

db.get() 會傳回正確模型類別的執行個體。請務必確認已經匯入模型類別,以便擷取實體。

更新實體

如果要更新現有實體,請修改物件的屬性,然後呼叫物件的 put() 方法。物件資料會覆寫現有實體,每次呼叫 put() 時,系統會將整個物件傳送至 Cloud Datastore。

如果要刪除屬性,請從 Python 物件中刪除該屬性:

del address.postal_code

然後儲存該物件。

刪除實體

如果有實體的金鑰,就可以透過 db.delete() 函式來刪除該實體

address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
db.delete(address_k)

或是藉由呼叫實體專屬的 delete() 方法:

employee_k = db.Key.from_path('Employee', 'asalieri')
employee = db.get(employee_k)

# ...

employee.delete()

批次作業

db.put()db.get()db.delete() 函式 (以及這些函式的非同步對應函式 db.put_async()db.get_async()db.delete_async()),可接受引數清單,以便於單次 Cloud Datastore 呼叫中在多個實體上執行:

# A batch put.
db.put([e1, e2, e3])

# A batch get.
entities = db.get([k1, k2, k3])

# A batch delete.
db.delete([k1, k2, k3])

批次操作對費用沒有影響。您需要支付批次操作中所有金鑰的費用,無論各個金鑰存在與否。作業中實體的規模大小並不影響費用。

刪除大量實體

如果需要刪除大量的實體,建議使用 Cloud Dataflow 來刪除大量實體

使用空白清單

針對 NDB 介面,Cloud Datastore 過去會寫入空白清單當做靜態屬性與動態屬性的省略屬性。為了維持向下相容的能力,會繼續以此做為預設行為。如果想在全球範圍或是在各個 ListProperty 的範圍內覆寫,請將 Property 類別中的 write_empty_list 引數設為 true,接下來就會將空白清單寫入 Cloud Datastore,且可當成空白清單讀取。

對於 DB 介面,在過去如果屬性為動態,則完全不容許寫入空白清單:如果嘗試此做法,就會出現錯誤狀況。這表示無須為了 DB 動態屬性,而保留向下相容的預設行為,如此一來,無須進行變更,即可在動態模型中讀取及寫入空白清單。

然而對於 DB 靜態屬性,會以省略屬性的形式寫入空白清單,系統也會為了向下相容,繼續以此做為預設行為。如果想要開啟 DB 靜態屬性的空白清單,請在 Propety 類別中,將 write_empty_list 引數設為 true,接著就會將空白清單寫入 Cloud Datastore。

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
App Engine standard environment for Python