我正在研究索引引擎,特别是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与搜索协同工作,您将不得不牺牲一些东西。
-
如果你的语料库大小很小(我认为最多有10K个文档),你可以创建一个禁止(或允许,以较不详细的为准)文档的缓存位集,并发送相关的过滤器查询
(+*:* -DocumentNr:1 ... -DocumentNr:X)
。不用说,这是没有规模的。发送大型查询会使搜索速度变慢,但这是可以管理的(当然在一定程度上)。查询解析很便宜。 -
如果您可以以某种方式对这些文档进行分组,并在文档组上应用ACL,这将允许减少查询长度,并且上述方法将非常适合。这几乎就是我们正在使用的——我们的解决方案实现了分类法,并通过
fq
查询获得了分类法权限。 -
如果不需要显示总体结果集计数,则可以在客户端运行查询并过滤结果集。再说一遍,不完美。
-
您还可以取消数据结构的规范化,并将这两个表存储在一个文档中,如下所示:
文档编号:1
名称:Foo
Allowed_users:u1、u2、u3(或Forbidden_users:…)剩下的就像在查询中发送用户id一样简单。
只有当ACL很少更改时,以上内容才可行并且您可以在更改时重新索引整个语料库。
-
您可以编写一个自定义查询过滤器,该过滤器将缓存用户(组?)从数据库中检索到的允许或禁止文档的
BitSet
。这不仅需要为Solr网络应用程序提供DB访问权限,还需要扩展/重新打包Solr附带的.war。虽然这相对容易,但更困难的部分是缓存无效:当ACL数据发生更改时,主应用程序应该以某种方式向Solr应用程序发出信号。
如果您可以将Solr和您的应用程序放在同一JVM上并使用javabin驱动程序,那么选项1和2可能更合理。
如果不了解语料库/ACL的具体情况,很难提供更多建议。
我同意mindas的建议(sol-4),我以同样的方式实现了我的解决方案,但不同的是我有几种不同类型的ACL。在用户组级别、用户级别甚至文档级别(私有访问)。
解决方案运行良好。但在我的案例中,主要担心的是ACL会频繁更改,这需要在索引中更新,这意味着搜索性能也不应该受到影响。
我正试图通过负载平衡和在集群中添加更多节点来管理这一点。
mindas,unicron,你能谈谈你的想法吗?