Datastore 能够以编程方式访问部分元数据以支持元编程,从而实现后端管理功能、简化一致性缓存以及实现类似的目标;例如,您可以使用该功能为应用构建自定义 Datastore 查看器。可用的元数据包括应用所用的实体组、命名空间、实体种类和属性的相关信息,以及每个属性的属性表示法。
Google Cloud 控制台中的 Datastore 信息中心还提供一些有关应用的元数据,但其中显示的数据在某些重要方面与这些函数返回的数据有所不同。
- 时效性。信息中心内的数据每天只更新一次,而使用 API 读取元数据会获取当前数据。
- 内容。信息中心内的某些元数据不能通过 API 获得;反之亦然。
- 速度。元数据获取和查询的计费方式与 Datastore 获取和查询相同。元数据查询用于获取命名空间、种类和属性的相关信息,但执行起来通常较慢。根据经验,返回 N 个实体的元数据查询预计与各返回单个实体的 N 个普通查询的时间大致相同。此外,属性表示法查询(非仅限于键的属性查询)比仅限于键的属性查询速度要慢。对实体组元数据进行的元数据获取比获取常规实体要快一些。
实体组元数据
Cloud Datastore 提供实体组“版本”信息。版本必定是正数,且随实体组的每次更改而提高。
对包含正数 __version__
属性的特殊伪实体进行 get()
调用可获得实体组版本信息。伪实体的键可以使用 Entities.createEntityGroupKey()
方法创建:
旧版行为
在旧版的实体组版本行为中,实体组版本仅在实体组发生更改时才会提高。旧版实体组元数据行为可用于多种用途,例如,可以始终如一地缓存对实体组的复杂祖先查询。
以下示例缓存查询结果(匹配结果的计数),并通过实体组版本的旧版行为来使用当前的缓存值:
如果实体组从未写入,则可能不存在 __entity_group__
实体。
元数据查询
com.google.appengine.api.datastore
软件包中定义的 Java 类 Entities
提供了三种为元数据查询预留的特殊实体种类。它们通过 Entities
类的静态常量表示:
静态常量 | 实体种类 |
---|---|
Entities.NAMESPACE_METADATA_KIND |
__namespace__ |
Entities.KIND_METADATA_KIND |
__kind__ |
Entities.PROPERTY_METADATA_KIND |
__property__ |
这些种类不会与应用中可能已存在的其他同名种类发生冲突。通过查询这些特殊种类,您可以检索包含所需元数据的实体。
元数据查询返回的实体是根据 Datastore 的当前状态动态生成的。虽然您可以创建种类为 __namespace__
、__kind__
或 __property__
的本地 Entity
对象,但任何将它们存储在 Datastore 中的尝试都将失败,并抛出 IllegalArgumentException
异常。
发出元数据查询最简单的方法是使用低层级 Datastore API。以下示例输出应用中所有命名空间的名称:
命名空间查询
如果您的应用使用 Namespaces API,则您可以使用命名空间查询来查找应用实体中所用的所有命名空间。这样您就可以跨多个命名空间执行管理功能等活动。
命名空间查询返回特殊种类 __namespace__
的实体,其键名为命名空间的名称。(由空字符串 ""
指定的默认命名空间例外:由于空字符串不是有效的键名,因此此命名空间改为以数字 ID 1
为键。)此类查询支持通过特殊伪属性 __key__
仅对范围进行过滤,该伪属性的值就是实体的键。结果可以按 __key__
值升序(但不能降序)排序。由于 __namespace__
实体没有属性,仅限于键的查询和非仅限于键的查询返回的信息相同。
以下示例返回应用的命名空间列表,其范围介于 start
和 end
两个指定名称之间:
种类查询
种类查询返回种类为 __kind__
的实体,其键名为实体种类的名称。此类型的查询隐式地限制于当前命名空间,并且仅支持对 __key__
伪属性的范围进行过滤。结果可以按 __key__
值升序(但不能降序)排序。由于 __kind__
实体没有属性,仅限于键的查询和非仅限于键的查询返回的信息相同。
以下示例输出名称以小写字母开头的所有种类:
属性查询
属性查询返回种类为 __property__
的实体,该实体表示与某实体种类关联的属性。代表种类 K 的属性 P 的实体按以下方式构建:
- 对于该实体的键,种类为
__property__
,键名为 p。 - 父实体的键具有种类
__kind__
和键名 K。
属性查询的行为取决于它是仅限于键还是非仅限于键(属性表示法)的查询,如下文的各个子部分中所述。
属性查询:仅限于键
仅限于键的属性查询会为指定实体种类的每个编入索引的属性返回一个键(不包括未编入索引的属性)。以下示例将输出应用所有实体种类的名称以及与各种类相关联的属性:
此类型的查询隐式地限制于当前命名空间,并且仅支持对伪属性 __key__
的范围进行过滤,在这种情况下,键表示 __kind__
或 __property__
实体。结果可以按 __key__
值升序(但不能降序)排序。过滤适用于“种类属性对”,先按种类排序,再按属性排序:例如,假定您有一个具有以下属性的实体:
- 种类
Account
,其属性为:balance
company
- 种类
Employee
,其属性为:name
ssn
- 种类
Invoice
,其属性为:date
amount
- 种类
Manager
,其属性为:name
title
- 种类
Product
,其属性为:description
price
返回属性数据的查询会如下所示:
以上查询会返回以下结果:
Employee: ssn
Invoice: date
Invoice: amount
Manager: name
请注意,结果既不包括种类 Employee
的 name
属性和种类 Manager
的 title
属性,也不包括种类 Account
和 Product
的任何属性,因为这些属性不在为查询指定的范围内。
属性查询还支持对 __kind__
或 __property__
键进行祖先过滤,以将查询结果限为单一种类或属性。例如,您可以借助这一点获取与给定的实体种类关联的属性,如以下示例所示:
属性查询:非仅限于键(属性表示法)
非仅限于键的属性查询称为“属性表示法查询”,可返回各“种类属性对”所用表示法的相关额外信息(不包括未编入索引的属性)。为种类为 K 的属性 P 返回的实体具有的键与相应仅限于键的查询返回的键相同,同时具有返回属性表示法的额外 property_representation
属性。此属性的值是类 java.util.Collection<String>
的实例,对于在种类为 K 的任何实体中找到的属性 P 的每个表示法,这个类都包含一个对应的字符串。
请注意,表示法与属性类不同;多个属性类可以对应同一种表示法。(例如,java.lang.String
和 com.google.appengine.api.datastore.PhoneNumber
都使用 STRING
表示法。)
属性类与其表示法的对应关系如下表所示:
属性类 | 表示法 |
---|---|
java.lang.Byte |
INT64 |
java.lang.Short |
INT64 |
java.lang.Integer |
INT64 |
java.lang.Long |
INT64 |
java.lang.Float |
DOUBLE |
java.lang.Double |
DOUBLE |
java.lang.Boolean |
BOOLEAN |
java.lang.String |
STRING |
com.google.appengine.api.datastore.ShortBlob |
STRING |
java.util.Date |
INT64 |
com.google.appengine.api.datastore.GeoPt |
POINT |
com.google.appengine.api.datastore.PostalAddress |
STRING |
com.google.appengine.api.datastore.PhoneNumber |
STRING |
com.google.appengine.api.datastore.Email |
STRING |
com.google.appengine.api.users.User |
USER |
com.google.appengine.api.datastore.IMHandle |
STRING |
com.google.appengine.api.datastore.Link |
STRING |
com.google.appengine.api.datastore.Category |
STRING |
com.google.appengine.api.datastore.Rating |
INT64 |
com.google.appengine.api.datastore.Key |
REFERENCE |
com.google.appengine.api.blobstore.BlobKey |
STRING |
java.util.Collection<T> |
T 的表示法 |
以下示例查找给定实体种类特定属性的所有表示法: