本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
joinOrder
SPARQL查询提示
当您提交SPARQL查询时,Amazon Neptune 查询引擎会调查查询的结构。它将对查询的各个部分重新排序,并尝试最大程度地减少计算所需的工作量和查询响应时间。
例如,通常不会按给定顺序计算一系列连接的三元组模式。使用试探法和统计数据(例如,各个模式的选择性以及它们通过共享变量连接的方式)来对查询重新排序。此外,如果您的查询包含更复杂的模式,例如子查询FILTERs、复杂OPTIONAL或MINUS块,Neptune 查询引擎会尽可能对它们进行重新排序,以实现有效的评估顺序。
对于更复杂的查询,Neptune 选择计算查询的顺序可能并不总是最佳的。例如,Neptune 可能会丢失在计算查询期间发生的实例数据特定的特征(例如命中图形中的电源节点)。
如果您知道确切的数据特性并且想要手动指示查询执行顺序,请使用 Neptune joinOrder
查询提示指定按给定的顺序计算查询。
joinOrder
SPARQL提示语法
joinOrder
查询提示被指定为SPARQL查询中包含的三重模式。
为清晰起见,以下语法使用查询中定义并包含的 hint
前缀来指定 Neptune 查询提示命名空间:
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
scope
hint:joinOrder "Ordered" .
可用范围
hint:Query
hint:Group
有关查询提示范围的更多信息,请参阅 Neptune 中SPARQL查询提示的范围。
joinOrder
SPARQL提示示例
本节介绍使用和未使用 joinOrder
查询提示和相关优化编写的查询。
在此示例中,假定数据集包含以下内容:
一个名为
John
的人(:likes
1000 人,包括Jane
)。一个名为
Jane
的人(:likes
10 人,包括John
)。
无查询提示
以下SPARQL查询从一组社交网络数据中提取所有被点名John
且彼此喜欢Jane
的人:
PREFIX : <https://example.com/> SELECT ?john ?jane { ?person1 :name "Jane" . ?person1 :likes ?person2 . ?person2 :name "John" . ?person2 :likes ?person1 . }
Neptune 查询引擎可能会以不同于编写的顺序计算语句。例如,它可能选择按以下顺序计算:
查找所有名为
John
的人。查找通过
:likes
边缘连接到John
的所有人。按名为
Jane
的人筛选此集。按通过
:likes
边缘连接到John
的人筛选此集。
根据此数据集,按此顺序进行计算会导致在第二步中提取 1000 个实体。第三步将此范围缩小到单个节点 Jane
。之后,最后一步确定 Jane
也将 :likes
节点 John
。
查询提示
从 Jane
节点开始是有利的,因为她只有 10 个传出 :likes
边缘。这将避免在第二步中提取 1000 个实体,从而减少了查询计算期间的工作量。
以下示例使用joinOrder查询提示通过禁用查询的所有自动联接重新排序来确保首先处理Jane
节点及其传出边缘:
PREFIX : <https://example.com/> PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#> SELECT ?john ?jane { hint:Query hint:joinOrder "Ordered" . ?person1 :name "Jane" . ?person1 :likes ?person2 . ?person2 :name "John" . ?person2 :likes ?person1 . }
一个适用的现实场景可能是社交网络应用程序,其中网络中的人员被分为具有许多连接的影响者和具有很少连接的普通用户。在此场景中,您可以确保在类似于上一个示例的查询中,先处理普通用户 (Jane
),再处理影响者 (John
)。
查询提示和重新排序
您可以进一步了解此示例。如果您知道 :name
属性对于单一节点是唯一的,则可通过重新排序和使用 joinOrder
查询提示来加快查询速度。此步骤确保首先提取唯一节点。
PREFIX : <https://example.com/> PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#> SELECT ?john ?jane { hint:Query hint:joinOrder "Ordered" . ?person1 :name "Jane" . ?person2 :name "John" . ?person1 :likes ?person2 . ?person2 :likes ?person1 . }
在此情况下,您可以在每个步骤中将查询减少到以下单个操作:
查找包含
:name
Jane
的单个人节点。查找包含
:name
John
的单个人节点。检查使用
:likes
边缘连接到第二个节点的第一个节点。检查使用
:likes
边缘连接到第一个节点的第二个节点。
重要
如果您选择了错误的顺序,则 joinOrder
查询提示可能会导致性能显著下降。例如,如果 :name
属性不是唯一的,则上一个示例的效率低下。如果所有 100 个节点都名为 Jane
并且所有 1000 个节点都名为 John
,则查询将最终检查 :likes
边缘的 1000 * 100 (100000) 个对。