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

时间:2013-01-14 08:22:07

标签: java tags jcr modeshape

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

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

1 个答案:

答案 0 :(得分:13)

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

选项1:使用Mixins

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

(在本回复的其余部分中,&#34; acme&#34;用作通用命名空间。您应该将其替换为适合您自己的应用程序和组织的命名空间。) < / p>

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

SELECT * FROM [acme:tag1]

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

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

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

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

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

要查找特定标记的所有节点,您可以调用&#34; getReferences()&#34;在标记节点上查找包含对标记节点的引用的所有节点。

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

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

此选项是类似于上述选项2的混合选项,除了&#34; acme:tags&#34;属性将是WEAKREFERENCE而不是REFERENCE。您仍然可以定义和管理一个或多个分类法。要查找具有特定标记的节点,您无法使用&#34; getReferences()&#34;标记节点上的方法(因为它们不能与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的节点将不再有效。这可以通过应用程序中的某些约定来解决,或者通过简单地使用分类法上的元数据来表示特定标记被弃用&#34;并且不应该使用。 (IMO,后者实际上是这种方法的一个好处。)

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

选项4:使用字符串属性

另一种方法是简单地使用STRING属性来标记每个节点以及要应用的标记的名称。例如,您可以定义一个mixin(例如,&#34; acme:taggable&#34;)来定义多值STRING属性,当您想要标记一个节点时,只需添加mixin(如果尚未存在)和将标记的名称添加为&#34; acme:tags&#34; STRING属性(再次,如果它还没有作为值存在)。

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

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

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

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

此选项的性能会比选项3好一些(因为查询更简单),但也可以扩展。