0

我们的数据库包含具有大量元数据的文档,包括这些文档之间的关系。虚构示例:

<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>

我们正在使用基于 Marklogic 搜索 API 的 1 框搜索来允许用户搜索这些文档。搜索语法描述了各种约束和搜索选项,但大多数情况下(默认情况下)它们通过定义为包含大多数元数据元素的字段进行搜索,并(在某种程度上)仔细选择权重(这里真正重要的是document-number具有最高重量。)

问题是业务需要非常具体的结果排序,我想不出使用搜索 api 实现它的方法。

引起麻烦的要求是,如果用户搜索匹配文档编号(例如他们搜索“12345”),则具有该文档编号的所有文档都应位于结果集的顶部,按日期降序排列。将它们放在结果集的顶部很容易;document-number权重最高,因此按分数排序可以正常工作。问题是按日期进行二次排序不起作用,因为即使所有document-number匹配项的分数都高于其他文档,但它们的分数不同,因此它们最终按搜索词在其余文档中出现的频率排序元数据;这根本没有意义。

我认为我们真正需要的是一种仅通过与搜索词匹配的权重最高的元素来获得搜索 api 分数结果的方法,而无需参考文档中的任何其他匹配项。我已经查看了评分算法,但看不到这样做的算法;我错过了什么或者这不可能吗?显然,它不一定是score我们订购的;如果有其他方法可以获取文档中单个最佳匹配的分数并将其用于排序,那很好。

还有其他我什至没有想到的解决方案吗?

我想过进行两次搜索(一次在 上document-number,一次在整个元数据树上),然后合并结果,但这似乎会给分页和性能带来很多麻烦。哪种方式首先违背了使用搜索 api 的目的。

我应该补充一点,在结果集中包含其他匹配项是正确的,所以我们不能只搜索document-number.

4

2 回答 2

3

我认为您已经达到了高级搜索 API 可以为您做的事情的极限。不过,我有一些技巧要建议。这些不会是 100% 健壮的,但它们可能对业务来说已经足够好了。然后你就可以继续申请了。对不起,如果我听起来愤世嫉俗或不屑一顾,但我不相信微观管理搜索结果。

最简单的可能:重新排序内存中的第一页。第一页可能比您向用户显示的页面大一点。因为它的大小仍然有限,所以您可以为这个相当复杂的规则制定规则而不会受到太大影响。这将解决您的“递减日期”问题。第 1 页的结果与第 2 页的结果不太匹配,但这可能已经足够了。

采取复杂性的下一步,考虑使用文档质量来处理递减日期问题。这种方法被http://markmail.org等使用。在插入或更新每个文档时,使用从日期派生的数字设置文档质量。这可能是自 1970 年以来的几天、几周或几个月,或者使用其他一些固定日期。较新的结果往往会浮到顶部。如果任何其他提升往往会淹没基于日期的提升,那么您可能会接近您想要的。

在分析查询以提取潜在的提升术语时也可能有一些用处。如有必要,您可以开始xdmp:exists(cts:search(doc(), $query))对每个提升术语进行递归运行,就好像它是一个独立的查询一样。找到true()结果后立即退出:这意味着您将使用高得离谱的权重来提升该查询词,使其浮动到顶部。

一旦你知道什么是提升词,重写整个查询以将所有其他词的权重设置为低得多的值,甚至可能为 0。权重越低,那些非提升词对基于日期的质量和增加体重。如果没有提升项,您可能需要进行其他调整。顺便说一句,所有这些都比听起来便宜。除了xdmp:exists调用之外,它只是内存中的表达式评估。

不过,再一次,这些都只是轻推分数的技巧。他们不会让您绝对控制您正在寻找的排名。以我的经验,对分数进行微观管理的尝试注定要失败。我敢打赌,无论您的业务经理说什么,您的用户都会对原始 TF/IDF 更满意。

于 2012-11-08T16:46:30.853 回答
2

另一种方法是按照您的建议使用两次搜索。在文档编号(理想情况下是文档日期)上放置一个范围索引,从查询中提取任何潜在的文档编号值(search:parse提取,然后search:resolve是一个很好的策略),然后执行 cts:element-range-query 以进行文档匹配那些日期递减的文档编号值。如果没有足够的结果来填满您的 N 个结果页面,则从搜索 api 获取下一个 Nx 结果。您可以跟踪在第一个结果集中返回的文档,并从第二个结果集中排除这些 URI。跟踪分页不会太糟糕。

这可能不如第一个解决方案执行得好,但是对于大多数人来说,附加范围索引查询与更短的搜索 api 查询相结合的时间差异应该可以忽略不计。

于 2012-11-08T17:40:57.090 回答