通过JCR实现基于标签的搜索系统的最佳方式,如Modeshape

我需要JCR的基于标签的搜索系统,如Modeshape。 我想通过一些标签搜索节点。 问题是实施它的最佳方法是什么?

  1. 为标签添加新的节点类型和mixins,如果这是真的,我在哪里可以定义可供用户查看的标签名称?
  2. 实现标记层次结构并在我的节点中引用它们。 所以,如果这是真的,我怎么能参考它们?
  3. 任何其他方式。

有几种方法可以在JCR中实现标记。 您选择哪个选项取决于您自己的应用程序的需求。 以下是我所知道的四个选项。

选项1:使用Mixins

为每个标记定义一个mixin节点类型定义,它是一个标记mixin(它没有属性定义或子节点定义),使用NodeTypeManager动态注册它们。 然后,当您想要“标记”节点时,只需向该节点添加表示标记的mixin。 任何节点都可以有多个标记,您可以查询具有特定标记的所有节点。

(在此响应的其余部分中,“acme”用作通用名称空间。您应该将其替换为适合您自己的应用程序和组织的名称空间。)

例如,给定标记“acme:tag1”,您可以使用简单查询找到具有此标记的所有节点:

SELECT * FROM [acme:tag1] 

这种方法的缺点是维护标签很麻烦。 创建新标记需要注册新节点类型。 您不能轻易地重命名标记,而是必须使用新名称为标记创建mixin; 找到mixin代表旧标签的所有节点,删除旧的mixin,然后添加新的mixin; 最后删除旧标记的节点类型定义(在任何地方不再使用之后)。 删除旧标签以类似的方式完成。 另一个缺点是将附加元数据(例如,显示名称)与标签相关联并不容易,因为节点类型定义上不允许额外的属性。

这种方法应该表现得很好。

选项2:使用分类法和强引用

在此方法中,您将在存储库的区域中创建一个简单的节点结构,您可以在其中为每个标记创建节点(例如,分类)。 在此节点上,您可以设置描述标记的属性(例如,显示名称); 这些属性可以随时更改(例如,重命名标记)。

然后,要将标记“应用”到节点,您只需要创建某种与标记的关系。 一种方法是定义一个mixin节点类型,其中包含REFERENCE类型的“acme:tags”多值属性。 如果要将一个或多个标记应用于节点,只需将mixin添加到节点,并将“acme:tags”属性设置为标记节点。

要查找特定标记的所有节点,可以在标记节点上调用“getReferences()”以查找包含对标记节点的引用的所有节点。

这种方法的好处是必须在一个或多个分类法(包括可能是用户特定的分类法)内控制/管理所有标签。 但是,也有一些缺点。 首先,REFERENCE属性的性能可能不是很好。 一些JCR实现完全不鼓励使用REFERENCES。 ModeShape没有,但是当有许多节点包含对同一节点的引用时(例如,许多带有单个标记的节点),ModeShape可能会开始降低REFERENCE性能。

选项3:使用分类法和弱引用

此选项与上面的选项2类似,但“acme:tags”属性为WEAKREFERENCE而不是REFERENCE。 您仍然可以定义和管理一个或多个分类法。 要查找具有特定标记的节点,您不能在标记节点上使用“getReferences()”方法(因为它们不适用于WEAKREFERENCE属性),但您可以使用查询轻松执行此操作:

 SELECT * FROM [acme:taggable] AS taggable JOIN [acme:tag] AS tag ON taggable.[acme:tags] = tag.[jcr:uuid] AND LOCALNAME(tag) = 'tag1' 

这种方法确实强制使用一个或多个分类法,使得控制标签更容易,因为它们必须存在于分类中才能使用。 重命名和删除也更容易。 性能方面,这比REFERENCE方法更好,因为WEAKREFERENCE属性在大量引用时表现更好,无论它们是指向一个节点还是多个节点。

缺点是您可以删除标记,即使它仍在使用,但包含对该删除标记的WEAKREFERENCE的节点将不再有效。 这可以通过应用程序中的某些约定来解决,或者通过简单地使用分类法上的元数据来表示特定标记是“已弃用”且不应使用。 (IMO,后者实际上是这种方法的好处。)

此选项通常比选项2更好地执行和扩展。

选项4:使用字符串属性

另一种方法是简单地使用STRING属性来标记每个节点以及要应用的标签的名称。 例如,您可以定义一个mixin(例如,“acme:taggable”)来定义多值STRING属性,当您想要标记一个节点时,只需添加mixin(如果尚未存在)并添加名称标记为“acme:tags”STRING属性的值(同样,如果它尚未作为值存在)。

这种方法的主要优点是它非常简单:您只是在要标记的节点上使用字符串值。 要查找使用特定标记标记的所有节点(例如,“tag1”),只需发出查询:

 SELECT * FROM [acme:taggable] AS taggable WHERE taggable.[acme:tags] = 'tag1' 

标签管理很简单:没有管理。 如果要重命名标记,则可以重命名标记值。 如果要删除标记(并从使用它标记的节点中删除),则可以通过从“acme:tags”属性中删除值(可能在后台作业中)来完成。

请注意,这允许使用任何标记名称,因此最适用于根本不控制标记名称的情况。 如果要控制用作标记值的字符串列表,只需在存储库中创建分类(如上面的选项2和3中所述),并让应用程序将值限制为分类中的值。 您甚至可以拥有多个分类,其中一些可能是特定于用户的。 但是这种方法与选项2或3没有完全相同的控制。

此选项将比选项3执行得更好(因为查询更简单),但也可以扩展。