正确的记录访问实现



我正在研究索引引擎,特别是Apache Lucene Solr。我们愿意在搜索中使用它,但我们的框架搜索解决的问题之一是行级访问。

Solr不提供开箱即用的记录访问:

<…>Solr不关心文档级别或通信级别的安全性。

在关于文档级安全性的部分中:http://wiki.apache.org/solr/SolrSecurity#Document_Level_Security

很少有建议-要么使用Manifold CF(它是高度未记录的,似乎处于测试前阶段),要么编写自己的请求处理程序/搜索组件(该部分标记为存根)-我想后面的一个会对性能产生更大的影响。

因此,我认为在这个领域没有做太多的工作。

在最近发布的Solr 4.0版本中,他们引入了连接两个索引实体。加入可能是个不错的主意,因为我们的框架还进行了一个连接,以了解用户是否可以访问记录。这里的问题是,有时我们进行内部联接,有时进行外部联接(取决于范围中的乐观(所有不被禁止的都被允许)或悲观(所有被禁止的只有明确允许的)安全设置)。

为了更好地了解我们的结构:

文档

DocumentNr | Name
------------------
1          | Foo
2          | Bar

DocumentRecordAccess

DocumentNr | UserNr | AllowRead | AllowUpdate | AllowDelete
------------------------------------------------------------
1          | 1      | 1         | 1           | 0

因此,例如,在悲观安全设置中为文档生成的查询将是:

SELECT * FROM Documents AS d 
INNER JOIN DocumentRecordAccess AS dra ON dra.DocumentNr=d.DocumentNr AND dra.AllowRead=1 AND dra.UserNr=1

这将只返回foo,而不返回bar。在乐观的环境中:

SELECT * FROM Documents AS d 
LEFT JOIN DocumentRecordAccess AS dra ON dra.DocumentNr=d.DocumentNr AND dra.AllowRead=1 AND dra.UserNr=1

同时回归Foo和Bar。

回到我的问题——也许有人已经这样做了,可以分享他们的见解和经验?

恐怕这里没有简单的解决方案。为了让ACL与搜索协同工作,您将不得不牺牲一些东西。

  1. 如果你的语料库大小很小(我认为最多有10K个文档),你可以创建一个禁止(或允许,以较不详细的为准)文档的缓存位集,并发送相关的过滤器查询(+*:* -DocumentNr:1 ... -DocumentNr:X)。不用说,这是没有规模的。发送大型查询会使搜索速度变慢,但这是可以管理的(当然在一定程度上)。查询解析很便宜。

  2. 如果您可以以某种方式对这些文档进行分组,并在文档组上应用ACL,这将允许减少查询长度,并且上述方法将非常适合。这几乎就是我们正在使用的——我们的解决方案实现了分类法,并通过fq查询获得了分类法权限。

  3. 如果不需要显示总体结果集计数,则可以在客户端运行查询并过滤结果集。再说一遍,不完美。

  4. 您还可以取消数据结构的规范化,并将这两个表存储在一个文档中,如下所示:

    文档编号:1
    名称:Foo
    Allowed_users:u1、u2、u3(或Forbidden_users:…)

    剩下的就像在查询中发送用户id一样简单。

    只有当ACL很少更改时,以上内容才可行并且您可以在更改时重新索引整个语料库。

  5. 您可以编写一个自定义查询过滤器,该过滤器将缓存用户(组?)从数据库中检索到的允许或禁止文档的BitSet。这不仅需要为Solr网络应用程序提供DB访问权限,还需要扩展/重新打包Solr附带的.war。虽然这相对容易,但更困难的部分是缓存无效:当ACL数据发生更改时,主应用程序应该以某种方式向Solr应用程序发出信号。

如果您可以将Solr和您的应用程序放在同一JVM上并使用javabin驱动程序,那么选项1和2可能更合理。

如果不了解语料库/ACL的具体情况,很难提供更多建议。

我同意mindas的建议(sol-4),我以同样的方式实现了我的解决方案,但不同的是我有几种不同类型的ACL。在用户组级别、用户级别甚至文档级别(私有访问)。

解决方案运行良好。但在我的案例中,主要担心的是ACL会频繁更改,这需要在索引中更新,这意味着搜索性能也不应该受到影响。

我正试图通过负载平衡和在集群中添加更多节点来管理这一点。

mindas,unicron,你能谈谈你的想法吗?

最新更新