在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 端点上和使用 Websockets 提交的查询,无论是作为字节码还是以字符串形式提交。

注意

即使启用了查询缓存,发送到配置文件端点的查询也不会被缓存。

您可以通过多种方式控制 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

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

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'),并返回该查询的新结果。

也可以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 在找不到与该范围内的查询完全匹配的查询时,会清除不包含该范围的查询的缓存。

配合使用 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)

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