我们的数据库包含了包含大量元数据的文档,包括这些文档之间的关系。虚构的例子:
<document>
<metadata>
<document-number>ID 12345 : 2012</document-number>
<publication-year>2012</publication-year>
<cross-reference>ID 67890 : 1995</cross-reference>
<cross-reference>ID 67890 : 1998</cross-reference>
<cross-reference>ID 67891 : 2000</cross-reference>
<cross-reference>ID 12345 : 2004</cross-reference>
<supersedes>ID 12345 : 2004</supersedes>
...
</metadata>
</document>
<document>
<metadata>
<document-number>ID 12345 : 2004</document-number>
<publication-year>2004</publication-year>
<cross-reference>ID 67890 : 1995</cross-reference>
<cross-reference>ID 67890 : 1998</cross-reference>
<cross-reference>ID 67891 : 2000</cross-reference>
<cross-reference>ID 12345 : 2012</cross-reference>
<cross-reference>ID 12345 : 2001</cross-reference>
<superseded-by>ID 12345 : 2012</superseded-by>
<supersedes>ID 12345 : 2001</supersedes>
...
</metadata>
</document>我们使用基于的1盒搜索,允许用户搜索这些文档。搜索语法描述了各种禁忌和搜索选项,但它们大多(在默认情况下)是通过定义为包含大多数元数据元素的字段进行搜索的,具有(某种程度上)精心选择的权重(真正重要的是,document-number具有最高的权重)。
问题是业务需要非常具体的结果排序,我想不出使用search来实现它的方法。
造成麻烦的要求是,如果用户搜索匹配一个文档号(比如他们搜索"12345“),那么所有带有该文档号的文档都应该位于结果集的顶部,按降序日期排序。很容易将它们放在结果集的顶端;document-number具有最高的权重,所以按分数排序很好。问题是按日期进行的第二次排序不起作用,因为即使所有document-number匹配的分数都高于其他文档,但它们没有相同的分数,因此它们最终按搜索词出现在其余元数据中的频率排序;这一点根本没有意义。
我认为我们真正需要的是通过匹配搜索项的最高加权元素获得search评分结果,而不引用文档中的任何其他匹配项。我已经看过得分算法了,但没有看到这样的算法;我错过了什么吗?或者这是不可能的?显然,我们订购的并不一定是score;如果有其他方法来获得文档中单个最佳匹配的得分,并使用它进行排序,那就很好了。
还有什么别的办法我都没想过吗?
我想做两个搜索(一个在document-number上,一个在整个元数据树上),然后组合结果,但是这似乎会给分页和性能带来很大的痛苦。哪种类型一开始就违背了使用搜索api的目的。
我应该补充一点,在结果集中有其他匹配是正确的,所以我们不能只在document-number上搜索。
发布于 2012-11-08 16:46:30
我认为您已经达到了高级搜索API可以为您做的极限。不过,我有几个窍门要提。这些并不是100%的强健,但它们可能对企业来说已经足够了。然后你就可以继续处理这个应用程序了。对不起,如果我听起来愤世嫉俗或不屑一顾,但我不相信微观管理搜索结果。
最简单的可能:重新排序内存中的第一页。第一页可能比您显示给用户的页面要大一些。因为它的大小仍然有限,所以您可以使这个规则变得相当复杂,而不会遭受太大的痛苦。这会解决你的“降日”问题。第1页的结果不太符合第2页,但这可能足够好。
在复杂性的下一步中,考虑使用文档质量来处理下降日期问题。http://markmail.org和其他人都使用这种方法。在插入或更新每个文档时,使用从日期派生的数字设置文档质量。这可能是1970年以来的几天、几周或几个月,或者使用其他固定日期。较新的结果将倾向于浮到顶端。如果任何其他的刺激倾向于淹没基于日期的刺激,你可能会接近你想要的。
在分析查询以提取潜在的提升项时,也可能有一些用处。如果有必要,您可以在每个提升项上开始递归运行xdmp:exists(cts:search(doc(), $query)),就好像它是一个独立的查询一样。一旦您找到一个true()结果,就立即退出:这意味着您将以非常高的权重提升该查询项,使其浮到顶部。
一旦您知道了提升项是什么,重写整个查询,将所有其他项的权重设置为低得多的值,甚至0。权重越低,非助推项对基于日期的质量和提升权重的干扰就越小。如果没有提振期,你可能需要做其他调整。顺便说一句,这一切都比听起来要便宜。除了xdmp:exists调用之外,它只是内存中的表达式评估。
尽管如此,这些都只是推动分数的诀窍。他们不会给你绝对的控制排名,你正在寻找。根据我的经验,对分数进行微观管理的尝试注定要失败。我敢打赌,不管你的业务经理怎么说,你的用户会更喜欢原始TF/国防军。
发布于 2012-11-08 17:40:57
另一种方法是使用两个搜索,如您所建议的。在文档编号(最好是文档日期)上设置一个范围索引,从查询中提取任何可能的文档编号值(search:parse,提取,然后search:resolve是一个很好的策略),然后对文档执行cts:element query,以匹配那些文档号值和日期下降。如果没有足够的结果来填充您的N-结果页面,那么从search获得下一个next结果。您可以跟踪第一个结果集中返回的文档,并将这些URI从第二个结果集中排除在外。记录下页码不会太糟。
这可能不像第一个解决方案那样好,但是附加范围索引查询与更短的搜索api查询的时间差对于大多数人来说应该是可以忽略不计的。
https://stackoverflow.com/questions/13290707
复制相似问题