将来自多个文档的匹配组合成Lucene中的单个命中

时间:2009-09-08 11:50:06

标签: lucene lucene.net

我正在努力让特定的搜索工作,这证明是有问题的。实际的源数据非常复杂,但可以通过以下示例进行总结:

  

我有索引的文章   他们可以被搜查。每   文章也有多个属性   与之相关的也是   索引和搜索。当用户   搜索,他们可以得到命中   主要文章或相关的   属性。无论哪里一击   实现后,文章被退回   作为搜索命中(即属性   永远不会受到打击。)

现在的复杂性:

  

每个物业都有安全保障,   这意味着对于任何给定的用户,   他们可能会或可能不会看到   属性。如果用户看不到   财产,他们显然没有得到   搜索命中了它。这个安全检查   是专有的,无法完成   使用典型的存储机制   索引中的一个角色   文件中的其他字段。

我目前有一个索引,其中包含单独索引的文章和属性(即,文章被索引为文档,并且每个属性都有自己的文档)。当搜索发生时,文章A中的命中或文章A的任何属性中的命中应该被归类为单独的文章A的命中,并且得分合并。

为了实现这一点,Lucene v1.3被修改为允许通过更改BooleanQuery来实现这一点,以便有一个可以应用安全检查逻辑的自定义Scorer,以及被归类为命中的不同文档中两个命中的组合在一份文件中。我正在尝试将此版本升级到最新版本(v2.3.2 - 我正在使用Lucene.Net),但理想情况下无需以任何方式修改Lucene。

如果我进行AND搜索,则会出现其他问题。如果文章包含单词 foo 并且其中一个属性包含单词 bar ,则搜索“foo AND bar”将返回文章作为匹配。我目前的代码在自定义Scorer中处理这个问题。

任何想法如何/是否可以这样做?

我正在考虑使用自定义HitCollector并将其传递到搜索中,但是当执行布尔搜索“foo AND bar”时,执行永远不会到达我的HitCollector,因为ConjunctionScorer会过滤掉所有结果到达那里之前的子查询。


编辑:

用户是否可以查看属性不是基于属性本身,而是基于属性的值。因此,我不能预先将额外的安全条件放入查询中,因为我不知道要过滤的值。

举个例子:

+---------+------------+------------+
| Article | Property 1 | Property 2 |
+---------+------------+------------+
|    A    |     X      |     J      |
|    B    |     Y      |     K      |
|    C    |     Z      |     L      |
+---------+------------+------------+

如果用户可以看到所有内容,则搜索“B和Y”将返回文章B的单个搜索结果。

如果其他用户的值不包含Y,则无法查看该属性,则搜索“B和Y”将不会返回任何匹配。

我无法知道用户可以使用哪些值,也无法预先看到。他们唯一的方法就是执行安全检查(目前在从文档中的字段过滤命中时完成),我显然不能为每个用户的每个可能的数据值做。

2 个答案:

答案 0 :(得分:3)

现在已经实现了这个目标(在经过Lucene搜索后经过大量的讨论和踩踏)后,我想我会回复我是如何实现它的。

因为我对所有结果感兴趣(即一次不是一个页面),所以我可以避免使用Hits对象(无论如何在Lucene的更高版本中已经弃用)。这意味着我可以使用Search(Weight, Filter, HitCollector) IndexSearcher方法执行我自己的命中集合,迭代所有可能的结果并合并文档命中。要做到这一点,我不得不挂钩Lucene的查询机制,但只有在存在AND和NOT子句时。这是通过以下方式实现的:

  1. 创建自定义QueryParser并覆盖GetBooleanQuery(ArrayList, bool)以返回我自己的实现。
  2. 创建自定义BooleanQuery(从自定义QueryParser返回)并覆盖CreateWeight(Searcher)以返回我自己的实现。
  3. 创建自定义Weight(从自定义BooleanQuery返回)并覆盖Scorer(IndexReader)以返回我自己的实现。
  4. 创建自定义BooleanScorer2(从自定义Weight返回)并覆盖Score(HitCollector)方法。这就是处理自定义逻辑的原因。
  5. 这可能看起来像很多类,但是大多数类派生自Lucene类,只是覆盖一个方法。

    自定义Score(HitCollector)类中BooleanScorer2方法的实现现在负责执行自定义逻辑。如果没有必需的子得分者,则可以将评分传递给基础Score方法并正常运行。如果有必要的子得分者,则表示查询中有NOT或AND子句。在这种情况下,问题中提到的特殊组合逻辑发挥作用。我有一个名为ConjunctionScorer的课程(这与Lucene中的ConjunctionScorer无关)。

    ConjunctionScorer获取一个得分手列表并对其进行迭代。对于每一个,我提取命中及其分数(使用Doc()Score()方法)并创建我自己的搜索命中集合,其中仅包含当前用户在执行相关安全检查后可以看到的那些命中。如果另一位得分手已经找到命中,我将它们组合在一起(使用他们的得分的平均分数)。如果命中的是来自被禁止的得分手,我会删除命中(如果已找到)。

    在所有这些结束时,我将匹配设置为传递到HitCollector方法的BooleanScorer2.Score(HitCollector)。这是我传入HitCollector方法的自定义IndexSearcher.Search(Query, HitCollector),用于最初执行搜索。当此方法返回时,我的自定义HitCollector现在包含我想要的搜索结果。

    希望这些信息对面临同样问题的其他人有用。这听起来很费劲,但实际上是非常微不足道的。大多数工作是在ConjunctionScorer中将命中组合在一起完成的。请注意,这适用于Lucene v2.3.2,在以后的版本中可能有所不同。

答案 1 :(得分:0)

以另一种方式回顾

  

此安全检查是专有的   使用典型的无法完成   存储角色的机制   索引与其他领域一起   文件。

如何在查询构建阶段检查属性的权限?因此,如果明确隐藏用户的属性,则避免将其包含在结果树