在 Amazon Neptune Gremlin 中缓存查询结果 - Amazon Neptune
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 Amazon Neptune Gremlin 中缓存查询结果

以下是启动引擎版本 1.0.5.1,Amazon Neptune 支持 Gremlin 查询的结果缓存。

您可以启用查询结果缓存,然后使用查询提示缓存 Gremlin 只读查询的结果。

然后,任何重新运行查询都会以低延迟且没有 I/O 成本检索缓存的结果,只要这些结果仍在缓存中。这适用于在 HTTP 端点上提交的查询和使用 Websocket 提交的查询,无论是作为字节码还是字符串形式。

您可以通过多种方式控制 Neptune 查询结果缓存的行为方式。例如:

  • 你可以将缓存的结果分页(以块为单位)。

  • 您可以指定 time-to-live (TTL) 用于指定的查询。

  • 您可以清除指定查询的缓存。

  • 您可以清除整个缓存。

  • 您可以设置为在结果超过缓存大小时收到通知。

缓存使用 least-recently-used (LRU) 策略,这意味着一旦分配给缓存的空间已满, least-recently-used 删除结果以便在缓存新结果时腾出空间。

重要

查询结果缓存不可用t2.medium要么t3.medium实例类型。

在 Neptune 中启用查询结果缓存

要在 Neptune 中启用查询结果缓存,请使用控制台设置neptune_result_cache数据库实例参数到1(已启用)。

启用结果缓存后,Neptune 会留出一部分当前内存来缓存查询结果。您使用的实例类型越大,可用的内存越多,Neptune 为缓存留的内存就越多。

如果结果缓存内存已满,Neptune 会自动丢弃 least-recently-used (LRU) 缓存结果以便为新的结果铺路。

您可以使用实例状态命令。

使用提示缓存查询结果

启用查询结果缓存后,您可以使用查询提示来控制查询缓存。以下所有示例都适用于同一个查询遍历,即:

g.V().has('genre','drama').in('likes')

使用 enableResultCache

启用查询结果缓存后,您可以使用enableResultCache查询提示,如下所示:

g.with('Neptune#enableResultCache', true) .V().has('genre','drama').in('likes')

然后,Neptune 将查询结果返回给你,并缓存它们。稍后,您可以通过再次发出完全相同的查询来访问缓存的结果:

g.with('Neptune#enableResultCache', true) .V().has('genre','drama').in('likes')

标识缓存结果的缓存键是查询字符串本身,即:

g.V().has('genre','drama').in('likes')

使用 enableResultCacheWithTTL

您可以通过使用enableResultCacheWithTTL查询提示。例如,以下查询指定查询结果应在 120 秒后过期:

g.with('Neptune#enableResultCacheWithTTL', 120) .V().has('genre','drama').in('likes')

同样,识别缓存结果的缓存键是基本查询字符串:

g.V().has('genre','drama').in('likes')

再次,你可以使用该查询字符串访问缓存的结果enableResultCache查询提示:

g.with('Neptune#enableResultCache', true) .V().has('genre','drama').in('likes')

如果自缓存结果以来已过去 120 秒或更长时间,则该查询将返回新的结果并缓存它们,而无需任何生存时间。

您也可以通过使用enableResultCacheWithTTL查询提示。例如:

g.with('Neptune#enableResultCacheWithTTL', 140) .V().has('genre','drama').in('likes')

直到 120 秒钟过去(也就是说,当前有效的 TTL),这个新查询使用enableResultCacheWithTTL查询提示返回缓存的结果。120 秒后,它将返回新结果并用 time-to-live 140 秒。

注意

如果查询密钥的结果已经被缓存,那么同一个查询密钥enableResultCacheWithTTL不会产生新结果并且不会影响 time-to-live 当前缓存的结果。

  • 如果以前使用缓存结果enableResultCache,必须先清除缓存之前enableResultCacheWithTTL生成新结果并针对它指定的 TTL 缓存它们。

  • 如果以前使用缓存结果enableResultCachewithTTL,之前的 TTL 必须先过期之前enableResultCacheWithTTL生成新结果并针对它指定的 TTL 缓存它们。

使用 invalidateResultCacheKey

您可以使用invalidateResultCacheKey查询提示以清除某个特定查询的缓存结果。例如:

g.with('Neptune#invalidateResultCacheKey', true) .V().has('genre','drama').in('likes')

该查询清除查询密钥的缓存,g.V().has('genre','drama').in('likes'),然后返回该查询的新结果。

您也可以组合使用invalidateResultCacheKeyenableResultCache要么enableResultCacheWithTTL. 例如,以下查询清除当前缓存的结果、缓存新结果并返回它们:

g.with('Neptune#enableResultCache', true) .with('Neptune#invalidateResultCacheKey', true) .V().has('genre','drama').in('likes')

使用 invalidateResultCache

您可以使用invalidateResultCache查询提示以清除查询结果缓存中的所有缓存结果。例如:

g.with('Neptune#invalidateResultCache', true) .V().has('genre','drama').in('likes')

该查询清除整个结果缓存并返回查询的新结果。

您也可以组合使用invalidateResultCacheenableResultCache要么enableResultCacheWithTTL. 例如,以下查询清除整个结果缓存、缓存此查询的新结果并返回它们:

g.with('Neptune#enableResultCache', true) .with('Neptune#invalidateResultCache', true) .V().has('genre','drama').in('likes')

对缓存的查询结果进行分页

假设你已经缓存了大量这样的结果:

g.with('Neptune#enableResultCache', true) .V().has('genre','drama').in('likes')

现在假设你发出以下范围查询:

g.with('Neptune#enableResultCache', true) .V().has('genre','drama').in('likes').range(0,10)

Neptune 首先寻找完整的缓存密钥,即g.V().has('genre','drama').in('likes').range(0,10). 如果该键不存在,Neptune 接下来看看该查询字符串是否有没有范围的密钥(即g.V().has('genre','drama').in('likes'))。当它找到那个密钥时,Neptune 然后从缓存中获取前十个结果,如范围所指定的那样。

注意

如果您将invalidateResultCacheKey查询提示带有最后一个范围的查询,如果 Neptune 没有找到与该范围的查询完全匹配,则 Neptune 会清除没有该范围的查询的缓存。

配合使用 numResultsCached.iterate()

使用numResultsCached查询提示,您可以在不返回所有缓存结果的情况下填充结果缓存,这在您更喜欢为大量结果分页时非常有用。

这些区域有:numResultsCached查询提示仅适用于以结尾的查询iterate().

例如,如果要缓存示例查询的前 50 个结果:

g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 50) .V().has('genre','drama').in('likes').iterate()

在这种情况下,缓存中的查询密钥是:g.with("Neptune#numResultsCached", 50).V().has('genre','drama').in('likes'). 现在,您可以使用此查询检索前十个缓存结果:

g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 50) .V().has('genre','drama').in('likes').range(0, 10)

而且,您可以按如下方式从查询中检索接下来的十个结果:

g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 50) .V().has('genre','drama').in('likes').range(10, 20)

不要忘记包含numResultsCached提示!它是查询密钥的重要组成部分,因此必须存在才能访问缓存的结果。

使用时需要记住的一些事项numResultsCached

  • 你提供的号码numResultsCached将在查询的末尾应用。  这意味着,例如,以下查询实际上缓存了该范围的结果(1000, 1500)

    g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 500) .V().range(1000, 2000).iterate()
  • 你提供的号码numResultsCached指定要缓存的最大结果数量。  这意味着,例如,以下查询实际上缓存了该范围的结果(1000, 2000)

    g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 100000) .V().range(1000, 2000).iterate()
  • 由以结尾的查询缓存的结果.range().iterate()有自己的范围。  例如,假设您使用以下查询缓存结果:

    g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 500) .V().range(1000, 2000).iterate()

    要从缓存中检索前 100 个结果,你需要编写这样的查询:

    g.with("Neptune#enableResultCache", true) .with("Neptune#numResultsCached", 500) .V().range(1000, 2000).range(0, 100)

    这百个结果将等同于范围内基本查询的结果(1000, 1100).

用于查找缓存结果的查询缓存键

在缓存查询结果之后,后续查询具有相同查询缓存键从缓存中检索结果,而不是生成新的结果。查询的查询缓存密钥按如下方式评估:

  1. 查询提示将被忽略,但numResultsCached.

  2. 最终决赛iterate()忽略步骤。

  3. 查询的其余部分是根据其字节码表示形式进行排序的。

生成的字符串与缓存中已经存在的查询结果的索引进行匹配,以确定查询是否存在缓存命中。

与结果缓存相关的例外

如果您尝试缓存的查询结果太大而无法容纳缓存内存,即使在删除之前缓存的所有内容之后,Neptune 会引发QueryLimitExceededException故障。不返回任何结果,异常会生成以下错误消息:

The result size is larger than the allocated cache, please refer to results cache best practices for options to rerun the query.

你可以使用noCacheExceptions查询提示,如下所示:

g.with('Neptune#enableResultCache', true) .with('Neptune#noCacheExceptions', true) .V().has('genre','drama').in('likes')