實體、屬性和金鑰

注意:強烈建議建構新應用程式的開發人員使用 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

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

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

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

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

系統分配的 ID 值保證為實體群組獨有。如果您由一個實體群組或命名空間將實體複製到其他實體群組或命名空間,並希望保留索引鍵的 ID 部分,請務必先分配 ID,避免讓 Cloud Datastore 未來指派時選擇這個 ID。

祖系路徑

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

實體的父項、父項的父項等以此類推,全都是這個實體的「祖系」;實體的子項、子項的子項等等,則都是其「子系」。 根實體及所有子系都屬於相同的「實體群組」。 從根實體開始,再從父項到子項,最後到指定實體的實體序列,即構成該實體的「祖系路徑」。 完整金鑰代表包含種類-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
評分 db.Rating 數字
Cloud Datastore 金鑰 db.Key 依路徑元素
(種類、ID、
種類、ID...)
Blobstore 金鑰 blobstore.BlobKey 位元組順序
零值 NoneType

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

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

  • 短字串 (不超過 1,500 個位元組) 會建立索引,可用於查詢篩選器條件和排序順序。
  • 長字串 (不超過 1 MB) 不會建立索引,也不能用於查詢篩選器和排序順序。
注意:長位元組字串類型在 Cloud Datastore API 中稱為「Blob」,這個類型與 Blobstore API 使用的 blob 無關。

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

  1. 空值
  2. 固定點數
    • 整數
    • 日期和時間
    • 評分
  3. 布林值
  4. 位元組序列
    • 位元組字串
    • Unicode 字串
    • Blobstore 索引鍵
  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。

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

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

這個網頁
Python 2 適用的 App Engine 標準環境