在 XQuery 中查找一个文档中存在但另一个文档中不存在的元素的有效方法
Efficient way of finding elements that exists in one document but not the other in XQuery
我有以下数据:
<Subjects>
<Subject>
<Id>1</Id>
<Name>Maths</Name>
</Subject>
<Subject>
<Id>2</Id>
<Name>Science</Name>
</Subject>
<Subject>
<Id>2</Id>
<Name>Advanced Science</Name>
</Subject>
<Subject>
<Id>500</Id>
<Name>XYZ</Name>
</Subject>
<Subject>
<Id>1000</Id>
<Name>ABC</Name>
</Subject>
</Subjects>
和:
<Courses>
<Course>
<SubjectId>1</SubjectId>
<Name>Algebra I</Name>
</Course>
<Course>
<SubjectId>1</SubjectId>
<Name>Algebra II</Name>
</Course>
<Course>
<SubjectId>1</SubjectId>
<Name>Percentages</Name>
</Course>
<Course>
<SubjectId>2</SubjectId>
<Name>Physics</Name>
</Course>
<Course>
<SubjectId>2</SubjectId>
<Name>Biology</Name>
</Course>
</Courses>
并且我希望能够使用 500
和 1000
获取 subject
元素,因为它们没有出现在第二个 XML 文档中。
我如何以最有效的方式做到这一点(记住我有大约 750 个科目,每个科目有 120 门课程)?
效率取决于您的优化器,但由于您在标签中提到了 Saxon,我想这就是我们可以瞄准的目标。假设您已将变量 $subjects
和 $courses
分别绑定到 <Subjects>
和 <Courses>
元素,最简单的查询可能是
$subjects/Subject[not(Id = $courses/Course/SubjectId)]
作为第一步,我会尝试 运行 看看它是否能在可接受的时间内产生正确的结果;从那时起它的性能调整工作。对于性能调整,请确保您有不同大小的源文档,以便您可以衡量性能如何随文档大小变化。
通常对于连接查询,Saxon-EE 在优化方面会比 Saxon-HE 做得更好,但我怀疑它在这个查询上是否会取得很大成功,因为谓词表示为否定。所以这可能会有二次性能。
为了手动优化它,我会建立一个索引。在 XSLT 中可以使用 xsl:key 完成,在 XQuery 3.1 中可以使用映射完成。定义包含出现在 $courses:
中的所有 SubjectId 的映射
let $courseSubjects := map:merge($courses/Course/SubjectId ! map{.: true()})
然后用它来 select:
return $subjects/Subject[not(map:contains($courseSubjects, Id))]
后记
我低估了 Saxon-EE 优化器。它实际上会生成一个索引来支持对该连接的评估。所以创建自己的地图可能是完全没有必要的。但是我没有做过任何测量。
我有以下数据:
<Subjects>
<Subject>
<Id>1</Id>
<Name>Maths</Name>
</Subject>
<Subject>
<Id>2</Id>
<Name>Science</Name>
</Subject>
<Subject>
<Id>2</Id>
<Name>Advanced Science</Name>
</Subject>
<Subject>
<Id>500</Id>
<Name>XYZ</Name>
</Subject>
<Subject>
<Id>1000</Id>
<Name>ABC</Name>
</Subject>
</Subjects>
和:
<Courses>
<Course>
<SubjectId>1</SubjectId>
<Name>Algebra I</Name>
</Course>
<Course>
<SubjectId>1</SubjectId>
<Name>Algebra II</Name>
</Course>
<Course>
<SubjectId>1</SubjectId>
<Name>Percentages</Name>
</Course>
<Course>
<SubjectId>2</SubjectId>
<Name>Physics</Name>
</Course>
<Course>
<SubjectId>2</SubjectId>
<Name>Biology</Name>
</Course>
</Courses>
并且我希望能够使用 500
和 1000
获取 subject
元素,因为它们没有出现在第二个 XML 文档中。
我如何以最有效的方式做到这一点(记住我有大约 750 个科目,每个科目有 120 门课程)?
效率取决于您的优化器,但由于您在标签中提到了 Saxon,我想这就是我们可以瞄准的目标。假设您已将变量 $subjects
和 $courses
分别绑定到 <Subjects>
和 <Courses>
元素,最简单的查询可能是
$subjects/Subject[not(Id = $courses/Course/SubjectId)]
作为第一步,我会尝试 运行 看看它是否能在可接受的时间内产生正确的结果;从那时起它的性能调整工作。对于性能调整,请确保您有不同大小的源文档,以便您可以衡量性能如何随文档大小变化。
通常对于连接查询,Saxon-EE 在优化方面会比 Saxon-HE 做得更好,但我怀疑它在这个查询上是否会取得很大成功,因为谓词表示为否定。所以这可能会有二次性能。
为了手动优化它,我会建立一个索引。在 XSLT 中可以使用 xsl:key 完成,在 XQuery 3.1 中可以使用映射完成。定义包含出现在 $courses:
中的所有 SubjectId 的映射let $courseSubjects := map:merge($courses/Course/SubjectId ! map{.: true()})
然后用它来 select:
return $subjects/Subject[not(map:contains($courseSubjects, Id))]
后记
我低估了 Saxon-EE 优化器。它实际上会生成一个索引来支持对该连接的评估。所以创建自己的地图可能是完全没有必要的。但是我没有做过任何测量。