本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在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.medium
或t4.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')
,并返回该查询的新结果。
也可以invalidateResultCacheKey
与enableResultCache
或结合使用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')
该查询会清除整个结果缓存并返回查询的新结果。
也可以invalidateResultCache
与enableResultCache
或结合使用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)
。
用于查找缓存结果的查询缓存密钥
缓存查询结果后,具有相同查询缓存键的后续查询会从缓存中检索结果,而不是生成新的结果。查询的查询缓存密钥的计算方法如下:
查询提示将被忽略,但除
numResultsCached
了。最后
iterate()
一步被忽略。查询的其余部分根据其字节码表示形式进行排序。
将生成的字符串与缓存中已经存在的查询结果的索引进行匹配,以确定查询是否存在缓存命中的情况。
与结果缓存相关的异常
如果您尝试缓存的查询结果太大而无法容纳在缓存内存中,即使在删除了之前缓存的所有内容之后,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')