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

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

在 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 结果,以便在缓存新结果时腾出空间。

重要

查询结果缓存不适用于 t3.mediumt4.medium 实例类型。

在 Neptune 中启用查询结果缓存

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

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

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

您可使用 实例状态 命令检查结果缓存的当前状态。

使用提示缓存查询结果

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

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

使用 enableResultCache

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

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 秒或更长时间,则该查询将返回新的结果,并对其进行缓存,但没有任何结果 time-to-live。

您也可以通过再次发出带有 enableResultCacheWithTTL 查询提示的相同查询来访问缓存的结果。例如:

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

在 120 秒(即当前有效的 TTL)过去之前,这个使用 enableResultCacheWithTTL 查询提示的新查询将返回缓存的结果。120 秒后,它将返回新结果并将其缓存 140 秒。 time-to-live

注意

如果查询密钥的结果已被缓存,则与的相同查询键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') 的缓存,并返回该查询的新结果。

也可以将 invalidateResultCacheKeyenableResultCacheenableResultCacheWithTTL 结合使用。例如,以下查询清除当前缓存的结果,缓存新结果并返回它们:

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')

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

也可以将 invalidateResultCacheenableResultCacheenableResultCacheWithTTL 结合使用。例如,以下查询会清除整个结果缓存,缓存该查询的新结果,然后返回这些结果:

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 找不到与具有该范围的查询完全匹配的查询时,它会清除没有该范围的查询的缓存。

配合使用 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. 查询的其余部分根据其字节码表示进行排序。

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

例如,使用以下查询:

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

它将存储为以下内容的字节码版本:

g.withSideEffect('Neptune#typePromotion', false) .with("Neptune#numResultsCached", 50) .V().has('genre','drama').in('likes')

与结果缓存相关的异常

如果您尝试缓存的查询结果太大而无法容纳在缓存内存中,即使删除了先前缓存的所有内容也是如此,那么 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')