我需要像Modelshape这样的JCR的基于标签的搜索系统。我想通过一些标签搜索节点。
问题是实现它的最佳方法是什么?
因此,如果是这样,我在哪里可以定义用户可以看到的标签名称?
所以,如果那是真的,我该如何引用它们?
最佳答案
有几种方法可以在JCR中实现标签。您选择哪个选项将取决于您自己的应用程序的需求。这是我所知道的四个选项。
选项1:使用Mixins
为每个标签定义一个混合节点类型定义,即标记混合(没有属性定义或子节点定义),并使用NodeTypeManager动态注册它们。然后,当您要“标记”节点时,只需将代表标记的混合添加到该节点。任何节点都可以具有多个标签,并且您可以查询具有特定标签的所有节点。
(在此响应的其余部分中,“acme”用作通用 namespace 。您应使用适合自己的应用程序和组织的 namespace 来替换它。)
例如,给定标签“acme:tag1”,您可以通过简单的查询找到所有具有该标签的节点:
SELECT * FROM [acme:tag1]
这种方法的缺点是维护标签很麻烦。创建新标签需要注册新的节点类型。您不能轻松地重命名标签,而必须使用新名称为标签创建mixin。找到所有具有mixin代表旧标签的节点,删除旧的mixin,然后添加新节点;最后删除旧标记的节点类型定义(此标记在任何地方都不再使用之后)。删除旧标签的方式与此类似。另一个缺点是,将额外的元数据(例如显示名称)与标签相关联并不容易,因为节点类型定义中不允许使用额外的属性。
这种方法应该执行得很好。
选项2:使用分类法和强引用
用这种方法,您将在存储库的区域中创建一个简单的节点结构,您可以在其中为每个标签创建一个节点(例如,分类法)。在此节点上,您可以设置描述标签的属性(例如显示名称);这些属性可以随时更改(例如,重命名标签)。
然后,要将标签“应用”到节点,只需创建与标签的某种关系即可。一种方法是定义一个混合节点类型,该类型包含一个REFERENCE类型的“acme:tags”多值属性。当您要将一个或多个标签应用于节点时,只需将mixin添加到该节点,然后将“acme:tags”属性设置为标签节点即可。
要查找特定标签的所有节点,可以在标签节点上调用“getReferences()”以查找包含对该标签节点的引用的所有节点。
这种方法的好处是,必须在一个或多个分类法(可能包括用户特定的分类法)内对所有标签进行控制/管理。但是,也有一些缺点。首先,REFERENCE属性的性能可能不佳。一些JCR实现完全不鼓励使用REFERENCES。 ModeShape不会,但是当有许多节点包含对同一节点的引用时(例如,许多具有单个标签的节点),ModeShape可能会开始降低引用性能。
选项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属性使用要应用的标签名称来标记每个节点。例如,您可以定义一个混合(例如“acme:taggable”)来定义一个多值STRING属性,而当您想标记一个节点时,只需添加混合(如果尚未存在)并添加名称即可。标签作为“acme:tags” STRING属性上的值(同样,如果尚未作为值存在)。
这种方法的主要优点是非常简单:您只是在要标记的节点上使用字符串值。要查找所有带有特定标记(例如“tag1”)标记的节点,只需发出查询:
SELECT *
FROM [acme:taggable] AS taggable
WHERE taggable.[acme:tags] = 'tag1'
标签的管理很容易:没有管理。如果要重命名标签,则可以重命名标签值。如果要删除标签(并从带有标签的节点中删除标签),则可以通过从“acme:tags”属性中删除值(可以在后台作业中)来完成。
请注意,这允许使用任何标签名,因此,对于根本不控制标签名的情况,效果最佳。如果要控制用作标记值的字符串列表,只需在存储库中创建一个分类法(如上面的选项2和3中所述),然后让您的应用程序将值限制为该分类法中的值。您甚至可以具有多种分类法,其中某些分类法可能是特定于用户的。但是这种方法没有与选项2或3完全相同的控件。
此选项的性能将比选项3更好(因为查询更简单),但伸缩性也一样。
关于java - 通过JCR实现基于标签的搜索系统的最佳方式,例如Modeshape,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14315031/