本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在 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
启用查询结果缓存后,您可以使用 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')
的缓存,并返回该查询的新结果。
也可以将 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)
这一百个结果将等同于范围
(1000, 1100)
中基本查询的结果。
用于查找缓存结果的查询缓存键
缓存查询的结果后,使用相同查询缓存键的后续查询将从缓存中检索结果,而不是生成新的结果。查询的查询缓存键的计算方式如下:
除
numResultsCached
外,所有与缓存相关的查询提示都将被忽略。最终
iterate()
步骤被忽略。查询的其余部分根据其字节码表示进行排序。
将生成的字符串与缓存中已有的查询结果索引进行匹配,以确定查询是否存在缓存命中。
例如,使用以下查询:
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')