`

gae 数据存储的 索引说明

阅读更多

引入索引

App Engine 数据存储区会为应用程序要进行的每个查询都保留一个索引。当应用程序对数据存储区实体做出更改时,数据存储区会使用正确的结果更新索引。当应用程序执行查询时,数据存储区会直接从相应的索引中抓取结果。

应用程序对查询中使用的每个类型、过滤器属性和操作符以及排序顺序的组合都具有一个索引。请考虑 JDOQL 中所述的示例查询:

select from Person where lastName == "Smith"
                      && height < 72
                order by height desc

该查询的索引是 Person 类型实体的键表,其中包括 height 和 lastName 属性的值列。该索引按照 height 的降序排序。

形式相同但过滤器值不同的两个查询会使用相同的索引。例如,下面的查询与上面的查询使用相同的索引:

select from Person where lastName == "Jones"
                      && height < 64
                order by height desc

数据存储区按照以下步骤执行查询:

  1. 数据存储区会标识符合查询的种类、过滤器属性、过滤器操作符和排序顺序的索引。
  2. 数据存储区会使用该查询的过滤器值在满足全部过滤器条件的第一个实体处开始扫描该索引。
  3. 数据存储区继续扫描索引,同时返回每个实体,直到发现不满足过滤条件的下一个实体,直到达到索引末尾,或者直到已收集了查询所请求的最多结果。

索引表包含在过滤器或排序顺序中使用的每个属性列。行的排序会按照以下几个方面进行:

  • 祖先
  • 在等式过滤条件中使用的属性值
  • 在不等式过滤器中使用的属性值
  • 在排序顺序中使用的属性值

这可将使用该索引的每项可能查询的所有结果以连续行的形式排在表格中。

该机制可支持许多查询,且适用于大部分应用程序。然而,该机制不支持您可能惯用的其他数据库技术中的一些查询类型。

Query 永远不会返回没有已过滤属性的实体

索引仅包含其每个属性都由该索引引用的实体。如果实体没有由某索引引用的属性,那么该实体将不会显示在该索引中,且永远不会成为使用该索引的查询的结果。

请注意,App Engine 数据存储区区分不具有属性的实体和具有带空值 (null) 的属性的实体。如果您希望某个种类的每个实体都成为查询的潜在结果,则可以使用 JDO 或 JPA 数据类,这些类始终将值赋给与类中的字段相对应的每个属性 。

Text 和 Blob 值未编入索引

索引中不包含具有长文本值类型 (Text) 或长二进制值类型 (Blob) 值的属性,所以不能通过查询查找。

不将这些属性值编入索引的结果是,属性上带有过滤器或排序顺序的查询将永远不会匹配属性值为 Text 或 Blob 的实体。带有此类值的属性会表现得如同未对该属性的查询过滤器和排序顺序进行设置。

混合类型的属性值按类型排序

如果两个实体所具有的属性名称相同而值类型不同,那么属性的索引首先按值类型对实体排序,然后按适合该类型的顺序排序。例如,如果两个实体所具有的属性名称均为“年龄”,其中一个具有整数值,另一个具有字符串值,则按“年龄”属性排序时,不管值本身是多少,具有整数值的实体将始终出现在具有字符串值的实体之前。

对于整数和浮点数更值得注意这一点,因为数据存储区会将它们视为彼此独立的类型。具有整数值 38 的属性排在具有浮点值 37.5 的属性之前,因为所有的整数都排在浮点数之前。

(如果使用的是 JDO 或 JPA,则不会出现这种情况,除非您修改字段类型而不同时在数据存储区中更新现有的实体,或者使用低级别的数据存储区 API 或非 Java API。)

用配置定义索引

App Engine 在默认情况下为许多简单查询创建索引。对于其他查询,应用程序必须在一个名为 datastore-indexes.xml 的配置文件中指定所需的索引。如果在 App Engine 下运行的应用程序试图执行一个无相应索引(默认情况下提供或在 datastore-indexes.xml 中描述)的查询,该查询会失败。

App Engine 会为以下形式的查询提供自动索引:

  • 只使用等式和祖先过滤条件的查询
  • 只使用不等式过滤条件(只能具有单个属性)的查询
  • 只有一种排序顺序的属性查询(要么升序,要么降序)

其他形式的查询需要在 datastore-indexes.xml 中指定其索引,这类查询包括:

  • 有多种排序顺序的查询
  • 对键的降序查询
  • 在一个属性上具有一个或多个不等式过滤条件,以及在其他属性上具有一个或多个等式过滤条件的查询
  • 具有不等式过滤条件和祖先过滤条件的查询

开发网络服务器使得管理索引配置很容易:开发网络服务器可以生成索引的配置从而使查询成功,而不会无法执行没有索引但又需要索引的查询。如果对您的应用程序进行的本地测试调用该应用程序可能执行的每个查询(祖先、过滤条件和排序顺序的每种组合),则生成的条目便表示一组完整的索引。如果您的测试不会应用每种可能的查询形式,您可以在上传该应用程序之前审阅和调整索引配置。

可使用名为 datastore-indexes.xml 的配置文件(位于您的应用程序 WAR 的 WEB-INF/ 目录中)手动定义索引。如果您启用了自动索引配置(参见下文),则开发服务器将在 WEB-INF/appengine-generated/ 目录下名为 datastore-indexes-auto.xml 的文件中创建索引配置,并使用两个文件确定索引的完整集。

请再次考虑以下示例查询:

select from Person where lastName = 'Smith'
                      && height < 72
                   order by height desc

该查询所需的索引配置将显示在 datastore-indexes.xml 中,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes
  autoGenerate="true">
    <datastore-index kind="Person" ancestor="false">
        <property name="lastName" direction="asc" />
        <property name="height" direction="desc" />
    </datastore-index>
</datastore-indexes>

如果 datastore-indexes.xml 中的 <datastore-indexes> 元素具有 autoGenerate="true" 属性(同上),或应用程序没有datastore-indexes.xml 文件,则自动索引配置已启用。自动索引配置启用后,如果应用程序在开发服务器中执行该查询且不存在索引配置,则服务器会将该索引配置添加到 datastore-indexes-auto.xml 文件。

有关 datastore-indexes.xml 和 datastore-indexes-auto.xml 的详细信息,请参阅 Java 数据存储区索引配置

对键的查询

实体键可作为查询过滤条件或排序顺序的主题。在 JDO 中,您将使用对象的主键字段在查询中引用实体键。数据存储区将对这类查询考虑完整键值,包括实体的父实体路径、类型以及应用程序分配的键名称字符串或系统分配的数字 ID。

由于实体键在系统中的所有实体间唯一,键查询可使批量检索给定类型的实体(例如批量转储数据存储区内容)变得容易。与 JDOQL 范围不同,它对任意数量的实体都可高效地工作。

健首先按父路径排序,再按种类,然后按键名或 ID。种类和键名是字符串,按字节值排序。ID 是整数,按数字顺序排序。如果具有相同父实体和种类的实体同时使用键名字符串和数字 ID,则将带有数字 ID 的实体视为少于带有键名字符串的实体。对父路径的元素进行类似的比较:根据种类(字符串),然后根据键名(字符串)或 ID(数字)。

涉及键的查询与涉及属性的查询使用索引的情况相似,只有一个小小的差别:与使用属性的查询不同的是,使用等式过滤条件对键的查询还使用其他过滤条件,必须使用在应用程序的索引配置文件中定义的自定义索引。和所有查询一样,当对需要自定义索引的查询进行测试时,开发网络服务器在此文件中创建合适的配置条目。

对查询的限制

索引查询机制的本质是对查询功能强加一些限制。

对一个属性进行过滤或排序需要确认该属性确实存在

属性的查询过滤条件或排序顺序也暗含了一个条件,即实体必须具有该属性的值。

数据存储区实体不需具有其他同类实体所具有的属性值。属性上的过滤器只能与具有该属性的值的实体相匹配。过滤器或排序顺序中所使用的不具有属性值的实体会从为该查询创建的索引中删除。

没有可与不具有属性的实体相匹配的过滤器

无法为缺少指定属性的实体执行查询。一种解决方法是创建一个固定的(已建模的)属性,默认值为 null,然后为实体创建一个过滤条件,属性值为 null

不等式过滤条件只能用于一个属性

查询在其所有过滤器中只能在一个属性上使用不等式过滤条件(<<=>=>)。

例如,以下查询是允许使用的:

select from Person where birthYear >= minBirthYearParam
                      && birthYear <= maxBirthYearParam

而以下查询是不允许使用,因为此查询在同一个查询中的两个不同属性上使用了不等式过滤条件:

select from Person where birthYear >= minBirthYearParam
                      && height >= minHeightParam   // ERROR

过滤器可合并同一查询(包括属性上带有一个或多个不等式条件的查询)中不同属性的同级 (==) 比较。允许执行此操作:

select from Person where lastName == lastNameParam
                      && city == cityParam
                      && birthYear >= minBirthYearParam

查询机制基于将查询的所有结果彼此相邻地排列在索引表中,以避免为查找结果而不得不扫描整个整个表。在保持所有结果连续出现在表中的同时,单个索引表无法表示用于多个属性上的多个不等式过滤器。

必须在采用其他排序顺序之前对不等式过滤器中的属性进行排序

如果查询具有带不等式比较以及带一个或多个排序顺序的两种过滤器,那么,该查询必须包含在该不等式中使用的属性的排序顺序,且该排序顺序必须出现在其他属性上的排序顺序之前。

以下查询无效,因为此查询使用了不等式过滤条件,且未根据已过滤的属性进行排序:

select from Person where birthYear >= minBirthYearParam
                order by lastName                    // ERROR

同样,以下查询无效,因为它在根据其他属性排序之前未根据已过滤的属性进行排序:

select from Person where birthYear > minBirthYearParam
                order by lastName, birthYear         // ERROR

以下查询有效:

select from Person where birthYear >= minBirthYearParam
                order by birthYear, lastName

要获得与不等式过滤条件匹配的所有结果,查询会扫描索引表寻找第一个匹配的行,然后返回所有连续的匹配结果,直到找到不匹配的行为止。表示完整结果集的连续行必须先按照不等式过滤条件排序,然后再按其他顺序排序。

排序顺序和具有多个值的属性

鉴于将具有多个值的属性编入索引的方式,这些属性的排序顺序不平常:

  • 如果实体按照多值属性以升序排列,则用于排序的值会成为最小的值。
  • 如果实体按照多值属性以降序排列,则用于排序的值会成为最大的值。
  • 其他值不影响排序顺序,值的数目也不影响。
  • 就链而言,该实体的键被用作该链的断路器。

此排序顺序引起异常结果:以升序和降序排序时 [1, 9] 都显示在 [4, 5, 6, 7] 之前。

需要特别注意对于多值属性既具有等式过滤条件又具有排序顺序的查询。在这些查询中,排序顺序将被忽略。对于单值属性,这是一个简单的优化。对于属性来说,每个结果都具有相同的值,因此,不需要对结果进一步排序。

然而,多值属性可能具有其他的值。由于忽略了排序顺序,与应用了排序顺序时相比,可能会以一个不同于前者顺序的顺序返回查询结果。(恢复已放弃的排序顺序会花费巨大并需要额外的标记,又因为这种使用情况很少出现,因此查询计划员禁止此项操作。)

大的实体和分解索引

如上所述,会把每个实体的每个属性(不具有 Text 或 Blob 值)添加到至少一个索引表(包含默认情况下提供的简单索引和在引用该属性的应用程序的 文件中所描述的任何索引)datastore-indexes.xml 中。如果实体的每个属性都有一个值,App Engine 会将属性值在简单索引中存储一次,并且在每次引用属性时在自定义索引中存储一次。每次更改该属性的值时,这些索引条目中的每一个都必须进行更新,因此,引用该属性的索引越多,更新该属性所需要的时间就越长。

为防止更新实体花费过多时间,数据存储区会限制单个实体可具有的索引条目的数量。该限制涉及的范围广大,且使用大部分应用程序时将不会引起用户的注意。然而,有些情况下您可能会遇到该限制。例如,具有许多单一值属性的实体可能会超出索引条目的限制。

具有多个值的属性将每个值作为单独的条目存储在索引中。当单个属性具有许多值时,具有该单个属性的实体可以超出索引条目的限制。

当自定义索引引用多个多值属性时,即使仅有几个值,容量也会很大。要完整记录这类属性,索引表必须包含一行,该行内容为该索引每个属性的值的所有排列。

例如,以下索引(用 datastore-indexes.xml 语法描述)包括类型为 MyModel 的实体的 x 和 y 属性:

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes>
    <datastore-index kind="MyModel">
        <property name="x" direction="asc" />
        <property name="y" direction="asc" />
    </datastore-index>
</datastore-indexes>

以下代码会创建分别具有属性 x 和属性 y 的 2 个值的实体:

        MyModel m = new MyModel();

        m.setX(Arrays.asList("one", "two"));
        m.setY(Arrays.asList("three", "four"));

        pm.makePersistent(m);

为了正确表示这些值,该索引必须存储 12 个属性值:x 和 y 上的每个内置索引各 2 个,自定义索引中 x 和 y 的 4 项排列中每项各 1 个。如果存在许多多值属性的值,这可能意味着一个索引必须存储单个实体的许多索引条目。您可以将引用多个多值属性的索引称作“爆炸式索引”,因为该类索引即使仅有几个值,容量也会很大。

如果 put() 会导致产生大量超出限制的索引条目,那么调用会失败,并引发异常。如果您创建一个包含大量索引条目的新索引,且这些索引条目超出了对所创建的任何实体的限制,那么针对该索引的查询会失败,并且该索引会以“错误”的状态显示在管理控制台中。

您可以通过避免需要自定义索引的查询使用列表属性来避免分解索引。如上所述,这包括具有多种排序顺序的查询、使用等式和不等式过滤条件的查询以及使用祖先过滤条件的查询。

分享到:
评论

相关推荐

    dsql:数据存储区SQL。 适用于Google App Engine数据存储区SQL引擎

    DSQL扩展了gae数据存储区,以实现各种数据存储区之间的本地联接,以及为未索引的属性提供本地过滤。 DSQL使用熟悉的sql语法。 SQL联接使用数据存储统计信息进行了优化。 假定数据存储架构的设计类似于关系数据库。...

    thundr-contrib-gae-admin

    在thundr-gae应用程序的数据存储区管理控制台中删除。 查询数据存储中的数据 重新生成搜索索引。 入门 将 Maven 依赖项添加到您的 pom.xml: &lt;groupId&gt;com.atomicleopard.thundr&lt;/groupId&gt; &lt;artifactId&gt;...

    nosql 入门教程

    10.1.2 使用Python进行基本的GAE数据建模 165 10.1.3 查询与索引 168 10.1.4 过滤和结果排序 170 10.1.5 Java App Engine SDK 172 10.2 Amazon SimpleDB 175 10.2.1 SimpleDB入门 176 10.2.2 使用REST API ...

    google app engine 一些文档 python

    3. **数据存储**:GAE的NoSQL数据存储系统称为Datastore,它提供了一个基于Bigtable的强大存储解决方案。文档会解释实体、键值对、查询、事务和预定义索引的概念。 4. **HTTP服务**:如何处理HTTP请求和响应,使用...

    Google App Engine 数据库

    总之,Google App Engine的Datastore提供了一种灵活且强大的数据存储解决方案,适合构建大规模、高并发的应用。然而,开发者需要理解和适应其非关系型特性和特定的查询语法,以便有效地利用这一服务。

    Developing with Google App Engine.rar

    2. **优化数据存储**:理解数据存储模式,合理设计实体结构,利用索引和查询优化来提高性能。 3. **异步处理**:尽可能使用任务队列处理耗时操作,避免阻塞主线程。 总之,谷歌应用引擎为开发者提供了强大的工具和...

    jdo API 2.2

    在Google App Engine (GAE)环境中,JDO API 2.2是开发者常用的工具,它允许应用程序与GAE的数据存储服务进行交互。JDO 2.2提供了一种简单、灵活且强大的方式来管理对象的生命周期,包括创建、查询、更新和删除对象。...

    Google App Engine 开发人员指南.pdf

    - **数据库 API**:支持高效的数据存储与检索操作,适用于构建大规模的在线应用。 - **图像 API**:提供图像处理功能,如裁剪、缩放等。 - **邮件 API**:通过简单的接口实现邮件发送功能。 - **Memcache API**:...

    super-material-seed-gae:种子

    基于Google留言簿示例的超级...在Course文件夹中,有一些关于crud视图的示例(编辑,索引,新建,显示) 数据存储在App Engine(NoSQL)高复制数据存储区(HRD)中,并使用强一致性(祖先)查询进行检索。 任何人都可以

    Google App Engine

    - **多种服务**:包括数据存储(如Datastore)、任务队列(Task Queue)、电子邮件服务、缓存服务等。 - **灵活的语言支持**:支持Python、Java、Go和PHP等多种编程语言。 - **强大的API**:提供如Google Cloud ...

    Programming Google App Engine - Dan Sanderson

    - **数据存储**:Google App Engine提供了强大的数据存储服务,包括实体和属性的概念。这部分会深入探讨数据模型、查询和索引机制以及事务处理等方面的内容。 - **服务**:除了数据存储之外,Google App Engine还...

    云计算技术介绍

    云计算是一种通过互联网提供的计算服务模式,它使得用户能够根据需要从远程服务器获取计算能力和数据存储服务。这种服务模式改变了传统上需要本地部署和维护复杂硬件与软件的做法,为用户提供了一种灵活、高效、低...

    云端代码Google App Engine编程

    #### 五、数据存储 1. **Datastore**:Google App Engine默认支持Datastore,这是一种高度可扩展的NoSQL数据库服务。 2. **实体模型**:在Datastore中,数据被组织成实体,每个实体都包含一组键值对属性。 3. **...

    云应用开发 ——Google App Engine & Google Web Toolkit入门指南

    简要介绍 Google App Engine 的数据存储机制。 ##### 7.2 定义数据类 如何使用 Java 类来定义实体数据模型。 ##### 7.3 创建,获取和删除数据 如何执行 CRUD(创建、读取、更新、删除)操作。 ##### 7.4 查询和...

Global site tag (gtag.js) - Google Analytics