【问题标题】:Jackrabbit searches across joined nodesJackrabbit 跨连接节点搜索
【发布时间】:2012-03-26 11:49:15
【问题描述】:

我在 Jackrabbit 存储库中标记了对象(实际上是 Adob​​e/Day CQ 的 CRX,但我认为这是 Jackrabbit 代码):

  • 资产:标签 = A、B
    • 子资产数据 1:标签 = A、C、E
    • 子资产数据 2:标签 = D、E

我想查询父资产的一组标签和一个子资产的联合,即“B C”将匹配资产,因为我们在父资产和子资产 1 中有这些,但“C D”不匹配,因为有没有匹配的父子组合,因为 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')

但是在 JCR-SQL2 中没有 SELECT DISTINCT:如果我搜索“B E”,我将返回此资产两次,因为它同时匹配资产+child1 和资产+child2。

我可以在 Java 中对任一查询结果进行后处理,即过滤掉第一种情况的误报匹配或过滤掉第二种情况的重复结果,但我很担心这会如何影响分页性能:我需要扫描多余的节点以清除不良节点,并且我需要扫描该批次以计算分页的正确结果大小。对于第二个 SQL2 案例,这应该更便宜,因为如果我的搜索是有序的,我可以仅根据节点路径发现重复项,并且所有重复项都是连续的,所以我只能通过廉价扫描找到给定页面的数据价值,而无需阅读每个结果的整个节点,但即使对于简单的仅路径情况,我也不知道扫描所有结果以获取分页计数的成本。

我们考虑的另一个选项是将标签非规范化为单个节点。在这种情况下,为了保持搜索的准确性,这意味着在每个子节点中创建一个新的 combine_tags 属性并仅针对子节点集执行所有搜索。但是,如果我们匹配同一资产下的两个子节点,这仍然会遇到明显的问题。

感谢您的任何建议。这已经是一个大型实例,需要进一步扩展。我已经看到其他问题说 ModeShape 是一个确实有 SELECT DISTINCT 的 JCR 实现,但我认为,如果确实可以在 ModeShape 上托管 CQ,则必须为此切换到 ModeShape。


我们现在想出的一个想法是计算资产标签和子标签的每个并集,并将标签组合成一个字符串,然后将每个值写入资产的多值属性,即资产 + child1 = " A B C E" 和asset + child2 = "A B D E",所以我们得到

  • 资产:标签 = A、B; tagUnions = "A B C E", "A B D E"

只要我们定义了将标签组合成字符串的固定顺序(例如字母顺序),我们就可以使用tagUnions LIKE '%B%C%' 搜索任何组合(除非在实际情况下我会在标签之间使用适当的分隔符)。虽然这会起作用,但据我们所知,我真的不喜欢它:每个资产+子项可能有大量标签,所有标签的名称都比单个字母长,这意味着我们最终会得到执行LIKE 查询的长字符串在所有可能无法有效索引的地方。

另一种做法是制作位掩码:定义 A=1、B=2 等,并在此处存储一个多值整数数组,然后进行按位比较。但是,这可能仅限于 64 个不同的标签,并且由于我们有 1,000 多个标签,我认为我们无法做到这一点 - 即使 JCR 支持按位运算,我希望它不会。

因此,我仍在为此寻找类似数据库的干净解决方案。你已经错过了我提出的赏金,但仍有滴答声、投票和感谢任何帮助。

【问题讨论】:

    标签: jackrabbit jcr aem crx


    【解决方案1】:

    来自the Apache Jackrabbit mailing list

    是的,很遗憾,不支持联合查询。任何有关的工作 区域将不胜感激。

    同时最好的解决方法可能是执行两个单独的查询 并通过以下方式在应用程序代码中显式执行联合 合并两个结果集。

    所以,这是一种选择。查看您提供的 SQL:

    但在 JCR-SQL2 中没有 SELECT DISTINCT:如果我改为搜索“B E" 我将返回此资产两次,因为这两者都匹配 资产+child1 和资产+child2。

    我查看了 Jackrabbit 支持的可能解决方案,但一无所获。不过,我同意here 提出的解决方案:

    我所做的是用适当的 ORDER BYs 做一个简单的 SELECT ... 然后每次我使用一行时,我都验证它与 以前的:-)

    (保留原文。)

    虽然ORDER BY 可能是可疑的,除非您需要数据库支持的排序,但是否有任何东西阻止您在控制器中构建哈希集以使用 JCR API 将结果限制为唯一值?

    【讨论】:

    • 谢谢。它实际上不是一个 SQL UNION 我需要跨两个查询的集合联合,但我正在计算一个匹配来自不同节点的两个属性的逻辑联合,所以它是我的 SQL JOINSELECT DISTINCT需要。您链接的解决方案 - 按顺序排列并删除连续重复 - 是我在关于后处理结果的段落中提到的想法之一,问题在于正确分页:我需要扫描所有记录到当前页面来计算页面实际开始的位置,并扫描所有内容以获得准确的总页数。
    • ... 而我正在使用的系统拥有数百万资产,因此来自简单查询的 10,000 多个结果并非闻所未闻 - 我不能假设我有少量结果正如那个人所说,他在那个链接的解决方案中。我确实需要数据库支持的排序才能获得我认为的有效分页。在任何情况下,Jackrabbit 文档都建议您使用ORDER BY,因为 JCR 默认顺序(除非在 repository.xml 中禁用)计算成本可能很高。
    • @Rup 感谢您的更新。正如您所提到的,在 Java 中对结果进行后处理是可能的,但是当您遍历您已经访问过的其他节点时,可能会很昂贵。因此,这归结为有效遍历数据结构的问题。嗯。稍后我将不得不查看此内容并回复您。 :)
    • @Rup 从图形的形状方面考虑这一点,我意识到最有效的解决方案是专门为您的查询构建一个索引using tools tailored to it,或者以其他方式折叠子节点父级作为一种散列形式,JCR 似乎没有向其查询层公开。因此,我建议使用 Lucene。你已经看过了吗?
    • 不,没问题 - 感谢您的尝试!我们正在探索除 Jackrabbit 之外的其他选项,因此我可能不需要基于 Jackrabbit 的解决方案。
    猜你喜欢
    • 2012-01-02
    • 1970-01-01
    • 2016-11-09
    • 2011-08-28
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    相关资源
    最近更新 更多