我在 Jackrabbit 存储库中标记了对象(实际上是 Adobe/Day CQ 的 CRX,但我认为这是 Jackrabbit 代码):
- 资产:标签= A,B
- 子资产数据 1:标签 = A、C、E
- 子资产数据 2:标签 = D、E
我想查询父资产的一组标签和一个孩子的并集,即“B C”将匹配资产,因为我们在父资产和孩子 1 中有这些,但“CD”不匹配,因为没有组合父节点和一个匹配的子节点,因为 C 和 D 被拆分为不同的子数据节点。
有没有办法在 Jackrabbit 中做到这一点?我们可以编写一个 XPath 查询
\\element(*, dam:Asset)[(@tags = 'C' or *\@tags='C')
and (@tags = 'D' or *\@tags='D')]
但这不起作用,因为 XPath 似乎不能保证*
加入的子资产是相同的,即这意味着“任何孩子都有 C/D”,因此将匹配我的资产,因为 1+ 孩子有 C 和 1+孩子们有一个 D。相反,我可以使用 JCR-SQL2
SELECT * FROM dam:Asset as asset
LEFT OUTER JOIN nt:unstructured as child ON ISCHILDNODE(child,asset)
WHERE (asset.tags = 'C' or child.tags = 'C')
AND (asset.tags = 'D' or child.tags = 'D')
但SELECT DISTINCT
在 JCR-SQL2 中没有:如果我搜索“B E”,我将返回此资产两次,因为它与资产 + 子 1 和资产 + 子 2 匹配。
我可以在 Java 中对任一查询结果进行后处理,即过滤掉第一种情况的误报匹配或过滤掉第二种情况的重复结果,但我很担心这会如何影响分页性能:我需要扫描更多节点不需要清除坏节点,我需要扫描很多以计算分页的正确结果大小。对于第二个 SQL2 案例,这应该更便宜,因为如果我的搜索是有序的,我可以仅根据节点路径发现重复项,并且所有重复项都是连续的,所以我可以通过廉价扫描找到给定页面的数据价值,只希望不阅读每个结果的整个节点,但即使对于简单的仅路径情况,我也不知道扫描所有结果以获取分页计数的成本。
我们考虑的另一个选项是将标签非规范化为单个节点。在这种情况下,为了保持搜索准确,这意味着在每个子节点中创建一个新的 combine_tags 属性并仅针对该组子节点执行所有搜索。但是,如果我们匹配同一资产下的两个子节点,这仍然会遇到明显的问题。
感谢您的任何建议。这已经是一个大型实例,需要进一步扩展。我已经看到其他问题说 ModeShape 是一个 JCR 实现,SELECT DISTINCT
但我认为切换到 ModeShape 必须是最后的手段,如果确实可以在 ModeShape 上托管 CQ。
我们现在提出的一个想法是计算资产标签和子标签的每个并集并将标签组合成单个字符串,然后将每个值写入资产的多值属性,即资产 + child1 = "ABC E"和资产 + child2 = "ABD E",所以我们得到
- 资产:标签= A,B;tagUnions = "ABC E", "ABD E"
只要我们定义了将标签组合成字符串的固定顺序(例如字母顺序),我们就可以使用搜索任何组合tagUnions LIKE '%B%C%'
(除了在实际情况下我会在标签之间使用适当的分隔符)。虽然这会起作用,但据我们所见,我真的不喜欢它:每个资产+子项可能有大量标签,所有标签的名称都比单个字母长,这意味着我们最终会得到长字符串来执行LIKE
所有的查询它们可能无法有效地被索引。
另一种做法是制作位掩码:定义 A=1、B=2 等,并在此处存储一个多值整数数组,然后进行按位比较。然而,这可能仅限于 64 个不同的标签,并且由于我们有 1,000 多个标签,我认为我们无法做到这一点——即使 JCR 支持按位运算,我希望它不会。
因此,我仍在为此寻找类似数据库的干净解决方案。你已经错过了我提出的赏金,但仍有滴答声、投票和感谢任何帮助。