我正在研究索引引擎,特别是Apache Lucene Solr.我们愿意将它用于我们的搜索,但我们的框架搜索解决的问题之一是行级访问.
Solr不提供开箱即用的记录访问:
<...> Solr不关心文档级别或通信级别的安全性.
在关于文档级安全性的部分中:http://wiki.apache.org/solr/SolrSecurity#Document_Level_Security
有一些建议 - 要么使用Manifold CF(高度无证,似乎处于非β前期阶段),要么编写自己的请求处理程序/搜索组件(该部分标记为存根) - 我想后者会有对性能的影响更大.
所以我假设在这个领域没有做太多.
在最近发布的4.0版Solr中,他们引入了两个索引实体.加入似乎是个好主意,因为我们的框架也会联系以了解该记录是否可供用户访问.这里的问题是,有时我们做一个内连接,有时和外连接(取决于乐观(允许禁止的一切)或悲观(一切都被禁止,只有明确允许的内容)范围内的安全设置).
为了更好地理解我们的结构:
文件
DocumentNr | Name
------------------
1 | Foo
2 | Bar
Run Code Online (Sandbox Code Playgroud)
DocumentRecordAccess
DocumentNr | UserNr | AllowRead | AllowUpdate | AllowDelete
------------------------------------------------------------
1 | 1 | 1 | 1 | 0
Run Code Online (Sandbox Code Playgroud)
因此,例如,在悲观安全设置中生成的文档查询将是:
SELECT * FROM Documents AS d
INNER JOIN DocumentRecordAccess AS dra ON dra.DocumentNr=d.DocumentNr AND dra.AllowRead=1 AND dra.UserNr=1
Run Code Online (Sandbox Code Playgroud)
这只会返回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
Run Code Online (Sandbox Code Playgroud)
回归 - Foo和Bar.
回到我的问题 - 也许有人已经这样做了,可以分享他们的见解和经验吗?
恐怕这里没有简单的解决方案.您将不得不牺牲一些东西来使ACL与搜索一起工作.
如果您的语料库大小很小(我说最多10K文档),您可以创建一个禁用的(或允许的,任何更简洁的)文档的缓存位集并发送相关的过滤查询(+*:* -DocumentNr:1 ... -DocumentNr:X)
.不用说,这不会扩展.发送大型查询会使搜索速度变慢,但这是可管理的(当然是一个点).查询解析很便宜.
如果您可以以某种方式对这些文档进行分组并在文档组上应用ACL,这将允许缩短查询长度,并且上述方法将完全适合.这几乎就是我们正在使用的 - 我们的解决方案实现了分类,并通过fq
查询完成了分类权限.
如果您不需要显示整体结果集计数,则可以运行查询并在客户端过滤结果集.再次,不完美.
您还可以对数据结构进行非规范化,并将两个表格平铺在单个文档中,如下所示:
DocumentNr:1
名称:Foo
Allowed_users:u1,u2,u3(或Forbidden_users:...)
其余的就像使用您的查询发送用户ID一样简单.
如果ACL很少发生变化,并且您可以负担得起重建索引整个语料库,则上述情况才可行.
您可以编写一个自定义查询过滤器,该过滤器BitSet
将从数据库中检索的用户(组?)缓存允许或禁止的文档.这不仅需要为Solr webapp提供数据库访问,还需要扩展/重新打包Solr附带的.war.虽然这相对容易,但更难的部分是缓存失效:当ACL数据发生变化时,主应用程序应以某种方式向Solr应用程序发出信号.
如果您可以将Solr和您的应用程序放在同一个JVM上并使用javabin驱动程序,则选项1和2可能更合理.
在不知道语料库/ ACL的细节的情况下,很难提供更多建议.