我正在努力让特定的搜索工作,这证明是有问题的。实际的源数据非常复杂,但可以通过以下示例进行总结:
我有索引的文章 他们可以被搜查。每 文章也有多个属性 与之相关的也是 索引和搜索。当用户 搜索,他们可以得到命中 主要文章或相关的 属性。无论哪里一击 实现后,文章被退回 作为搜索命中(即属性 永远不会受到打击。)
现在的复杂性:
每个物业都有安全保障, 这意味着对于任何给定的用户, 他们可能会或可能不会看到 属性。如果用户看不到 财产,他们显然没有得到 搜索命中了它。这个安全检查 是专有的,无法完成 使用典型的存储机制 索引中的一个角色 文件中的其他字段。
我目前有一个索引,其中包含单独索引的文章和属性(即,文章被索引为文档,并且每个属性都有自己的文档)。当搜索发生时,文章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”将不会返回任何匹配。
我无法知道用户可以使用哪些值,也无法预先看到。他们唯一的方法就是执行安全检查(目前在从文档中的字段过滤命中时完成),我显然不能为每个用户的每个可能的数据值做。
答案 0 :(得分:3)
现在已经实现了这个目标(在经过Lucene搜索后经过大量的讨论和踩踏)后,我想我会回复我是如何实现它的。
因为我对所有结果感兴趣(即一次不是一个页面),所以我可以避免使用Hits
对象(无论如何在Lucene的更高版本中已经弃用)。这意味着我可以使用Search(Weight, Filter, HitCollector)
IndexSearcher
方法执行我自己的命中集合,迭代所有可能的结果并合并文档命中。要做到这一点,我不得不挂钩Lucene的查询机制,但只有在存在AND和NOT子句时。这是通过以下方式实现的:
QueryParser
并覆盖GetBooleanQuery(ArrayList, bool)
以返回我自己的实现。BooleanQuery
(从自定义QueryParser
返回)并覆盖CreateWeight(Searcher)
以返回我自己的实现。Weight
(从自定义BooleanQuery
返回)并覆盖Scorer(IndexReader)
以返回我自己的实现。BooleanScorer2
(从自定义Weight
返回)并覆盖Score(HitCollector)
方法。这就是处理自定义逻辑的原因。这可能看起来像很多类,但是大多数类派生自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)
以另一种方式回顾
此安全检查是专有的 使用典型的无法完成 存储角色的机制 索引与其他领域一起 文件。
如何在查询构建阶段检查属性的权限?因此,如果明确隐藏用户的属性,则避免将其包含在结果树
中